Skip to content

Dataset

Constructors

Each of these returns a ready-to-use Dataset.

FlyWire (FAFB).

FlyWire

FlyWire(release: str = 'public', **kwargs)

FlyWire, the whole-brain FAFB reconstruction.

fw = connecto.FlyWire() # public release, mat 783 fw = connecto.FlyWire("production") # live, needs permissions

Source code in connecto/datasets/flywire.py
def FlyWire(release: str = "public", **kwargs):
    """FlyWire, the whole-brain FAFB reconstruction.

        fw = connecto.FlyWire()                  # public release, mat 783
        fw = connecto.FlyWire("production")      # live, needs permissions
    """
    from ..backends import build

    spec = {"public": FLYWIRE, "production": FLYWIRE_PRODUCTION}.get(release)
    if spec is None:
        raise ValueError(f"`release` must be 'public' or 'production', got {release!r}.")
    return build(spec, **kwargs)

BANC - the Brain And Nerve Cord dataset.

BANC is the reason connecto treats backend and dataset as orthogonal: it is served by CAVE (brain_and_nerve_cord_public, materialization 888) and by neuPrint (banc:v888) - the same snapshot, two backends. So::

connecto.BANC()                 # neuPrint, the default
connecto.BANC(backend="cave")   # CAVE - for the chunkedgraph and the L2 cache

which also gives us a real test that the normalisation is genuine rather than aspirational: both should return the same edges.

BANC

BANC(**kwargs)

BANC. Defaults to neuPrint; pass backend="cave" for the CAVE copy.

Source code in connecto/datasets/banc.py
def BANC(**kwargs):
    """BANC. Defaults to neuPrint; pass ``backend="cave"`` for the CAVE copy."""
    from ..backends import build

    return build(BANC_SPEC, **kwargs)

FANC - the Female Adult Nerve Cord.

The female counterpart to MANC, but a CAVE dataset rather than a neuPrint one: an editable segmentation with a chunkedgraph, so root IDs move and version="auto" earns its keep.

Two things about FANC are not like the other CAVE datasets, and both are handled in the spec rather than in the backend:

  1. Its synapse table calls the confidence score score, not cleft_score. Same concept, different name - hence score_column.
  2. Its annotations are long: neuron_information is one row per (neuron, tag), with the category in tag2 and the value in tag. So a motor neuron carries tag2="primary class", tag="motor neuron". Pivoting it wide turns each category into a column, which is what the rest of connecto expects.

FANC is not public. It needs the FANC_edit group, so an unprivileged token gets a 403 - which connecto reports as a permission problem, not a bad token.

FANC

FANC(**kwargs)

FANC, the female adult nerve cord. Needs the FANC_edit group.

Source code in connecto/datasets/fanc.py
def FANC(**kwargs):
    """FANC, the female adult nerve cord. Needs the ``FANC_edit`` group."""
    from ..backends import build

    return build(FANC_SPEC, **kwargs)

MICrONS - mouse visual cortex.

MICrONS is the forcing function that keeps connecto from quietly becoming a fly library. It has no side, no fly-style super_class, and its cell types are spread across several tables produced by different methods (a transformer model, an SVM on nuclei, a hand-drawn column) rather than living in one canonical column.

So it ships with fields={} beyond the ID: annotations come back raw, with every native column present and no invented type. That is the honest default. If you want a type, say which table's opinion you want::

mic = connecto.MICrONS(annotations="mtypes")
mic.annotations.get(fields={"type": ("cell_type",)})

MICrONS

MICrONS(**kwargs)

MICrONS minnie65, mouse visual cortex.

Source code in connecto/datasets/microns.py
def MICrONS(**kwargs):
    """MICrONS minnie65, mouse visual cortex."""
    from ..backends import build

    return build(MICRONS_SPEC, **kwargs)

Aedes - the mosquito brain (Wei-Chung Lee lab).

