Skip to content

insectbrain_db

Client to manage Insect Brain DB session.

PARAMETER DESCRIPTION
token
        API token. See `authenticate()`.

TYPE: str DEFAULT: None

created_at
        Time and date the token was generated. Iso-formatted.

TYPE: str DEFAULT: None

Source code in navis/interfaces/insectbrain_db.py
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
class Session:
    """Client to manage Insect Brain DB session.

    Parameters
    ----------
    token :         str
                    API token. See `authenticate()`.
    created_at :    str
                    Time and date the token was generated. Iso-formatted.

    """

    def __init__(self, username=None, password=None, token=None, created_at=None):
        self._session = requests.Session()

        self.username = username
        self.password = password

        self.token = token
        self.created_at = created_at

    @property
    def token_expired(self):
        """Check if token is expired."""
        if self._token_created_at:
            now = dt.datetime.now()
            expires_in = dt.timedelta(days=1)
            if now - self._token_created_at >= expires_in:
                return True
        return False

    @property
    def token(self):
        return self._token

    @token.setter
    def token(self, token):
        if token and not token.startswith('Token'):
            token = f'Token {token}'
        self._token = token
        self._session.headers['Authorization'] = token

    @property
    def token_created_at(self):
        return self._token_created_at

    @token_created_at.setter
    def token_created_at(self, value):
        if value:
            self._token_created_at = dt.datetime.fromisoformat(value[:-1])
        else:
            self._token_created_at = None

    def fetch_token(self):
        """Fetch fresh token."""
        username = self.username
        if not username:
            username = os.environ.get('INSECT_BRAIN_DB_USER', None)
        password = self.password
        if not password:
            password = os.environ.get('INSECT_BRAIN_DB_PASSWORD', None)

        if not username or not password:
            msg = """\
            You must provide username + password, or an API token. Please see
            `navis.interfaces.insectbrian_db.authenticate()` for details.
            """
            raise ValueError(msg)

        creds = {'username': username, 'password': password}

        # Note: do NOT remove the trailing '/' here
        url = make_url(baseurl, 'api', 'v2', 'token/')

        resp = requests.post(url, data=creds)
        resp.raise_for_status()

        global session
        self.token = resp.json()['token']
        self.token_created_at = resp.json()['created']

        logger.info('Successfully retrieved 24h Insect Brain DB API token!')

    def preflight(self):
        """Check if we're ready to make requests."""
        if self.token and self.token_expired:
            self.fetch_token()

    def get(self, *args, **kwargs):
        """Make GET request."""
        self.preflight()

        r = self._session.get(*args, **kwargs)
        r.raise_for_status()

        return r.json()

    def post(self, *args, **kwargs):
        """Make POST request."""
        self.preflight()

        r = self._session.post(*args, **kwargs)
        r.raise_for_status()

        return r.json()

Check if token is expired.

Fetch fresh token.

Source code in navis/interfaces/insectbrain_db.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def fetch_token(self):
    """Fetch fresh token."""
    username = self.username
    if not username:
        username = os.environ.get('INSECT_BRAIN_DB_USER', None)
    password = self.password
    if not password:
        password = os.environ.get('INSECT_BRAIN_DB_PASSWORD', None)

    if not username or not password:
        msg = """\
        You must provide username + password, or an API token. Please see
        `navis.interfaces.insectbrian_db.authenticate()` for details.
        """
        raise ValueError(msg)

    creds = {'username': username, 'password': password}

    # Note: do NOT remove the trailing '/' here
    url = make_url(baseurl, 'api', 'v2', 'token/')

    resp = requests.post(url, data=creds)
    resp.raise_for_status()

    global session
    self.token = resp.json()['token']
    self.token_created_at = resp.json()['created']

    logger.info('Successfully retrieved 24h Insect Brain DB API token!')

Make GET request.

Source code in navis/interfaces/insectbrain_db.py
131
132
133
134
135
136
137
138
def get(self, *args, **kwargs):
    """Make GET request."""
    self.preflight()

    r = self._session.get(*args, **kwargs)
    r.raise_for_status()

    return r.json()

