Brain Areas
Install Urchin
Urchin is a Python package stored on PyPI, the following code needs to be run the first time you use Urchin in a Python environment.
Urchin’s full documentation can be found on our website.
[1]:
#Installing urchin
!pip install oursin -U
Setup Urchin and open the renderer webpage
By default Urchin opens the 3D renderer in a webpage. Make sure pop-ups are enabled, or the page won’t open properly. You can also open the renderer site yourself by replacing [ID here] with the ID that is output by the call to .setup()
at https://data.virtualbrainlab.org/Urchin/?ID=[ID here]
Note that Urchin communicates to the renderer webpage through an internet connection, we don’t currently support offline use (we hope to add support in the future).
[1]:
import oursin as urchin
urchin.setup()
(URN) connected to server
Login sent with ID: dcbfc6ba, copy this ID into the renderer to connect.
Loading a reference atlas and displaying brain areas
Multiple reference atlases are available in Urchin, before we can access individual brain areas we need to have an atlas loaded. Here we’ll load the Allen Mouse CCF atlas.
Only one atlas can be loaded at a time.
[2]:
urchin.ccf25.load()
An Atlas stores a list of areas, which can be loaded in the renderer. The list of all areas, stored as Structure
objects can be found in urchin.ccf25.data.areas
. Individual Structure
objects can be accessed directly by their acronym using urchin.ccf25.acronym
[3]:
print([area.acronym for area in urchin.ccf25.data.areas])
urchin.ccf25.root.set_visibility(True, side=urchin.utils.Side.FULL)
['root', 'grey', 'CH', 'CTX', 'CTXpl', 'Isocortex', 'FRP', 'FRP1', 'FRP2/3', 'FRP5', 'FRP6a', 'FRP6b', 'MO', 'MOp', 'MOp1', 'MOp2/3', 'MOp5', 'MOp6a', 'MOp6b', 'MOs', 'MOs1', 'MOs2/3', 'MOs5', 'MOs6a', 'MOs6b', 'SS', 'SSp', 'SSp-n', 'SSp-n1', 'SSp-n2/3', 'SSp-n4', 'SSp-n5', 'SSp-n6a', 'SSp-n6b', 'SSp-bfd', 'SSp-bfd1', 'SSp-bfd2/3', 'SSp-bfd4', 'SSp-bfd5', 'SSp-bfd6a', 'SSp-bfd6b', 'SSp-ll', 'SSp-ll1', 'SSp-ll2/3', 'SSp-ll4', 'SSp-ll5', 'SSp-ll6a', 'SSp-ll6b', 'SSp-m', 'SSp-m1', 'SSp-m2/3', 'SSp-m4', 'SSp-m5', 'SSp-m6a', 'SSp-m6b', 'SSp-ul', 'SSp-ul1', 'SSp-ul2/3', 'SSp-ul4', 'SSp-ul5', 'SSp-ul6a', 'SSp-ul6b', 'SSp-tr', 'SSp-tr1', 'SSp-tr2/3', 'SSp-tr4', 'SSp-tr5', 'SSp-tr6a', 'SSp-tr6b', 'SSp-un', 'SSp-un1', 'SSp-un2/3', 'SSp-un4', 'SSp-un5', 'SSp-un6a', 'SSp-un6b', 'SSs', 'SSs1', 'SSs2/3', 'SSs4', 'SSs5', 'SSs6a', 'SSs6b', 'GU', 'GU1', 'GU2/3', 'GU4', 'GU5', 'GU6a', 'GU6b', 'VISC', 'VISC1', 'VISC2/3', 'VISC4', 'VISC5', 'VISC6a', 'VISC6b', 'AUD', 'AUDd', 'AUDd1', 'AUDd2/3', 'AUDd4', 'AUDd5', 'AUDd6a', 'AUDd6b', 'AUDp', 'AUDp1', 'AUDp2/3', 'AUDp4', 'AUDp5', 'AUDp6a', 'AUDp6b', 'AUDpo', 'AUDpo1', 'AUDpo2/3', 'AUDpo4', 'AUDpo5', 'AUDpo6a', 'AUDpo6b', 'AUDv', 'AUDv1', 'AUDv2/3', 'AUDv4', 'AUDv5', 'AUDv6a', 'AUDv6b', 'VIS', 'VISal', 'VISal1', 'VISal2/3', 'VISal4', 'VISal5', 'VISal6a', 'VISal6b', 'VISam', 'VISam1', 'VISam2/3', 'VISam4', 'VISam5', 'VISam6a', 'VISam6b', 'VISl', 'VISl1', 'VISl2/3', 'VISl4', 'VISl5', 'VISl6a', 'VISl6b', 'VISp', 'VISp1', 'VISp2/3', 'VISp4', 'VISp5', 'VISp6a', 'VISp6b', 'VISpl', 'VISpl1', 'VISpl2/3', 'VISpl4', 'VISpl5', 'VISpl6a', 'VISpl6b', 'VISpm', 'VISpm1', 'VISpm2/3', 'VISpm4', 'VISpm5', 'VISpm6a', 'VISpm6b', 'VISli', 'VISli1', 'VISli2/3', 'VISli4', 'VISli5', 'VISli6a', 'VISli6b', 'VISpor', 'VISpor1', 'VISpor2/3', 'VISpor4', 'VISpor5', 'VISpor6a', 'VISpor6b', 'ACA', 'ACAd', 'ACAd1', 'ACAd2/3', 'ACAd5', 'ACAd6a', 'ACAd6b', 'ACAv', 'ACAv1', 'ACAv2/3', 'ACAv5', 'ACAv6a', 'ACAv6b', 'PL', 'PL1', 'PL2/3', 'PL5', 'PL6a', 'PL6b', 'ILA', 'ILA1', 'ILA2/3', 'ILA5', 'ILA6a', 'ILA6b', 'ORB', 'ORBl', 'ORBl1', 'ORBl2/3', 'ORBl5', 'ORBl6a', 'ORBl6b', 'ORBm', 'ORBm1', 'ORBm2/3', 'ORBm5', 'ORBm6a', 'ORBm6b', 'ORBvl', 'ORBvl1', 'ORBvl2/3', 'ORBvl5', 'ORBvl6a', 'ORBvl6b', 'AI', 'AId', 'AId1', 'AId2/3', 'AId5', 'AId6a', 'AId6b', 'AIp', 'AIp1', 'AIp2/3', 'AIp5', 'AIp6a', 'AIp6b', 'AIv', 'AIv1', 'AIv2/3', 'AIv5', 'AIv6a', 'AIv6b', 'RSP', 'RSPagl', 'RSPagl1', 'RSPagl2/3', 'RSPagl5', 'RSPagl6a', 'RSPagl6b', 'RSPd', 'RSPd1', 'RSPd2/3', 'RSPd4', 'RSPd5', 'RSPd6a', 'RSPd6b', 'RSPv', 'RSPv1', 'RSPv2/3', 'RSPv5', 'RSPv6a', 'RSPv6b', 'PTLp', 'VISa', 'VISa1', 'VISa2/3', 'VISa4', 'VISa5', 'VISa6a', 'VISa6b', 'VISrl', 'VISrl1', 'VISrl2/3', 'VISrl4', 'VISrl5', 'VISrl6a', 'VISrl6b', 'TEa', 'TEa1', 'TEa2/3', 'TEa4', 'TEa5', 'TEa6a', 'TEa6b', 'PERI', 'PERI1', 'PERI2/3', 'PERI5', 'PERI6a', 'PERI6b', 'ECT', 'ECT1', 'ECT2/3', 'ECT5', 'ECT6a', 'ECT6b', 'OLF', 'MOB', 'AOB', 'AOBgl', 'AOBgr', 'AOBmi', 'AON', 'TT', 'TTd', 'TTv', 'DP', 'PIR', 'NLOT', 'NLOT1', 'NLOT2', 'NLOT3', 'COA', 'COAa', 'COAp', 'COApl', 'COApm', 'PAA', 'TR', 'HPF', 'HIP', 'CA', 'CA1', 'CA2', 'CA3', 'DG', 'DG-mo', 'DG-po', 'DG-sg', 'FC', 'IG', 'RHP', 'ENT', 'ENTl', 'ENTl1', 'ENTl2', 'ENTl3', 'ENTl5', 'ENTl6a', 'ENTm', 'ENTm1', 'ENTm2', 'ENTm3', 'ENTm5', 'ENTm6', 'PAR', 'POST', 'PRE', 'SUB', 'ProS', 'HATA', 'APr', 'CTXsp', 'CLA', 'EP', 'EPd', 'EPv', 'LA', 'BLA', 'BLAa', 'BLAp', 'BLAv', 'BMA', 'BMAa', 'BMAp', 'PA', 'CNU', 'STR', 'STRd', 'CP', 'STRv', 'ACB', 'FS', 'OT', 'LSX', 'LS', 'LSc', 'LSr', 'LSv', 'SF', 'SH', 'sAMY', 'AAA', 'BA', 'CEA', 'CEAc', 'CEAl', 'CEAm', 'IA', 'MEA', 'PAL', 'PALd', 'GPe', 'GPi', 'PALv', 'SI', 'MA', 'PALm', 'MSC', 'MS', 'NDB', 'TRS', 'PALc', 'BST', 'BAC', 'BS', 'IB', 'TH', 'DORsm', 'VENT', 'VAL', 'VM', 'VP', 'VPL', 'VPLpc', 'VPM', 'VPMpc', 'PoT', 'SPF', 'SPFm', 'SPFp', 'SPA', 'PP', 'GENd', 'MG', 'MGd', 'MGv', 'MGm', 'LGd', 'LGd-sh', 'LGd-co', 'LGd-ip', 'DORpm', 'LAT', 'LP', 'PO', 'POL', 'SGN', 'Eth', 'ATN', 'AV', 'AM', 'AMd', 'AMv', 'AD', 'IAM', 'IAD', 'LD', 'MED', 'IMD', 'MD', 'SMT', 'PR', 'MTN', 'PVT', 'PT', 'RE', 'Xi', 'ILM', 'RH', 'CM', 'PCN', 'CL', 'PF', 'PIL', 'RT', 'GENv', 'IGL', 'IntG', 'LGv', 'SubG', 'EPI', 'MH', 'LH', 'HY', 'PVZ', 'SO', 'ASO', 'PVH', 'PVa', 'PVi', 'ARH', 'PVR', 'ADP', 'AVP', 'AVPV', 'DMH', 'MEPO', 'MPO', 'OV', 'PD', 'PS', 'PVp', 'PVpo', 'SBPV', 'SCH', 'SFO', 'VMPO', 'VLPO', 'MEZ', 'AHN', 'MBO', 'LM', 'MM', 'MMme', 'MMl', 'MMm', 'MMp', 'MMd', 'SUM', 'TM', 'TMd', 'TMv', 'MPN', 'PMd', 'PMv', 'PVHd', 'VMH', 'PH', 'LZ', 'LHA', 'LPO', 'PST', 'PSTN', 'PeF', 'RCH', 'STN', 'TU', 'ZI', 'FF', 'ME', 'MB', 'MBsen', 'SCs', 'SCop', 'SCsg', 'SCzo', 'IC', 'ICc', 'ICd', 'ICe', 'NB', 'SAG', 'PBG', 'MEV', 'SCO', 'MBmot', 'SNr', 'VTA', 'PN', 'RR', 'MRN', 'SCm', 'SCdg', 'SCdw', 'SCiw', 'SCig', 'PAG', 'PRC', 'INC', 'ND', 'Su3', 'PRT', 'APN', 'MPT', 'NOT', 'NPC', 'OP', 'PPT', 'RPF', 'CUN', 'RN', 'III', 'MA3', 'EW', 'IV', 'Pa4', 'VTN', 'AT', 'LT', 'DT', 'MT', 'MBsta', 'SNc', 'PPN', 'RAmb', 'IF', 'IPN', 'IPR', 'IPC', 'IPA', 'IPL', 'IPI', 'IPDM', 'IPDL', 'IPRL', 'RL', 'CLI', 'DR', 'HB', 'P', 'P-sen', 'NLL', 'PSV', 'PB', 'KF', 'SOC', 'POR', 'SOCm', 'SOCl', 'P-mot', 'B', 'DTN', 'PDTg', 'PCG', 'PG', 'PRNc', 'SG', 'SUT', 'TRN', 'V', 'P5', 'Acs5', 'PC5', 'I5', 'P-sat', 'CS', 'LC', 'LDT', 'NI', 'PRNr', 'RPO', 'SLC', 'SLD', 'MY', 'MY-sen', 'AP', 'CN', 'DCO', 'VCO', 'DCN', 'CU', 'GR', 'ECU', 'NTB', 'NTS', 'SPVC', 'SPVI', 'SPVO', 'Pa5', 'MY-mot', 'VI', 'VII', 'ACVII', 'AMB', 'AMBd', 'AMBv', 'DMX', 'GRN', 'ICB', 'IO', 'IRN', 'ISN', 'LIN', 'LRN', 'LRNm', 'LRNp', 'MARN', 'MDRN', 'MDRNd', 'MDRNv', 'PARN', 'PAS', 'PGRN', 'PGRNd', 'PGRNl', 'PHY', 'NR', 'PRP', 'PPY', 'VNC', 'LAV', 'MV', 'SPIV', 'SUV', 'x', 'XII', 'y', 'MY-sat', 'RM', 'RPA', 'RO', 'CB', 'CBX', 'VERM', 'LING', 'CENT', 'CENT2', 'CENT3', 'CUL', 'CUL4, 5', 'DEC', 'FOTU', 'PYR', 'UVU', 'NOD', 'HEM', 'SIM', 'AN', 'ANcr1', 'ANcr2', 'PRM', 'COPY', 'PFL', 'FL', 'CBN', 'FN', 'IP', 'DN', 'VeCB', 'fiber tracts', 'cm', 'von', 'In', 'onl', 'lotg', 'lot', 'lotd', 'aco', 'IIn', 'bsc', 'csc', 'och', 'opt', 'IIIn', 'mlf', 'pc', 'IVn', 'Vn', 'moV', 'sV', 'sptV', 'VIIn', 'gVIIn', 'VIIIn', 'vVIIIn', 'cVIIIn', 'tb', 'das', 'll', 'cic', 'bic', 'Xn', 'ts', 'drt', 'cett', 'dc', 'cuf', 'ml', 'cbf', 'cbc', 'cbp', 'scp', 'dscp', 'uf', 'sctv', 'mcp', 'icp', 'sctd', 'arb', 'scwm', 'lfbs', 'cc', 'fa', 'ec', 'ee', 'ccg', 'fp', 'ccb', 'ccs', 'cst', 'int', 'cpd', 'py', 'pyd', 'lfbst', 'em', 'or', 'ar', 'eps', 'epsc', 'nst', 'tsp', 'tspd', 'dtd', 'tspc', 'rust', 'vtd', 'mfbs', 'mfbc', 'amc', 'act', 'cing', 'fxs', 'alv', 'df', 'fi', 'fxpo', 'mct', 'fx', 'hc', 'dhc', 'vhc', 'st', 'stc', 'mfsbshy', 'mfb', 'sup', 'mfbsma', 'pm', 'mtt', 'mtg', 'mp', 'mfbse', 'sm', 'fr', 'hbc', 'VS', 'VL', 'SEZ', 'chpl', 'V3', 'AQ', 'V4', 'V4r', 'c']
Throughout this tutorial, we’ll use the screenshot function on the main camera to see what effect we had on the scene. Note that because taking screenshots requires waiting for data to come back, you need to use the Python await
keyword.
[4]:
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) Camera CameraMain received an image
(Camera receive) CameraMain complete
[4]:
Areas have a bit of metadata as well
[5]:
print(urchin.ccf25.root.data.name)
print(urchin.ccf25.root.data.acronym)
print(urchin.ccf25.root.data.atlas_id)
print(urchin.ccf25.root.data.color)
root
root
997
r=1.0 g=1.0 b=1.0 a=1
You might not want to load areas with their default color or material, you can set your own color, material, and alpha overrides.
[6]:
urchin.ccf25.root.set_color([1, 1, 0.5], push = False)
urchin.ccf25.root.set_material('transparent-lit', push = False)
urchin.ccf25.root.set_alpha(0.5)
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) CameraMain complete
[6]:
You can also clear the atlas off of the screen. It will remain loaded in the background.
[7]:
urchin.ccf25.clear()
You can use the side=
input parameter for any of the area functions to load a single hemisphere.
[8]:
# load just left hemisphere
urchin.ccf25.root.set_visibility(True, side=urchin.utils.Side.LEFT)
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) CameraMain complete
[8]:
[9]:
urchin.ccf25.clear()
Complete example with the IBL BWM dataset
We’re going to work through a complete example here similar to what you might do in your own analysis. We’ll grab a set of data files related to the IBL Brain-wide map and use those to set the color of brain regions in the renderer. Then we’ll rotate the camera to get a nice angle and take a screenshot.
[ ]:
!pip install pyarrow pandas
[10]:
# import additional packages
import pyarrow.parquet as pq
import pandas as pd
import requests
import numpy as np
from io import BytesIO
[11]:
## Get data from google drive
# The BWM analysis output are stored in set of parquet files, let's load them from their google drive links
# The datasets are the decoding analysis results for block, choice, feedback, stimulus, wheel speed, and wheel velocity
drive_ids = ['16m-vWRxtbsnaq4oX15lK7BIKnsqsZ-UT',
'1F-UYxLCX0FT_0Vh5ugGByVM6RL0u7cCp',
'1Fq_07Rexvq_Vp7Mh0_TOR1xRmLhHSwDh',
'1MU5Oe-BaU8YQTlS-0egwPhgoiOLYO5Zm',
'15Vas51DHezrwrUje1ZJrMI2uAeJcxl8j',
'1nquiEYdFuORtrHF3LyJT32Dr_d2Kt_k4']
datasets = []
for file_id in drive_ids:
url = f"https://drive.google.com/uc?id={file_id}"
response = requests.get(url)
parquet_file = pq.read_table(BytesIO(response.content))
datasets.append(parquet_file.to_pandas())
# There's one area that shows up in IBL that we don't have in our atlas, so we'll just drop that area...
missing_area = 'CUL4 5'
for i, dataset in enumerate(datasets):
datasets[i] = dataset[dataset.acronym_b != missing_area]
[12]:
urchin.ccf25.load()
(Warning) Atlas was already loaded, the renderer can have issues if you try to load an atlas twice.
[12]:
# Let's start by loading all the brain areas, just the left side
area_names = datasets[0].acronym_b.values
area_list = urchin.ccf25.get_areas(area_names)
urchin.ccf25.set_visibilities(area_list, True, urchin.utils.Side.LEFT)
[17]:
area_names
[17]:
array(['FRP', 'MOp', 'MOs', 'SSp-n', 'SSp-bfd', 'SSp-ll', 'SSp-m',
'SSp-ul', 'SSp-tr', 'SSs', 'VISC', 'AUDp', 'AUDv', 'VISam', 'VISl',
'VISp', 'VISpm', 'VISli', 'VISpor', 'ACAd', 'ACAv', 'PL', 'ILA',
'ORBl', 'ORBm', 'ORBvl', 'AId', 'AIp', 'AIv', 'RSPagl', 'RSPd',
'RSPv', 'VISa', 'VISrl', 'TEa', 'ECT', 'AON', 'TTd', 'DP', 'PIR',
'COAp', 'CA1', 'CA3', 'DG', 'ENTl', 'ENTm', 'PAR', 'POST', 'PRE',
'SUB', 'ProS', 'EPd', 'EPv', 'BLA', 'BMA', 'PA', 'CP', 'ACB', 'OT',
'LSr', 'LSv', 'SF', 'CEA', 'MEA', 'GPe', 'SI', 'MS', 'TRS', 'BST',
'VAL', 'VM', 'VPL', 'VPM', 'PoT', 'MG', 'LGd', 'LP', 'PO', 'POL',
'SGN', 'Eth', 'AV', 'AM', 'LD', 'MD', 'SMT', 'PVT', 'PCN', 'RT',
'LGv', 'MPO', 'LHA', 'PeF', 'ZI', 'IC', 'MRN', 'SCm', 'PAG', 'APN',
'RN', 'PPN', 'PB', 'PRNc', 'V', 'CS', 'PRNr', 'DCO', 'SPVI', 'GRN',
'IRN', 'MDRN', 'PARN', 'MV', 'CENT2', 'CENT3', 'NOD', 'SIM',
'ANcr1', 'ANcr2', 'PRM', 'COPY', 'IP'], dtype=object)
[14]:
# rotate the camera so we are looking from the "anterior/left/dorsal" coordinate
urchin.camera.main.set_rotation([22.5, 22.5, 225])
urchin.camera.main.set_zoom(45)
[16]:
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) CameraMain complete
[16]:
[17]:
# With all the areas loaded, let's color them using one of the available colormaps
urchin.ccf25.set_colormap('grey-green')
# We'll set the value of each area according to it's stimulus decoding effect, re-scaled to take advantage of the full colormap range
stim_decoding = datasets[0].decoding_effect.values
min_val = np.min(stim_decoding)
max_val = np.max(stim_decoding)
def rescale(val):
return (val - min_val) / (max_val - min_val)
stim_decoding_rescaled = [rescale(x) for x in stim_decoding]
urchin.ccf25.set_color_intensity(area_list, stim_decoding_rescaled, 'left')
[18]:
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) CameraMain complete
[18]:
We could make that look a little nicer by loading all the areas, since a few aren’t included in the decoding analysis, and coloring the ones that are missing grey. But let’s stop there for now.
[19]:
urchin.ccf25.clear()
Each Atlas includes a set of “default” areas. These are the highest regions in the ontology hierarchy that split the brain into major areas. Loading the defaults can be useful to create a clean visualization of the whole brain where major areas are clearly segmented.
Loading the defaults loads the left and right hemispheres separately, this is so that you can easily use the “explode” feature to pull brain regions apart. This does mean that if you want to set the materials, colors, etc, you need to use sided='left'
or sided='right'
[20]:
urchin.ccf25.load_defaults()
[21]:
await urchin.camera.main.screenshot(size=[600,400])
(Camera receive) CameraMain complete
[21]:
[ ]: