Neuroinformatics API

We have included a neuroinformatics subsystem in NeuroScale to track different pieces of information in the system (e.g. input and output data) and make them discoverable to users via search queries.

The basic concept in the neuroinformatics system is entity. An entity is an immutable (i.e. non-changing) object/document containing information about a data object or action (e.g. data transformation or pipeline execution). An entity must have a unique id and a non-empty type value. id must consist of the letters a-z (lower or upper case), the digits 0-9 or any of the following punctuation characters: _ - : . @ ( ) + , = ; $ ! * ' %.

Many of the entities placed in the system will have a type associated with a class defined in ESS ("EEG Study Schema"). The type value for such entities must start with ess: to indicated ESS namespace, for example ess:Entity/Block. Child classes (types) in ESS have their parent class (concatenated with /) as their prefix, e.g. ess:Entity/Block.

Basic meta-data, such as sampling rate, are automatically extracted from files upon upload (including pipeline outputs).

There are three ways to find entities using the neuroinformatics API:

  1. By their type: returns zero or more entities with the given type.
  2. By example: enables you to find entities with properties that have the specified values. You provide a JSON string as the query, e.g. '{"age" : 20}' and entities that have all the properties set in the provided JSON (with values equal to the provided values) will be returned.

For example: if there are three entities in the database:

A = {“age”: 20, “gender”: “female”}
B = {“age”: 20, “gender”: “female”, “height”:5.5}
C = {“age”: 10}

the query {"age" : 20} will return entities A and B, while the query {“age”: 20, “gender”: “female”} will return only B.

  1. By filter: enables you to find entities using AQL query language. The supported AQL format is
FOR e in [collection]
FILTER [your query]
[Return e] or [your RETURN statement]

You provide the AQL query string, without the first line (FOR..) or the FILTER command. The [collection] is set by the system. You must write your filter statement for a variable named e.

You can also optionally include a custom RETURN statement. In this case, you must always ‘name’ your output by assigning them to properties, e.g. instead of

RETURN e.id
use
RETURN {id:e.id}

so the returned value becomes an array of objects:

[ {“id”: xyz1}, {“id”: abc2},..}

(otherwise the result value may become as an array of disjoint characters, etc.)

Example 1:

The query:

e.age >=20 && e.gender == “female”

Executes the following internal AQL query:

FOR e in [collection]
    FILTER e.age >=20 && e.gender == “female”
    RETURN e

Example 2:

The query:

e.age >=20 && e.gender == “female” RETURN {id:e.id}

Executes the following internal AQL query:

FOR e in [collection]
    FILTER e.age >=20 && e.gender == “female”
    RETURN {id:e.id}

Example 3 (query the subfields):

e.subject.age >=20 && e.subject.gender == “female” RETURN {subject:e.subject}

The neuroinformatics API endpoint for finding endpoints is /catalogue/entities. To use it, similar to other NeuroScale endpoints, you first need to provide your access token (sample code in Python):

# define API URL
api_url = 'https://api.neuroscale.io/v1/catalogue'

# define your access token
api_token = '346346-545-4da6-8990-457457JBbig' #[change this to your access token]

# form authorization header
headers = {'Authorization': 'Bearer %s' % api_token}

Now to query all entities visible to you:

resp = requests.get('%s/entities' % api_url, headers=headers)
print(json.dumps(resp.json(), indent=2))

and to query entities by example:

resp = requests.get('%s/entities' % api_url,
params={'q': '{"storage_path": "studies/sra3_1.h5"}'},
headers=headers)


print(json.dumps(resp.json(), indent=2))

The q parameter contains the query string. In the example above it searches for an entities that is stored at studies/sra3_1.h5. The query type is by default example and hence not specified.

To query the dataset using compound predicates we use the filter query type :

resp = requests.get('%s/entities' % api_url,
params={'q': 'e.analogsignals.channel_count > 30', 'type': 'filter'},
headers=headers)


print(json.dumps(resp.json(), indent=2))

This returns all entities that have more than 30 channels (their analogsignals.channel_count property is greater than 30).

To find all entities of particular type, use the type query type.

resp = requests.get('%s/entities' % api_url,
params={'q': 'ess:Entity/Block', 'type': ‘type’},
headers=headers)


print(json.dumps(resp.json(), indent=2))

This will return all entities of type ess:Entity/Block.