Make POST request.

Source code in navis/interfaces/insectbrain_db.py
140
141
142
143
144
145
146
147
def post(self, *args, **kwargs):
    """Make POST request."""
    self.preflight()

    r = self._session.post(*args, **kwargs)
    r.raise_for_status()

    return r.json()

Check if we're ready to make requests.

Source code in navis/interfaces/insectbrain_db.py
126
127
128
129
def preflight(self):
    """Check if we're ready to make requests."""
    if self.token and self.token_expired:
        self.fetch_token()

Authenticate against Insect Brain DB.

You can either provide username + password, or a token. Each token is only valid for 24h though. The better alternative is to provide your username + password as environment variables: INSECT_BRAIN_DB_USER and INSECT_BRAIN_DB_PASSWORD, respectively. If you are using these environment you don't need to bother with authenticate() at all.

PARAMETER DESCRIPTION
username
        Your username on Insect Brain DB.

TYPE: str DEFAULT: None

password
        Your password on Insect Brain DB.

TYPE: str DEFAULT: None

token
        A token. If provided you don't need to provide username +
        password.

TYPE: str DEFAULT: None

Source code in navis/interfaces/insectbrain_db.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def authenticate(username=None, password=None, token=None):
    """Authenticate against Insect Brain DB.

    You can either provide username + password, or a token. Each token is only
    valid for 24h though. The better alternative is to provide your
    username + password as environment variables: `INSECT_BRAIN_DB_USER` and
    `INSECT_BRAIN_DB_PASSWORD`, respectively. If you are using these environment
    you don't need to bother with `authenticate()` at all.

    Parameters
    ----------
    username :      str, optional
                    Your username on Insect Brain DB.
    password :      str, optional
                    Your password on Insect Brain DB.
    token :         str, optional
                    A token. If provided you don't need to provide username +
                    password.

    """
    if not token and (not username and not password):
        raise ValueError('Must provide either username + password, or token '
                         '(or both).')

    if username:
        session.username = username
    if password:
        session.password = password

    if token:
        session.token = token
    else:
        session.fetch_token()

Fetch brain meshes for given species.

PARAMETER DESCRIPTION
species
        Species for which to fetch brain volumes. Strings are
        interpreted as names (scientific or common), integers as IDs.

TYPE: Union[str, int]

combine
        If True, will combine subvolumes (i.e. neuropils) into
        a single navis.Volume - else will return list with volumes.

TYPE: bool DEFAULT: False

max_threads
        Number of parallel threads to use for fetching meshes.

TYPE: int DEFAULT: 4

RETURNS DESCRIPTION
list of navis.Volume

Examples:

