Multi-area V1-V4 viewer

Realized EdgeList only — no simulation re-run, no kernel change (Δscience=0). Hover neurons for layer / E/I / phenotype / H / degree / position. Toggle edges by category via checkboxes + legend. Standalone HTML — no server.

N=400 · edges=80,427 · layers=L1, L2/3, L4, L5, L6 · cell types=E, PV, SST, VIP · phenotype distinct=20 · H ownership=no H (equilibrium 1.0, HDP disabled)

Configured → Realized (EdgeList is truth)

Left = what was requested in cfg.metadata (connectivity / circuit / compilation). Right = what model.params["edge_list"] materialized — the only place dynamics reads.

AspectConfigured specRealized EdgeList
N neurons400
Edgesspec: see configured 80,427 (realized EdgeList)
Mean in-degree201.1
Mean out-degree201.1
Weight0.35 (configured within_gain)mean 0.005973 σ 0.01142 min -0.0175 max 0.09984
Delayall zero (instantaneous) unique steps [0]
τ per edge[2.0, 5.0]
CategoriesE→E 45,323 · E→I 15,204 · I→E 15,000 · I→I 4,900
FF / FB / localFF 365 · FB 462 · local 79,600 (hierarchy ['V1', 'V4'])
Layers → counts{"L1": 80, "L2/3": 80, "L4": 80, "L5": 80, "L6": 80}
Cell-type → counts{"E": 300, "PV": 40, "SST": 30, "VIP": 30} phenotype distinct 20
Configured JSON (cfg.metadata slice)
{
  "connectivity": {
    "within_area": "all_to_all_uniform_random",
    "within_gain": 0.35
  }
}

Edge sampling cap for display: 600 per category, 2400 total. Histograms sampled from up to 80427 edges with deterministic seed.

Edge toggles — E→E / E→I / I→E / I→I / FF / FB

FF = cross-area low→high in hierarchy ['V1', 'V4']; FB = high→low. Local = same-area (79,600 edges) not toggled separately — it is inside the E→E etc. categories. For single-area columns FF/FB are zero by construction.

3D column — layers · E/I class · position · phenotype · H ownership · degree (hover)

Rotate/drag to inspect depth (z). Layer colors via legend — click legend entries to isolate a layer. Neuron symbols: E circle, I diamond (same hue per layer). Hover shows H, in/out-degree, phenotype, position.

Weight stats (realized)

Mean 0.005973 σ 0.01142 · by category: E→E 0.01155 · E→I 0.01147 · I→E -0.01093 · I→I -0.01091

Delay stats (steps)

All delays zero — instantaneous kernel · unique steps [0]

Degree stats

Mean in 201.1 max 215 · mean out 201.1 max 225

Layer × E/I degree (mean)

Phenotype heatmap — layer × cell type counts

Phenotype & H ownership

Phenotype (layer/cell_type) distinct20 · {"L1/E": 60, "L1/PV": 8, "L1/SST": 6, "L1/VIP": 6, "L2/3/E": 60, "L2/3/PV": 8, "L2/3/SST": 6, "L2/3/VIP": 6, "L4/E": 60, "L4/PV": 8, "L4/SST": 6, "L4/VIP": 6, "L5/E": 60, "L5/PV": 8, "L5/SST": 6, "L5/VIP": 6, "L6/E": 60, "L6/PV": 8, "L6/SST": 6, "L6/VIP": 6}
Cell-type counts{"E": 300, "PV": 40, "SST": 30, "VIP": 30} — E/I split: E 300 / I 100
Layer counts{"L1": 80, "L2/3": 80, "L4": 80, "L5": 80, "L6": 80}
H ownership{'present': False, 'enabled': False, 'mean': None, 'note': ''} — equilibrium (model.params has no hdp_initial_H)

How to verify

import jaxfne as jtfne
from jaxfne.vis.column_viewer import render_column_viewer, collect_column_viewer_data
cfg = jtfne.build_laminar_column(n=1000, ei_profile="canonical")
cfg = cfg.set_emitter("izhikevich","cortical_eig").probes(["spikes"],n_contacts=16).field(domain="laminar_column", conductivity="proxy", boundary="mean_zero_neumann")
model = jtfne.construct(cfg)
data = collect_column_viewer_data(model)  # no simulation, reads realized EdgeList
render_column_viewer(model, output_path="artifacts/column_viewer_canonical_1000n.html")
# Check: data["realized"]["n_edges"] == int(model.params["edge_list"].n_edges)
# and edge_category_counts sum to n_edges.

No kernel or sampler was changed to build this viewer. The HTML is self-contained (Plotly.js via CDN) — open it in a browser, no Python server needed. Re-render with any Model (laminar, multi-area, neuronal tensor, HDP) without re-running a simulation.