Creating analyses

Another major use of pyNS is to create Neuroscout analyses programatically.

This is particulary useful for users that want to create a large number of analyses, or specify a BIDS Stats Model that is not currently supported by the Neuroscout frontend web application.

Note

To update analyses, you must be authenticated and be the owner of a particular analysis

Querying for Analyses

First, as before, you can use pyNS to query and look up existing any existing public analyses.

For example, we can find two arbitrary analyses named brightness by name:

>>> neuroscout.analyses.get(name='speech')[-1]
{'dataset_id': 30, 'description': None, 'hash_id': '52546', 'modified_at': '2021-10-07T21:1', 'name': 'speech', 'nv_count': 0, 'status': 'PASSED', 'user': 'adelavega'}

The Analysis object

To make it easier to work with the analyses, pyNS provides a special Analysis which represents a single Neuroscout analysis as a Python object. To create this object, you can use pyns.endpoints.analyses.get_analysis() to create an object from an Analysis’ hash_id

This Analysis object has all the attributes of an analysis as class attributes that can be modified and updated.

>> my_analysis = neuroscout.analyses.get_analysis('52546')
>> my_analysis.hash_id
'52546'
>> my_analysis.predictors
[40344,
40345,
40346,
40347,
40348,
40349,
40995,
40999,
41003,
41007,
41011,
41015,
42227]
>> my_analysis.user
'adelavega'

Modifying analyses

Assuming you are the owner of an analysis–and the analysis is still editable–you can modify it using the Analysis object. Simply modify the attributes of the pyns.endpoints.Analysis object and then call Analysis.push() to push the changes to the server

>>> my_analysis.predictors = [40344] # remove all other predictors
>>> my_analysis.push()
>>> my_analysis.pull() # pull the updated analysis from the server
>>> my_analysis.predictors
[40344]

Note

If you have compiled the analysis, it can no longer be modified

Creating new analyses

You can use the pyns.endpoints.analyses.create_analysis() function to create a new pyns.endpoints.Analysis object corresponding to a new analysis you just created. This function makes it easy to create an analysis, by allowing you to specify your predictors, dataset, and other attributes of the analysis by name.

>>> analysis = neuroscout.analyses.create_analysis(
dataset_name='Life', name='My new analysis!',
predictor_names=['rmse', 'FramewiseDisplacement'],
hrf_variables=['rmse'],
subject=['rid000001', 'rid000005']
)

Uploading custom predictors

It is possible to upload custom predictors by passing a list of event_files (list of strings), and a corresponding list of lists of run_id integers of the same length to neuroscout.predictors.create_collection().

Features should be in BIDS-compliant events format. Two columns are mandatory: onset and duration (both in seconds). You can then include any number of novel predictors as additional columns. Missing values can be annotated using the value n/a.

For each events file that you upload, you will be asked to associate it with runs in the respective dataset. Typically, there will be a different event file for each run in a naturalistic dataset. You must then associate each file with subjects. For example, in most cases, all subjects will have seen the same stimulus, but this will vary across datasets.

>>> raiders1 = neuroscout.runs.get(dataset_id=10,number=1)[0:3] # 3 runs from raiders part 1
>>> raiders2 = neuroscout.runs.get(dataset_id=10,number=2)[0:3] # 3 runs from raiders part 2
>>> runs = [ [p['id'] for p in raiders1], [p['id'] for p in raiders2] ]
>>> runs
[[328, 344, 336], [331, 323, 355]]
>>> event_files = ['food_raiders1.tsv', 'food_raiders2.tsv']
>>> descriptions = {
    "grapes": "instances of grapes manually coded",
    "apples": "instances of apples manually coded",
    "bananas": "instances of bananas manually coded"}
>>> neuroscout.predictors.create_collection(collection_name="raiders food",\
                                        dataset_id=11, \
                                        runs=runs, \
                                        event_files=event_files, \
                                        descriptions = descriptions)

In the above example, food_raiders1.tsv matches with run_ids [328, 344, 336] and food_raiders2.tsv corresponds to runs [331, 323, 355]. The description parameter is optional and is a dictionary. Each key in the dictionary is a column in the .tsv file and matches to a string description of the columns.

Tutorial

For a complete guide on using pyNS, and in particular creating and updating Analysis, see this Jupyter Notebook.

For a complete example, including meta-analytic workflows, see the the Neuroscout Paper Jupyter Book.