>>> import navis
>>> import navis.interfaces.insectbrain_db as ibdb
>>> v = ibdb.get_brain_meshes('Desert Locust', combine_vols=True)
>>> navis.plot3d(v)
Source code in navis/interfaces/insectbrain_db.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def get_brain_meshes(species: Union[str, int],
                     combine: bool = False,
                     max_threads: int = 4
                     ) -> Optional[List[Volume]]:
    """Fetch brain meshes for given species.

    Parameters
    ----------
    species:        str | int
                    Species for which to fetch brain volumes. Strings are
                    interpreted as names (scientific or common), integers as IDs.
    combine :       bool, optional
                    If True, will combine subvolumes (i.e. neuropils) into
                    a single navis.Volume - else will return list with volumes.
    max_threads :   int
                    Number of parallel threads to use for fetching meshes.

    Returns
    -------
    list of navis.Volume

    Examples
    --------
    >>> import navis
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> v = ibdb.get_brain_meshes('Desert Locust', combine_vols=True)
    >>> navis.plot3d(v)

    """
    # Get info with all available neuropils
    sp_info = get_species_info(species)

    # Go over all brains
    n_brains = len(sp_info.reconstructions)  # type: ignore
    n_reconstr = len([r for r in sp_info.reconstructions if r.get('viewer_files')])  # type: ignore
    logger.info(f'{n_reconstr} reconstruction(s) from {n_brains} brain(s) found')

    volumes: List[Volume] = []
    for brain in config.tqdm(sp_info.reconstructions,
                             disable=config.pbar_hide,
                             leave=config.pbar_leave,
                             desc='Brains'):  # type: ignore
        this_v = []
        # If no reconstructions, continue
        if not brain.get('viewer_files'):  # type: ignore
            continue

        with ThreadPoolExecutor(max_workers=max_threads) as executor:
            futures = {}
            for file in brain['viewer_files']:
                # If no file UUID, continue
                if not file['p_file']['uuid']:
                    continue
                filename = file['p_file']['file_name']
                f = executor.submit(_get_neuropil_mesh, file,)
                futures[f] = filename

            with config.tqdm(desc='Fetching',
                            total=len(futures),
                            leave=config.pbar_leave,
                            disable=len(futures) == 1 or config.pbar_hide) as pbar:
                for f in as_completed(futures):
                    name = futures[f]
                    pbar.update(1)
                    try:
                        this_v.append(f.result())
                    except Exception as exc:
                        print(f'{name} generated an exception:', exc)

        # Combine all volumes in this brain
        if combine:
            this_v = [Volume.combine(this_v)]
            this_v[0].color = (.85, .85, .85, .5)
            this_v[0].name = sp_info.scientific_name

        volumes += this_v

    return volumes

Fetch volumes associated with given experiment.

PARAMETER DESCRIPTION
id
The experiment ID. See e.g. `list_datasets`.

TYPE: int

RETURNS DESCRIPTION
list

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> vols = ibdb.get_meshes_experiment(61)
Source code in navis/interfaces/insectbrain_db.py
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
def get_meshes_experiment(id) -> 'NeuronList':
    """Fetch volumes associated with given experiment.

    Parameters
    ----------
    id :    int
            The experiment ID. See e.g. `list_datasets`.

    Returns
    -------
    list

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> vols = ibdb.get_meshes_experiment(61)

    """
    # Make sure ID is integer
    id = int(id)

    # Get files associated with experiment
    files = list_experiment_files(id)

    # Figure out which files are skeletons
    me_files = files[files.file_name.str.endswith('.glb')]

    if me_files.empty:
        raise ValueError('Did not find any meshes associated with '
                         f'experiment {id}')

    volumes = []
    for f in config.tqdm(me_files.itertuples(),
                         desc='Downloading',
                         total=me_files.shape[0]):
        # Load the file
        r = requests.get(f.url)
        r.raise_for_status()

        name = '.'.join(f.file_name.split('.')[:-1])
        ext = f.file_name.split('.')[-1]

        file = io.BytesIO(r.content)
        scene = tm.load(file, file_type=ext)

        for obj in scene.geometry.values():
            v = Volume(obj.vertices, obj.faces, name=name)
            volumes.append(v)

    logger.info(f'Done! Found {len(volumes)} meshes.')

    return volumes

Fetch skeletons for given neuron(s).

PARAMETER DESCRIPTION
x
        Name(s) or ID(s) of neurons you want to fetch.

TYPE: str | int | list thereof

max_threads
        Number of parallel threads to use for fetching skeletons.

TYPE: int DEFAULT: 4

