FruitFlyLab
The bench for a `FruitFlyBrain`. A movable, resizable window, laid out from `ui.screenSize()` so it reads the same on a phone held upright and on a wide monitor, holding everything a person does to the network by hand.
FruitFlyLab
The bench for a FruitFlyBrain. A movable, resizable window, laid out from
ui.screenSize() so it reads the same on a phone held upright and on a wide
monitor, holding everything a person does to the network by hand.
From the top:
- Header. The connectome's name and its neuron and connection counts, with thousands separators.
- State. Simulated seconds and the mean rate over the whole network on one line, spikes and dropped spikes on the next, in a tabular face. When the network is above 0.05 Hz with no drive live, a line says so: the activity is recurrence in the wiring, and reset is the cure.
- Run / pause, reset, clear drive, then the three sliders (gain, time scale, minimum synapses) in one fixed label column, so the tracks and the value pills line up. The pill is the value; the label is the name alone.
- Readouts. One row per watched group: an
xthat stops watching it, the group's name in its own colour, a bar drawn to that group's own full scale with the scale printed beside it, and the rate. The rows scroll inside a capped block, and groups sitting at zero collapse into one dimmed line with ashowthat opens them. Below, the trace: every group on one plot over the last 24 seconds, on a square root scale so a group at 4 Hz stays visible beside one at 130, with both gridline values named in the section header. A group of 32 neurons or fewer offers a raster, one row per neuron with a tick wherever that neuron was active at the sample. - Hot classes. The ten cell classes with the highest mean activity right now, as bars. Activity is the model's own 60 ms spike trace, not a rate, and the block says so.
- Live drives. What is being driven at this moment and by whom: the bench, the fly, or a protocol.
- Selection. Eight chips for the cell types this bench is used on most, a free text field, the rate slider, then stimulate / silence / restore, and watch / count with a name field.
- Neuron. What the last identified neuron is, with a button that fills the selection with its cell type.
- Fly. What the fly senses and what it does, as the fly reports them.
- Legend. A swatch per colour in the neuron cloud, with the dataset's own superclass names beside it.
A group keeps its colour for the life of the session: the colour comes from a hash of the group's own name into a twelve colour palette, so adding a group never recolours the others.
Selections
The grammar lives in selection.module beside this component, and its README
is the table of terms. lab:parseSelection(text) is the bench's way in to it
and returns the same (selection, error) pair it always did.
Controls
lab.inputMap carries the bench's own controls on keyboard, gamepad and
touch: labToggle (L, Start, the Lab button), labFocusNext and
labFocusPrev (arrows or Tab, D-pad), labActivate (Enter, north),
labAdjustLeft and labAdjustRight (arrows, D-pad, 5 percent of the
slider's range) and labIdentify (mouse left, west, the ID button). The
focused control draws a 2 px accent border, so every control is reachable
with a pad alone or a keyboard alone. A "Lab" button sits at the bottom left
of the screen for a finger, and the window's own hide and show button is
where it always was.
labIdentify names the neuron under the pointer, or under the screen centre
when nothing has moved the pointer recently, which is what a pad and the
touch button aim with. A press the bench's own window took is ignored.
Fields and methods
Fields: brain, fly, open, refreshHz, inputMap.
Method: parseSelection(text).
entity.spawn("Lab").component.add("FruitFlyLab", { brain = entity.find("Brain"), fly = entity.find("Fly") })
What the bench reads from the network
Everything the bench draws comes from the FruitFlyBrain on the brain
entity: describe() for the header, the state line and every group's size
and rate, classRates() for the hot classes, drives() for the live drives,
groupActivity(name) for a raster, and neuronAt(x, y) for a pick. A
network that publishes none of the last four still draws every other block,
and the blocks that need them say what is missing rather than showing a
number nobody computed.
The experiments guide (guides { path = "experiments" }) is the manual.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2FruitFlyLab: the bench for running experiments on a FruitFlyBrain. A movable window, laid out from the live screen size, shows the network (simulated time, mean rate, dropped spikes), holds its knobs (run, reset, synaptic gain, time scale, connection threshold), reads out every watched group as a live rate with a bar, a rolling trace and a raster, names the classes that are hot and the drives that are live, and takes a selection expression to stimulate, silence, restore, watch or count any set of neurons by cell type, class, superclass, side or pattern. When a `fly` is set, it also shows what that fly senses and does. Every control is reachable with a pointer, with the keyboard or a pad through `lab.inputMap` (the focused control draws a 2 px outline), and with a finger through the touch buttons the same map declares.
brainComp( ) → void
flyComp( ) → void
ask(target: any, method: string, ...: ?) → any
A method the network may not publish, called safely. A `Brain` handle is a plain table, so a name it does not carry reads as nil and the bench draws the block that does exist instead.
| arg | type | description |
|---|---|---|
| target | any | |
| method | string | |
| ... | ? |
askComponent(comp: any, method: string, ...: ?) → void
Answers the call's result and whether the component declares the method at all, which a nil result on its own cannot say.
| arg | type | description |
|---|---|---|
| comp | any | |
| method | string | |
| ... | ? |
fmt(n: number, digits: number?) → string
| arg | type | description |
|---|---|---|
| n | number | |
| digits | number? |
thousands(n: number) → string
| arg | type | description |
|---|---|---|
| n | number |
colorFor(name: string) → string
A group's colour, from the group's own name. Two captures with a group added between them show every other group in the colour it already had.
| arg | type | description |
|---|---|---|
| name | string |
niceScale(v: number) → number
| arg | type | description |
|---|---|---|
| v | number |
pct(v: number) → string
| arg | type | description |
|---|---|---|
| v | number |
label(text: string, color: string?, size: number?, extra: any?) → void
`wrap` is a label's data rather than its looks, so it goes in props while everything else in `extra` is style.
| arg | type | description |
|---|---|---|
| text | string | |
| color | string? | |
| size | number? | |
| extra | any? |
num(text: string, width: number, color: string?, size: number?) → void
| arg | type | description |
|---|---|---|
| text | string | |
| width | number | |
| color | string? | |
| size | number? |
row(children: any, extra: any?) → void
| arg | type | description |
|---|---|---|
| children | any | |
| extra | any? |
header(text: string) → void
| arg | type | description |
|---|---|---|
| text | string |
focusBox(id: string, child: any, flex: number?) → void
Everything focusable is wrapped in a box carrying a two pixel border that is transparent until the focus is on it, so moving the focus never moves the layout.
| arg | type | description |
|---|---|---|
| id | string | |
| child | any | |
| flex | number? |
remember(entry: any) → void
| arg | type | description |
|---|---|---|
| entry | any |
button(text: string, cb: string, tone: string?) → void
| arg | type | description |
|---|---|---|
| text | string | |
| cb | string | |
| tone | string? |
smallButton(text: string, cb: string, tone: string?) → void
| arg | type | description |
|---|---|---|
| text | string | |
| cb | string | |
| tone | string? |
sliderRow(name: string, cb: string, value: number, min: number, max: number) → void
Every slider is the same width, so the three tracks share an x and the value pills the slider widget draws for itself line up under each other. The pill IS the value, so the label column carries the name alone.
| arg | type | description |
|---|---|---|
| name | string | |
| cb | string | |
| value | number | |
| min | number | |
| max | number |
textField(id: string, text: string, placeholder: string, width: number?) → void
| arg | type | description |
|---|---|---|
| id | string | |
| text | string | |
| placeholder | string | |
| width | number? |
barRow(name: string, value: number, scale: number, color: string, unit: string?, lead: any?, nameCol: number?) → void
A bar drawn to its own full scale, with that scale printed at the track's right end, so two bars of different heights are never read as one scale.
| arg | type | description |
|---|---|---|
| name | string | |
| value | number | |
| scale | number | |
| color | string | |
| unit | string? | |
| lead | any? | |
| nameCol | number? |
traceY(v: number, peak: number) → string
The trace is drawn on a square root scale so a group at 4 Hz stays visible beside one at 130 Hz. Both gridlines carry the rate they stand for, and the section header names the scale, so nothing is read off the height alone.
| arg | type | description |
|---|---|---|
| v | number | |
| peak | number |
tracePlot(height: number) → void
| arg | type | description |
|---|---|---|
| height | number |
rasterPlot(name: string) → void
One row per neuron of a small group, a tick wherever that neuron was active at the sample.
| arg | type | description |
|---|---|---|
| name | string |
quietSplit(groups: any) → void
| arg | type | description |
|---|---|---|
| groups | any |
readoutBlock(children: any, groups: any) → void
| arg | type | description |
|---|---|---|
| children | any | |
| groups | any |
hotClassBlock(children: any, comp: any) → void
| arg | type | description |
|---|---|---|
| children | any | |
| comp | any |
driveBlock(children: any, comp: any) → void
| arg | type | description |
|---|---|---|
| children | any | |
| comp | any |
neuronBlock(children: any) → void
| arg | type | description |
|---|---|---|
| children | any |
flyBlock(children: any) → void
| arg | type | description |
|---|---|---|
| children | any |
legendBlock(children: any) → void
| arg | type | description |
|---|---|---|
| children | any |
buildTree( ) → void
render( ) → void
pruneGroup(name: string) → void
| arg | type | description |
|---|---|---|
| name | string |
sampleRaster(comp: any, name: string, size: number) → void
| arg | type | description |
|---|---|---|
| comp | any | |
| name | string | |
| size | number |
sample(dt: number) → void
| arg | type | description |
|---|---|---|
| dt | number |
focusIndex( ) → number
moveFocus(step: number) → void
| arg | type | description |
|---|---|---|
| step | number |
identifyAt(x: number, y: number) → void
| arg | type | description |
|---|---|---|
| x | number | |
| y | number |
identifyFromPointer( ) → void
tick(dt: number) → void
| arg | type | description |
|---|---|---|
| dt | number |
awake( ) → void
update(dt: ?) → void
| arg | type | description |
|---|---|---|
| dt | ? |
editorUpdate(dt: ?) → void
| arg | type | description |
|---|---|---|
| dt | ? |
onDestroy( ) → void
withSelection(fn: ?) → void
| arg | type | description |
|---|---|---|
| fn | ? |
onCallback(id: ?, data: ?) → void
| arg | type | description |
|---|---|---|
| id | ? | |
| data | ? |
parseSelection(text: string) →
Turn a selection expression into a `brain` selection: `type:A,B`, `prefix:JO-`, `pattern:^LB%d`, `class:Kenyon_Cell,MBON`, `super:descending_neuron`, `side:L`, `excitatory:true`, `indices:0,1`, `limit:100`, space separated. The grammar itself lives in `selection.module`; this is the bench's way in to it.
| arg | type | description |
|---|---|---|
| text | string | The expression. |
examples
lab:parseSelection("type:MN9 side:L")The lab bench for a connectome running as a spiking network: a window laid out from the live screen that shows the network's state, its knobs, every watched group as a bar, a trace and a raster, the hot cell classes and the live drives, and takes a selection expression to stimulate, silence, restore, watch or count any set of neurons by the dataset's own vocabulary. Reachable with a pointer, a keyboard, a gamepad or a finger.Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Showing up to 3 levels deep. Open a part to see what it holds further down.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.