2. Selecting neurons¶
There is one mini-language for saying "these neurons", and it works everywhere.
Anything you can pass to ids() you can pass to any query — edges(),
synapses(), skeletons.get(), all of it.
The five forms¶
Root IDs, body IDs, ints, strings of digits, lists, arrays, Series — all fine.
array([720575940603231916, 720575940604407468, 720575940605102694,
720575940613345442, 720575940614309535, 720575940617229632,
720575940619385765, 720575940621185050, 720575940621239679,
720575940623303108, 720575940623543881, 720575940626034819,
720575940630066007, 720575940637208718, 720575940637469254])
Matched across whichever columns the dataset declares as type columns — see below.
column:value filters any column in the annotation table — not just the ones
connecto knows about.
Combining¶
side= is separate, because you want it constantly:
array([720575940603231916, 720575940605102694, 720575940613345442,
720575940614309535, 720575940619385765, 720575940621185050,
720575940626034819, 720575940637208718])
Eight of the fifteen. side is always left / right / center regardless of what
the dataset natively calls it — FlyWire says left/right, hemibrain encodes it as
a suffix on instance (DA1_lPN_R), MANC says something else again. You get the
same three words.
A list is a union:
fw.ids(["DA1_lPN", "DA1_vPN"]) # both types
fw.ids(["/^AOTU00.*", 720575940604407468]) # regex OR a specific neuron
It is a pure function¶
ids() returns an array and mutates nothing. There is no add_neurons, no
accumulating selection on the dataset object, no hidden state that a later call will
read.
This is a deliberate reaction to how the previous attempt (cocoa) worked: a mutable
selection plus a memoised annotation frame is precisely how you end up joining
annotations from one materialization onto edges from another, and never finding out.
If you want the IDs, you hold them:
ids = fw.ids("DA1_lPN", side="left")
edges = fw.connectivity.edges(ids)
skels = fw.skeletons.get(ids)
What counts as a "type"¶
Different datasets have wildly different ideas about this, so each declares its own
priority order. FlyWire's is cell_type, then hemibrain_type; hemibrain's is just
type. ds.annotations.fields tells you:
{'type': ('cell_type', 'hemibrain_type'),
'side': ('side',),
'class': ('super_class',),
'nt': ('top_nt',),
...}
ds.ids("DA1_lPN") coalesces those in order: use cell_type if it is set, else fall
back to hemibrain_type.
If a dataset has no type column configured, connecto does not guess:
ValueError: MICrONS (minnie65) public has no `type` column configured. Pass
`fields={'type': (...)}` to the dataset, or query a raw column with 'column:value'.
MICrONS ships with fields={} on purpose. Its cell types are spread across several
tables with genuinely different semantics (cell_type_local, aibs_metamodel_mtypes,
nucleus_svm), and picking one to be the type would be a scientific judgement
disguised as a default. So it refuses, and tells you how to say what you meant:
mic = cn.MICrONS()
mic.ids("cell_type:BC") # be explicit, or
mic = cn.MICrONS(fields={"type": ("cell_type",)}) # declare it once
mic.ids("BC")
Finding out what is there¶
Searches type, class and instance. To see everything:
['id', 'type', 'side', 'class', 'nt', 'status', 'soma_x', 'soma_y', 'soma_z',
'supervoxel_id', 'pos_x', 'pos_y', 'pos_z', 'nucleus_id', 'flow', 'super_class',
'cell_class', 'cell_sub_class', 'supertype', 'cell_type', 'hemibrain_type',
'ito_lee_hemilineage', 'hartenstein_hemilineage', 'top_nt', 'top_nt_conf',
'known_nt', 'known_nt_source', 'nerve', 'vfb_id', 'fbbt_id', 'dimorphism',
'matching_notes', 'fru_dsx', 'synonyms']
The first nine are canonical — the same names, same dtypes, same units on every dataset. The remaining twenty-five are FlyWire's own, passed through untouched.
Annotations are an open schema, and that is the opposite choice from edges. Edges
are closed because you compare them across datasets. Annotations are open because
ito_lee_hemilineage has no hemibrain equivalent and no mouse equivalent, and
throwing it away would be worse than the asymmetry.
Any of those columns works as a filter:
Misspell one and it guesses:
ValueError: FlyWire (FAFB) public release annotations have no column 'super_clas'.
Did you mean 'super_class'?
A worked example¶
Left-side olfactory projection neurons, and what they talk to:
edges = fw.connectivity.edges(alpn, upstream=False, min_weight=5)
# Who do they target, by type?
ann = fw.annotations.get()[["id", "type"]]
top = (edges.merge(ann, left_on="post", right_on="id")
.groupby("type", observed=True)["weight"].sum()
.sort_values(ascending=False)
.head())
Note the join key: post on the left, id on the right. id is canonical — it is
called id in every annotation frame from every dataset, which is what lets that line
be written once.
Next: connectivity in earnest.