RETURNS DESCRIPTION
navis.NeuronList

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> neurons = ibdb.get_skeletons('TUps2-2')
Source code in navis/interfaces/insectbrain_db.py
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
def get_skeletons(x, max_threads=4):
    """Fetch skeletons for given neuron(s).

    Parameters
    ----------
    x :             str | int | list thereof
                    Name(s) or ID(s) of neurons you want to fetch.
    max_threads :   int
                    Number of parallel threads to use for fetching skeletons.

    Returns
    -------
    navis.NeuronList

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> neurons = ibdb.get_skeletons('TUps2-2')

    """
    if isinstance(x, (int, str, np.int32, np.int64)):
        neurons = [x]
    else:
        neurons = x

    # First fetch URLs for all neurons
    meta = []
    for x in neurons:
        if isinstance(x, str):
            q = search_neurons(name=x, partial_match=False)
            if q.empty:
                raise ValueError(f'No neuron with name "{x}" found')
            ids = q.id.values
        else:
            ids = x

        for i, id in enumerate(make_iterable(ids)):
            url = make_url(baseurl, 'api', 'v2', 'neuron', 'reconstruction',
                           neuron=id)
            info = session.get(url)

            if (not info
                or 'viewer_files' not in info[0]
                or not info[0]['viewer_files']):
                raise ValueError(f'Neuron {x} ({id}) has no skeleton.')

            meta.append(info[0])

    return _get_skeletons(meta, max_threads=max_threads)

Fetch all skeletons for given experiment.

PARAMETER DESCRIPTION
id
The experiment ID. See e.g. `list_datasets`.

TYPE: int

RETURNS DESCRIPTION
NeuronList

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> nl = ibdb.get_skeletons_experiment(61)
Source code in navis/interfaces/insectbrain_db.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
def get_skeletons_experiment(id) -> 'NeuronList':
    """Fetch all skeletons for given experiment.

    Parameters
    ----------
    id :    int
            The experiment ID. See e.g. `list_datasets`.

    Returns
    -------
    NeuronList

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> nl = ibdb.get_skeletons_experiment(61)

    """
    # Make sure ID is integer
    id = int(id)

    # Get files associated with experiment
    files = list_experiment_files(id)

    # Figure out which files are skeletons
    sk_files = files[files.file_name.str.contains('skeleton') | files.file_name.str.endswith('.gz')]

    if sk_files.empty:
        raise ValueError('Did not find any skeleton files associated with '
                         f'experiment {id}')

    skeletons = []
    for f in sk_files.itertuples():
        logger.info(f'Downloading {f.file_name}')
        # Load the file
        r = requests.get(f.url)
        r.raise_for_status()

        # Files appear to be json-formatted and not compressed
        data = r.json()

        for i, neuron in enumerate(data['data']):
            for sk in neuron['skeletons']:
                # Load SWC table
                swc = pd.DataFrame(sk['data'],
                                   columns=['node_id', 'skeleton_id',
                                            'x', 'y', 'z', 'radius',
                                            'parent_id'])
                # Some cleaning up
                swc.drop('skeleton_id', axis=1, inplace=True)
                swc['parent_id'] = swc.parent_id.fillna(-1).astype(int)
                # Create neuron
                tn = TreeNeuron(swc,
                                id=sk.get('id', 1),
                                name=neuron.get('name', 'NA'),
                                annotations=neuron.get('annotations', []),
                                soma=None)
                skeletons.append(tn)
    logger.info(f'Done! Found {len(skeletons)} skeletons.')

    return NeuronList(skeletons)

Fetch all skeletons for given species.

Note that some neurons might have multiple reconstructions. They will show up with the same ID with different names.

PARAMETER DESCRIPTION
species
        Name or ID of a species to fetch skeletons for.

TYPE: str | int

max_threads
        Number of parallel threads to use for fetching skeletons.

TYPE: int DEFAULT: 4

RETURNS DESCRIPTION
navis.NeuronList

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> neurons = ibdb.get_skeletons_species('Desert Locust')
Source code in navis/interfaces/insectbrain_db.py
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
def get_skeletons_species(species, max_threads=4):
    """Fetch all skeletons for given species.

    Note that some neurons might have multiple reconstructions. They will
    show up with the same ID with different names.

    Parameters
    ----------
    species :       str | int
                    Name or ID of a species to fetch skeletons for.
    max_threads :   int
                    Number of parallel threads to use for fetching skeletons.

    Returns
    -------
    navis.NeuronList

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> neurons = ibdb.get_skeletons_species('Desert Locust')

    """
    if isinstance(species, str):
        species = _get_species_id(species)

    # First fetch URLs for all neurons
    url = make_url(baseurl, 'api', 'v2', 'neuron', 'reconstruction',
                   neuron__species=species)
    meta = session.get(url)

    meta = [e for e in meta if e['viewer_files']]

    return _get_skeletons(meta, max_threads=max_threads)