The CAVE datastack is bare: a synapse table, a nucleus table, and no annotation table at all - no column that means "type" or "side". The project keeps its cell typing elsewhere, in FlyTable (the lab's SeaTable database): the aedes_main table of the aedes base. So connecto reads annotations from there rather than from CAVE:

aedes.connectivity.edges(root_ids)   # from CAVE
aedes.ids("class:KC")                # from FlyTable

FlyTable is lab-internal - it needs a SEATABLE_TOKEN on top of CAVE access, and there is no public alternative - so the source is public=False. Because it is the only source, annotations="auto" falls back to it (see DatasetSpec.annotation_source); a caller without the token gets a clear missing-token error, not a silently empty frame.

Aedes

Aedes(**kwargs)

The Aedes aegypti mosquito brain, via CAVE.

Source code in connecto/datasets/aedes.py
def Aedes(**kwargs):
    """The Aedes aegypti mosquito brain, via CAVE."""
    from ..backends import build

    return build(AEDES_SPEC, **kwargs)

The neuPrint datasets: hemibrain, maleCNS, MANC, fish2.

No optic-lobe. It was a partial release - the optic lobes of the same specimen that malecns now covers whole - so it was two names for one dataset, and the narrower one could only ever give you fewer neurons and a different set of body IDs for them. Use malecns and select the optic-lobe ROIs.

Datasets connecto has never heard of.

Adding a datastack must not require writing a class, or opening a PR:

ca3  = connecto.CAVE("zheng_ca3", fields={"type": ("cell_type",)})
wasp = connecto.NeuPrint("wasp3:v0.8", server="neuprint-pre.janelia.org")

The spec is probed from the server. A probed spec claims fewer capabilities and has no fields, so ds.ids("DA1_lPN") raises a clear error rather than guessing which column means "type" - curated specs for the datasets you care about, working defaults for everything else.

probe_cave

probe_cave(datastack: str, **overrides) -> DatasetSpec

Build a DatasetSpec by asking the CAVE server what it has.

Source code in connecto/datasets/generic.py
def probe_cave(datastack: str, **overrides) -> DatasetSpec:
    """Build a DatasetSpec by asking the CAVE server what it has."""
    from caveclient import CAVEclient

    from ..auth import get_token

    client = CAVEclient(datastack, auth_token=get_token("cave").token)
    info = client.info.get_datastack_info()

    voxel = (
        float(info.get("viewer_resolution_x") or 1),
        float(info.get("viewer_resolution_y") or 1),
        float(info.get("viewer_resolution_z") or 1),
    )

    tables = set(client.materialize.get_tables())

    synapse_table = info.get("synapse_table")
    nucleus = next((t for t in sorted(tables) if _NUCLEUS_RE.search(t)), None)
    proofread = next((t for t in sorted(tables) if _PROOFREAD_RE.search(t)), None)
    ann_tables = [t for t in sorted(tables) if _ANNOTATION_RE.search(t)]

    caps = {Cap.SEGMENTATION, Cap.CHUNKEDGRAPH, Cap.MESHES, Cap.NEUROGLANCER}
    if synapse_table:
        caps |= {Cap.CONNECTIVITY, Cap.SYNAPSES}
    if ann_tables:
        caps.add(Cap.ANNOTATIONS)
    if nucleus:
        caps.add(Cap.SOMAS)
    if proofread:
        caps.add(Cap.PROOFREADING)
    try:
        if client.l2cache.has_cache():
            caps |= {Cap.L2CACHE, Cap.SKELETONS}
    except Exception:  # noqa: BLE001 - absence of an L2 cache is not an error
        pass

    logger.info(
        "Probed %s: synapses=%s nucleus=%s proofreading=%s annotations=%s caps=%s",
        datastack, synapse_table, nucleus, proofread, ann_tables,
        sorted(str(c) for c in caps),
    )

    spec = DatasetSpec(
        name=datastack,
        label=info.get("description") or datastack,
        backends=(
            BackendSpec(
                "cave", datastack,
                synapse_table=synapse_table,
                nucleus_table=nucleus,
                proofreading_table=proofread,
            ),
        ),
        annotation_sources=tuple(
            AnnotationSource(t, "cave_table", t, id_column="pt_root_id")
            for t in ann_tables
        ),
        voxel_size=voxel,
        segmentation_source=info.get("segmentation_source"),
        capabilities=frozenset(caps),
    )
    return spec.evolve(**overrides) if overrides else spec

probe_neuprint

probe_neuprint(dataset: str, server: str = 'neuprint.janelia.org', **overrides) -> DatasetSpec

Build a DatasetSpec by asking a neuPrint server what it has.

Source code in connecto/datasets/generic.py
def probe_neuprint(dataset: str, server: str = "neuprint.janelia.org", **overrides) -> DatasetSpec:
    """Build a DatasetSpec by asking a neuPrint server what it has."""
    from neuprint import Client

    from ..auth import get_token
    from ..backends.neuprint.versions import available

    name = dataset.split(":")[0]
    token = get_token("neuprint", server=server).token

    versions = available(server, name, token)
    full = dataset if dataset in versions else versions[-1]

    client = Client(server, dataset=full, token=token)
    meta = client.meta
    voxel = tuple(meta.get("voxelSize") or (1, 1, 1))

    caps = {
        Cap.ANNOTATIONS, Cap.CONNECTIVITY, Cap.SYNAPSES, Cap.SYNAPSE_SCORES,
        Cap.ROI_CONN, Cap.ROIS, Cap.SKELETONS, Cap.SOMAS,
    }
    if meta.get("neuroglancerMeta"):
        caps |= {Cap.MESHES, Cap.NEUROGLANCER}

    logger.info("Probed %s/%s: voxel=%s rois=%s", server, full, voxel, len(client.primary_rois))

    spec = DatasetSpec(
        name=name,
        label=name,
        backends=(BackendSpec("neuprint", f"{server}/{full}"),),
        annotation_sources=(AnnotationSource("neuprint", "neuprint", id_column="bodyId"),),
        voxel_size=voxel,
        capabilities=frozenset(caps),
    )
    return spec.evolve(**overrides) if overrides else spec

CAVE

CAVE(datastack: str, *, version=None, annotations='auto', **overrides)

Any CAVE datastack, without writing a class.

Spec fields (fields, side_map, capabilities, ...) can be passed as keyword arguments to refine what was probed.

Source code in connecto/datasets/generic.py
def CAVE(datastack: str, *, version=None, annotations="auto", **overrides):
    """Any CAVE datastack, without writing a class.

    Spec fields (`fields`, `side_map`, `capabilities`, ...) can be passed as
    keyword arguments to refine what was probed.
    """
    from ..backends import build

    ds_kwargs = {"version": version, "annotations": annotations}
    spec = probe_cave(datastack, **overrides)
    return build(spec, **ds_kwargs)

NeuPrint

NeuPrint(dataset: str, *, server: str = 'neuprint.janelia.org', version=None, annotations='auto', **overrides)

Any neuPrint dataset, without writing a class.

Source code in connecto/datasets/generic.py
def NeuPrint(dataset: str, *, server: str = "neuprint.janelia.org", version=None,
             annotations="auto", **overrides):
    """Any neuPrint dataset, without writing a class."""
    from ..backends import build

    spec = probe_neuprint(dataset, server=server, **overrides)
    return build(spec, version=version, annotations=annotations)

The handle

Dataset

Dataset(spec: DatasetSpec, *, backend: str | None = None, version=None, annotations: str | None = 'auto', fields: dict | None = None, edges=None)

Bases: ABC

A connectome you can query.

Datasets are immutable. There is no self.neurons, no edges_, no use_types: a dataset is a handle, and the selection lives in the caller. Re-pinning a version returns a new object (:meth:at) rather than mutating - a mutable version setter plus a memoised annotation frame is exactly how you end up joining annotations from one materialization to edges from another.

Source code in connecto/core/dataset.py
def __init__(
    self,
    spec: DatasetSpec,
    *,
    backend: str | None = None,
    version=None,
    annotations: str | None = "auto",
    fields: dict | None = None,
    edges=None,
):
    if fields:
        spec = spec.evolve(fields=dict(spec.fields) | dict(fields))

    self.spec = spec
    self._backend = spec.backend(backend)
    self._annotation_source = spec.annotation_source(annotations)
    self._edge_source = edges
    self._namespaces: dict = {}
    self._version_request = (
        version if version is not None else self._backend.default_version
    )
    self._resolved_version: Version | None = None

capabilities property

capabilities: frozenset[Cap]

What this dataset can do through the backend it is bound to.

Not spec.capabilities - that is what the data has, which is a different and, for a live handle, useless claim. FlyWire has a chunkedgraph; a FlyWire handle on the neuPrint backend cannot reach it, so it does not claim it.

publications property

publications: tuple

The papers to cite for this dataset.

links: dict

Landing pages and data repositories, by name.

public property

public: bool

False if you need permission that a fresh token will not give you.

access property

access: str

What you need in order to read this dataset. Empty if it is public.

version property

version: Version

The version this dataset is pinned to (resolved on first access).

cite

cite() -> str

Who to credit for this dataset.

connecto knows exactly which dataset produced the numbers in your figure, which puts it in an unusually good position to tell you whose work it was::

print(cn.Hemibrain().cite())
Source code in connecto/core/dataset.py
def cite(self) -> str:
    """Who to credit for this dataset.

    connecto knows exactly which dataset produced the numbers in your figure,
    which puts it in an unusually good position to tell you whose work it was::

        print(cn.Hemibrain().cite())
    """
    lines = [f"{self.label} ({self.spec.species})".strip()]
    if self.description:
        lines += ["", self.description]
    if self.publications:
        lines += ["", "Please cite:"]
        lines += [f"  {p}" for p in self.publications]
    if self.links:
        lines += ["", "See also:"]
        lines += [f"  {k:<10} {v}" for k, v in self.links.items()]
    if not self.public:
        lines += ["", f"Access: {self.access}"]
    return "\n".join(lines)

versions

versions() -> list

All versions available for this dataset.

Source code in connecto/core/dataset.py
def versions(self) -> list:
    """All versions available for this dataset."""
    return self._list_versions()

at

at(version) -> Dataset

A new handle onto the same dataset, pinned to a different version.

Source code in connecto/core/dataset.py
def at(self, version) -> Dataset:
    """A new handle onto the same dataset, pinned to a different version."""
    clone = type(self).__new__(type(self))
    clone.__dict__.update(self.__dict__)
    clone._namespaces = {}
    clone._version_request = version
    clone._resolved_version = None
    return clone

find_version

find_version(x, *, raise_missing: bool = True) -> Version

The newest version in which all the given IDs are valid.

On CAVE this scans materializations newest-first, because root IDs change as neurons are edited and a set of IDs is only jointly valid in some of them. On neuPrint body IDs are immutable, so this is an identity - which is the point: version="auto" is correct code on both backends.

Source code in connecto/core/dataset.py
def find_version(self, x, *, raise_missing: bool = True) -> Version:
    """The newest version in which *all* the given IDs are valid.

    On CAVE this scans materializations newest-first, because root IDs change
    as neurons are edited and a set of IDs is only jointly valid in some of
    them. On neuPrint body IDs are immutable, so this is an identity - which
    is the point: ``version="auto"`` is correct code on both backends.
    """
    ids = np.asarray(x, dtype="int64").ravel()
    return self._find_version(ids, raise_missing=raise_missing)

ids

ids(x=None, *, side=None, regex='auto', version=None) -> ndarray

Resolve any neuron query to an array of int64 IDs.

ds.ids(720575940621039145) ds.ids("DA1_lPN") ds.ids("/AOTU00.*") ds.ids("cell_class:ALPN", side="left")

Source code in connecto/core/dataset.py
def ids(self, x=None, *, side=None, regex="auto", version=None) -> np.ndarray:
    """Resolve any neuron query to an array of int64 IDs.

        ds.ids(720575940621039145)   ds.ids("DA1_lPN")
        ds.ids("/AOTU00.*")          ds.ids("cell_class:ALPN", side="left")
    """
    return parse_ids(x, self, side=side, regex=regex, version=version)

Backends

CAVEDataset

CAVEDataset(spec: DatasetSpec, *, backend: str | None = None, version=None, annotations: str | None = 'auto', fields: dict | None = None, edges=None)

Bases: Dataset

A dataset served by a CAVE datastack.

Source code in connecto/core/dataset.py
def __init__(
    self,
    spec: DatasetSpec,
    *,
    backend: str | None = None,
    version=None,
    annotations: str | None = "auto",
    fields: dict | None = None,
    edges=None,
):
    if fields:
        spec = spec.evolve(fields=dict(spec.fields) | dict(fields))

    self.spec = spec
    self._backend = spec.backend(backend)
    self._annotation_source = spec.annotation_source(annotations)
    self._edge_source = edges
    self._namespaces: dict = {}
    self._version_request = (
        version if version is not None else self._backend.default_version
    )
    self._resolved_version: Version | None = None

NeuPrintDataset

NeuPrintDataset(spec: DatasetSpec, *, backend: str | None = None, version=None, annotations: str | None = 'auto', fields: dict | None = None, edges=None)

Bases: Dataset

A dataset served by a neuPrint server.

Source code in connecto/core/dataset.py
def __init__(
    self,
    spec: DatasetSpec,
    *,
    backend: str | None = None,
    version=None,
    annotations: str | None = "auto",
    fields: dict | None = None,
    edges=None,
):
    if fields:
        spec = spec.evolve(fields=dict(spec.fields) | dict(fields))

    self.spec = spec
    self._backend = spec.backend(backend)
    self._annotation_source = spec.annotation_source(annotations)
    self._edge_source = edges
    self._namespaces: dict = {}
    self._version_request = (
        version if version is not None else self._backend.default_version
    )
    self._resolved_version: Version | None = None

Versions

Version dataclass

Version(value: int | str, backend: str, timestamp: datetime | None = None, expires: datetime | None = None)

A resolved dataset version.