List publication datasets and associated experiments.

RETURNS DESCRIPTION
pandas.DataFrame

DataFrame with available datasets.

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> datasets = ibdb.list_datasets()
Source code in navis/interfaces/insectbrain_db.py
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
def list_datasets() -> pd.DataFrame:
    """List publication datasets and associated experiments.

    Returns
    -------
    pandas.DataFrame
            DataFrame with available datasets.

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> datasets = ibdb.list_datasets()

    """
    url = make_url(baseurl, 'api', 'publications', 'experiments?offset=0&limit=500')

    return _sort_columns(pd.DataFrame.from_records(session.get(url)['results']))

List files associated with given experiment.

PARAMETER DESCRIPTION
id
The experiment ID. See e.g. `list_datasets`.

TYPE: int

RETURNS DESCRIPTION
pandas.DataFrame

DataFrame with files.

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> files = ibdb.list_experiment_files(61)
Source code in navis/interfaces/insectbrain_db.py
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def list_experiment_files(id) -> pd.DataFrame:
    """List files associated with given experiment.

    Parameters
    ----------
    id :    int
            The experiment ID. See e.g. `list_datasets`.

    Returns
    -------
    pandas.DataFrame
            DataFrame with files.

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> files = ibdb.list_experiment_files(61)

    """
    url = make_url(baseurl, 'api', 'v2', 'experiment', id, 'file')

    return _sort_columns(pd.DataFrame.from_records(session.get(url)))

Search for neurons matching given parameters.

PARAMETER DESCRIPTION
name
        Name of the neuron.

TYPE: str DEFAULT: None

short_name
        Short name of the neuron.

TYPE: str DEFAULT: None

species
        Name or ID of the species. Can be common or scientific name.

TYPE: str | int DEFAULT: None

sex
        Sex of the neuron.

TYPE: "FEMALE" | "MALE" | "UNKNOWN" DEFAULT: None

arborization
        Restrict to neurons having arborizations in given neuropil.

TYPE: str DEFAULT: None

partial_match
        Whether to allow partial matches (does not apply for species).

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
pandas.DataFrame

Examples:

>>> import navis.interfaces.insectbrain_db as ibdb
>>> neurons = ibdb.search_neurons(species='Desert Locust')
Source code in navis/interfaces/insectbrain_db.py
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
def search_neurons(name=None, short_name=None, species=None, sex=None,
                   arborization=None, partial_match=True) -> pd.DataFrame:
    """Search for neurons matching given parameters.

    Parameters
    ----------
    name :          str, optional
                    Name of the neuron.
    short_name :    str, optional
                    Short name of the neuron.
    species :       str | int, optional
                    Name or ID of the species. Can be common or scientific name.
    sex :           "FEMALE" | "MALE" | "UNKNOWN", optional
                    Sex of the neuron.
    arborization :  str, optional
                    Restrict to neurons having arborizations in given neuropil.
    partial_match : bool
                    Whether to allow partial matches (does not apply for species).

    Returns
    -------
    pandas.DataFrame

    Examples
    --------
    >>> import navis.interfaces.insectbrain_db as ibdb
    >>> neurons = ibdb.search_neurons(species='Desert Locust')

    """
    # Construct query
    options = {}
    if species:
        if not isinstance(species, int):
            species = _get_species_id(species)
        options['species'] = species

    for key, value in zip(['name', 'short_name', 'sex',
                           'arborization_region__structure'],
                          [name, short_name, sex, arborization]):
        if not value:
            continue
        if partial_match:
            key += '__icontains'
        options[key] = value

    url = make_url(baseurl, 'api', 'v2', 'neuron', **options)

    resp = requests.get(url)

    resp.raise_for_status()

    return _sort_columns(pd.DataFrame.from_records(resp.json()))