crantpy.queries.nested_connectivity_matrices module#

class crantpy.queries.nested_connectivity_matrices.DirectedNestedMatrix(matrix, source_neurons, target_neurons, source_type_boundaries=None, target_type_boundaries=None, source_neuron_to_type=None, target_neuron_to_type=None)[source]#

Bases: object

A rectangular nested connectivity matrix with independent axes.

Rows are presynaptic/source neurons, columns postsynaptic/target. Unlike NestedMatrix the matrix may be rectangular and the two cell type sets may differ.

Constructors take source_types/source_ids (and the target_ pair) to select an axis; the resolved order is read back from .source_neurons/.target_neurons. Type and ID selectors on one axis are unioned; leaving both of them None keeps every available neuron on that axis.

Per axis, <axis>_neurons is <axis>_typed_neurons + <axis>_untyped_neurons, and only the typed part is covered by <axis>_type_boundaries and <axis>_neuron_to_type.

Parameters:
  • matrix (pd.DataFrame)

  • source_neurons (Iterable[Any])

  • target_neurons (Iterable[Any])

  • source_type_boundaries (Mapping[Any, tuple[int, int]] | None)

  • target_type_boundaries (Mapping[Any, tuple[int, int]] | None)

  • source_neuron_to_type (Mapping[Any, Any] | None)

  • target_neuron_to_type (Mapping[Any, Any] | None)

by(*, rank=None, extract=None, key=None, na='last')#

Sort a cell type’s neurons by annotation column(s).

A string at the order layer is only a named rule ("id", "annotation", "label", "size"). Column names live here.

Parameters:
  • columns (str) – Annotation columns to read, in priority order. The first column that yields a usable value wins.

  • rank (sequence of str, optional) – Explicit label order. Without extract, the leftmost rank label that appears in the cell is used, so "EPG/PEG_R1" and "Ξ”7_L8R1R9" both rank without a regex.

  • extract (str or compiled pattern, optional) – Regex whose first group is the label. A plain string is compiled.

  • key (callable, optional) – value -> sort key when rank is omitted. Defaults to a natural sort, so "ER_g2" precedes "ER_g10".

  • na ({"last", "first", "raise"}, default "last") – What an unrankable or null value costs. "raise" errors; the others put those neurons after or before the ranked ones, keeping annotation row order inside that group.

Return type:

By

Examples

>>> NestedMatrix.by("cell_instance")
>>> NestedMatrix.by("cell_instance", "cell_subtype", rank=EB_RING)
>>> NestedMatrix.by("cell_instance", extract=r"([LR]\d+)", rank=PB)
classmethod from_connectivity(connections_df, neuron_annotations, source_types=None, target_types=None, source_ids=None, target_ids=None, cell_type_column='cell_type', neuron_id_column='root_id', order=None, source_order=None, target_order=None, annotation_scope='annotated_only')[source]#

Create a rectangular directed nested matrix from connectivity data.

Parameters:
  • connections_df (pd.DataFrame) – Any format accepted by NestedMatrix.from_connectivity().

  • neuron_annotations (pd.DataFrame) – Neuron ID and cell type columns.

  • source_types (selector, optional) – Keep only these cell types on the row / column axis.

  • target_types (selector, optional) – Keep only these cell types on the row / column axis.

  • source_ids (selector, optional) – Keep only these neuron IDs, unioned with the same axis’ type selector. Leaving both selectors for an axis None keeps every available neuron on it.

  • target_ids (selector, optional) – Keep only these neuron IDs, unioned with the same axis’ type selector. Leaving both selectors for an axis None keeps every available neuron on it.

  • cell_type_column (str) – Annotation column names.

  • neuron_id_column (str) – Annotation column names.

  • order (NestedMatrix.order, sequence or None, optional) – Shared axis order; a bare sequence is types-only shorthand.

  • source_order (optional) – Per-axis override of order.

  • target_order (optional) – Per-axis override of order.

  • annotation_scope ({"annotated_only", "all"}, default "annotated_only") – Which neurons to retain before axis selection.

Return type:

DirectedNestedMatrix

classmethod from_synapses(synapses_df, neuron_annotations, source_types=None, target_types=None, source_ids=None, target_ids=None, pre_col='pre_pt_root_id', post_col='post_pt_root_id', weight_mode='relative_outgoing', weight_column=None, normalization_scope='selected', cell_type_column='cell_type', neuron_id_column='root_id', order=None, source_order=None, target_order=None, annotation_scope='annotated_only')[source]#

Create a rectangular directed nested matrix from synapse rows.

Axis selection and ordering work as in from_connectivity().

normalization_scope="selected" (the default) normalizes relative weights after axis filtering; "all" normalizes by every partner first, then restricts to the selected axes.

Parameters:
Return type:

DirectedNestedMatrix

classmethod from_synapses_by_neuropil(synapses_df, neuron_annotations, neuropil_names=None, coordinates='nm', position_column='ctr_pt_position', source_types=None, target_types=None, source_ids=None, target_ids=None, pre_col='pre_pt_root_id', post_col='post_pt_root_id', weight_mode='relative_outgoing', weight_column=None, normalization_scope='selected', cell_type_column='cell_type', neuron_id_column='root_id', order=None, source_order=None, target_order=None, annotation_scope='annotated_only', include_other=True, voxel_offset=None)[source]#

Create one DirectedNestedMatrix per neuropil, by mesh containment.

Arguments match from_synapses() and apply independently inside each ROI. ROIs empty on either axis are skipped.

Parameters:
Return type:

NeuropilCollection

get_relative_weights(by_type=False)[source]#

Calculate row-normalized source-to-target weights.

Parameters:

by_type (bool)

Return type:

pandas.DataFrame

property matrix: pandas.DataFrame#

Read-only source-to-target neuron connectivity matrix.

property mean_type_matrix: pandas.DataFrame#

Mean source-to-target connectivity by source and target cell type.

order(default=None, within=None)#

Build a reusable neuron order for a nested matrix axis.

Nested call:

NestedMatrix.order(
    types=["ER2", "EPG/PEG", "delta7"],
    default="id",
    within={"EPG/PEG": NestedMatrix.by("cell_instance", rank=EB_RING)},
)

Builder:

NestedMatrix.order().types(["ER2", "EPG/PEG"]).default("id").within(
    "EPG/PEG", NestedMatrix.by("cell_instance", rank=EB_RING)
)

A bare sequence passed as order= to a matrix constructor is still types-only shorthand for NestedMatrix.order(types=...).

Parameters:
  • types (Any)

  • default (Any | None)

  • within (Any | None)

Return type:

MatrixOrder

plot(output_path=None, level='neuron', figsize=(16, 14), show_neuron_labels=False, vmin_percentile=0.0, vmax_percentile=100.0, min_neurons_for_plot=1, linewidth_scale=1.0)[source]#

Plot the rectangular directed connectivity matrix as a heatmap.

Parameters:
  • output_path (str | None)

  • level (Literal['neuron', 'type_mean', 'type_sum'])

  • figsize (tuple[int, int])

  • show_neuron_labels (bool)

  • vmin_percentile (float)

  • vmax_percentile (float)

  • min_neurons_for_plot (int)

  • linewidth_scale (float)

Return type:

tuple[Figure, Axes]

property source_neuron_to_type: Mapping[str, Any]#

Read-only mapping from source neuron ID to cell type.

property source_neurons: tuple[str, ...]#

Resolved row order (not a filter – select with source_types/source_ids).

property source_type_boundaries: Mapping[str, tuple[int, int]]#

Read-only mapping from source cell type to its row slice.

property source_typed_neurons: tuple[str, ...]#

Row neurons carrying a cell type.

property source_untyped_neurons: tuple[str, ...]#

Row neurons with no cell type, appended after the blocks.

property sum_type_matrix: pandas.DataFrame#

Sum source-to-target connectivity by source and target cell type.

property target_neuron_to_type: Mapping[str, Any]#

Read-only mapping from target neuron ID to cell type.

property target_neurons: tuple[str, ...]#

Resolved column order (not a filter – select with target_types/target_ids).

property target_type_boundaries: Mapping[str, tuple[int, int]]#

Read-only mapping from target cell type to its column slice.

property target_typed_neurons: tuple[str, ...]#

Column neurons carrying a cell type.

property target_untyped_neurons: tuple[str, ...]#

Column neurons with no cell type, appended after the blocks.

class crantpy.queries.nested_connectivity_matrices.NestedMatrix(matrix, type_boundaries, ordered_neurons, neuron_to_type)[source]#

Bases: object

A square connectivity matrix with neurons grouped into cell type blocks. ordered_neurons is typed_neurons + untyped_neurons, and only the typed prefix is covered by type_boundaries and neuron_to_type.

Parameters:
  • matrix (pd.DataFrame)

  • type_boundaries (Mapping[Any, tuple[int, int]])

  • ordered_neurons (Iterable[Any])

  • neuron_to_type (Mapping[Any, Any])

matrix#

Neuron-by-neuron connectivity, ordered by type.

Type:

pd.DataFrame

type_boundaries#

Cell type -> half-open (start, end) slice into ordered_neurons. Contiguous from 0, covering typed_neurons only.

Type:

Mapping[str, tuple[int, int]]

ordered_neurons#

Neuron IDs in matrix order.

Type:

tuple[str, …]

typed_neurons, untyped_neurons

The typed prefix and the untyped tail of ordered_neurons.

Type:

tuple[str, …]

neuron_to_type#

Neuron ID -> cell type, for typed_neurons only.

Type:

Mapping[str, Any]

Examples

>>> matrix = NestedMatrix.from_connectivity(
...     connections_df=adjacency_df,
...     neuron_annotations=annotations_df
... )
>>> type_matrix = matrix.sum_type_matrix
>>> matrix.plot(level="type_mean")
static by(*columns, rank=None, extract=None, key=None, na='last')#

Sort a cell type’s neurons by annotation column(s).

A string at the order layer is only a named rule ("id", "annotation", "label", "size"). Column names live here.

Parameters:
  • columns (str) – Annotation columns to read, in priority order. The first column that yields a usable value wins.

  • rank (sequence of str, optional) – Explicit label order. Without extract, the leftmost rank label that appears in the cell is used, so "EPG/PEG_R1" and "Ξ”7_L8R1R9" both rank without a regex.

  • extract (str or compiled pattern, optional) – Regex whose first group is the label. A plain string is compiled.

  • key (callable, optional) – value -> sort key when rank is omitted. Defaults to a natural sort, so "ER_g2" precedes "ER_g10".

  • na ({"last", "first", "raise"}, default "last") – What an unrankable or null value costs. "raise" errors; the others put those neurons after or before the ranked ones, keeping annotation row order inside that group.

Return type:

By

Examples

>>> NestedMatrix.by("cell_instance")
>>> NestedMatrix.by("cell_instance", "cell_subtype", rank=EB_RING)
>>> NestedMatrix.by("cell_instance", extract=r"([LR]\d+)", rank=PB)
classmethod from_connectivity(connections_df, neuron_annotations, cell_type_column='cell_type', neuron_id_column='root_id', order=None, annotation_scope='annotated_only')[source]#

Create a NestedMatrix from an adjacency matrix or edge list.

Accepts the output of cp.get_connectivity().

Parameters:
  • connections_df (pd.DataFrame) –

    Connectivity data in one of the following formats: - Adjacency matrix (index and columns are neuron IDs) - Edge list with columns [β€˜type.from’, β€˜type.to’, β€˜weight’] - Edge list with columns [β€˜pre’, β€˜post’, β€˜weight’] - Edge list with columns [β€˜source’, β€˜target’, β€˜weight’] or [β€˜source’, β€˜target’, β€˜n_syn’]

    where each row is already aggregated to a unique source-target pair, such as the output of cp.get_connectivity()

  • neuron_annotations (pd.DataFrame) – Neuron annotations; needs at least the ID and cell type columns.

  • cell_type_column (str) – Annotation column names.

  • neuron_id_column (str) – Annotation column names.

  • order (NestedMatrix.order, sequence or None, optional) – How to order cell type blocks and the neurons inside them. Build one with NestedMatrix.order(...) or the chained builder; a bare sequence is types-only shorthand.

  • annotation_scope ({"annotated_only", "all"}, default "annotated_only") – "annotated_only" keeps only annotated neurons; "all" keeps every neuron, appending the untyped ones after the typed blocks.

Return type:

NestedMatrix

Examples

>>> adjacency = pd.DataFrame({
...     1: [0, 10, 0], 2: [5, 0, 15], 3: [0, 20, 0]
... }, index=[1, 2, 3])
>>> annotations = pd.DataFrame({
...     'root_id': [1, 2, 3],
...     'cell_type': ['ER', 'ER', 'Pbt']
... })
>>> matrix = NestedMatrix.from_connectivity(adjacency, annotations)
classmethod from_synapses(synapses_df, neuron_annotations, pre_col='pre_pt_root_id', post_col='post_pt_root_id', weight_mode='relative_outgoing', weight_column=None, cell_type_column='cell_type', neuron_id_column='root_id', order=None, annotation_scope='annotated_only')[source]#

Create a NestedMatrix from a synapse dataframe.

Returns one matrix over all supplied synapses. For ROI-specific output, pre-filter synapses_df or use from_synapses_by_neuropil().

Parameters:
  • synapses_df (pd.DataFrame) – Synapse rows, with pre- and postsynaptic ID columns.

  • neuron_annotations (pd.DataFrame) – Neuron annotations; needs at least the ID and cell type columns.

  • pre_col (str) – Pre- and postsynaptic ID columns in synapses_df.

  • post_col (str) – Pre- and postsynaptic ID columns in synapses_df.

  • weight_mode ({"relative_outgoing", "relative_incoming", "count", "column"}, default "relative_outgoing") – Edge weights per pre/post pair: raw synapse "count", that count normalized so each row ("relative_outgoing") or column ("relative_incoming") sums to 1, or the sum of weight_column ("column").

  • weight_column (str | None, optional) – Column to sum. Required for weight_mode="column", rejected otherwise.

  • cell_type_column (str) – Annotation column names.

  • neuron_id_column (str) – Annotation column names.

  • order (NestedMatrix.order, sequence or None, optional) – How to order cell type blocks and the neurons inside them. Build one with NestedMatrix.order(...) or the chained builder; a bare sequence is types-only shorthand.

  • annotation_scope ({"annotated_only", "all"}, default "annotated_only") – "annotated_only" keeps only rows whose pre and post neurons are both annotated; "all" keeps every row and appends the untyped neurons after the typed blocks.

Return type:

NestedMatrix

Examples

>>> synapses = pd.DataFrame({
...     'pre_pt_root_id': [1, 1, 2],
...     'post_pt_root_id': [3, 4, 3],
...     'Weight': [10, 20, 15]
... })
>>> annotations = pd.DataFrame({
...     'root_id': [1, 2, 3, 4],
...     'cell_type': ['KC', 'KC', 'MB', 'MB']
... })
>>> matrix = NestedMatrix.from_synapses(
...     synapses,
...     annotations,
...     weight_mode="column",
...     weight_column="Weight",
... )
>>> relative = NestedMatrix.from_synapses(
...     synapses,
...     annotations,
...     weight_mode="relative_outgoing",
... )
>>> # For neuropil ROI-specific matrices, use:
>>> # NestedMatrix.from_synapses_by_neuropil(...)
classmethod from_synapses_by_neuropil(synapses_df, neuron_annotations, neuropil_names=None, coordinates='nm', position_column='ctr_pt_position', pre_col='pre_pt_root_id', post_col='post_pt_root_id', weight_mode='relative_outgoing', weight_column=None, cell_type_column='cell_type', neuron_id_column='root_id', order=None, annotation_scope='annotated_only', include_other=True, voxel_offset=None)[source]#

Create NestedMatrix instances per neuropil using mesh containment.

Assigns each synapse to ROIs by testing its coordinates against the neuropil meshes, then builds one matrix per ROI that holds synapses. All other arguments match from_synapses() and apply independently inside each ROI.

Parameters:
  • synapses_df (pd.DataFrame) – Synapse rows, with the position and pre/post ID columns.

  • neuron_annotations (pd.DataFrame) – Neuron annotations; needs at least the ID and cell type columns.

  • neuropil_names (list[str] | None, optional) – Mesh names from NEUROPIL_MESH_DICT; None uses all of them.

  • coordinates ({"nm", "pixels"}, default "nm") – Units of position_column. Meshes are in nm; "pixels" is converted using the configured scale factors.

  • position_column (str, default "ctr_pt_position") – Column holding [x, y, z] coordinates.

  • pre_col (str) – Pre- and postsynaptic ID columns in synapses_df.

  • post_col (str) – Pre- and postsynaptic ID columns in synapses_df.

  • weight_mode (Literal['relative_outgoing', 'relative_incoming', 'count', 'column']) – As in from_synapses(), applied within each ROI subset.

  • weight_column (str | None) – As in from_synapses(), applied within each ROI subset.

  • cell_type_column (str) – Annotation column names.

  • neuron_id_column (str) – Annotation column names.

  • order (NestedMatrix.order, sequence or None, optional) – How to order cell type blocks and the neurons inside them. Build one with NestedMatrix.order(...) or the chained builder; a bare sequence is types-only shorthand.

  • annotation_scope ({"annotated_only", "all"}, default "annotated_only") – As in from_synapses(), applied before ROI assignment.

  • include_other (bool, default True) – Collect synapses outside every mesh under an "other" key.

  • voxel_offset (tuple[float, float, float] | None, optional) – Added to pixel coordinates before nm conversion, to align them with the meshes. Only used when coordinates="pixels".

Returns:

Dict-like, mapping ROI name (plus "other") to a NestedMatrix. Supports collection.plot(name, ...) and attribute access.

Return type:

NeuropilCollection

Raises:

ValueError – On an unknown neuropil name or coordinates value.

Examples

>>> matrices = NestedMatrix.from_synapses_by_neuropil(
...     synapses_df=synapses,
...     neuron_annotations=annotations,
...     neuropil_names=["antennal_lobe_left", "mushroom_body_pedunculus_and_lobes_left"],
...     coordinates="nm",
... )
>>> for name, mat in matrices.items():
...     print(name, mat.sum_type_matrix.shape)
get_relative_weights(by_type=False)[source]#

Row-normalized weights: each source’s share of output per target.

Each row is divided by its own sum, so rows sum to 1.0 – except a row whose weights sum to zero, which is left unchanged. That covers rows with no output, and also rows whose positive and negative weights cancel. Set by_type to compute this at the cell type level instead of the neuron level.

Parameters:

by_type (bool)

Return type:

pandas.DataFrame

property matrix: pandas.DataFrame#

Read-only neuron-to-neuron connectivity matrix.

property mean_type_matrix: pandas.DataFrame#

Mean weight across each type-pair block (read-only view).

Zero entries count towards the mean, so large cell types don’t dominate just by having more neurons.

property neuron_to_type: Mapping[str, Any]#

Read-only neuron ID -> cell type, for typed_neurons only.

static order(types='label', default=None, within=None)#

Build a reusable neuron order for a nested matrix axis.

Nested call:

NestedMatrix.order(
    types=["ER2", "EPG/PEG", "delta7"],
    default="id",
    within={"EPG/PEG": NestedMatrix.by("cell_instance", rank=EB_RING)},
)

Builder:

NestedMatrix.order().types(["ER2", "EPG/PEG"]).default("id").within(
    "EPG/PEG", NestedMatrix.by("cell_instance", rank=EB_RING)
)

A bare sequence passed as order= to a matrix constructor is still types-only shorthand for NestedMatrix.order(types=...).

Parameters:
  • types (Any)

  • default (Any | None)

  • within (Any | None)

Return type:

MatrixOrder

property ordered_neurons: tuple[str, ...]#

typed_neurons + untyped_neurons.

Type:

Neuron order for both axes

plot(output_path=None, level='neuron', figsize=(16, 14), show_neuron_labels=False, vmin_percentile=0.0, vmax_percentile=100.0, min_neurons_for_plot=1, linewidth_scale=1.0)[source]#

Plot the connectivity matrix as a heatmap.

Parameters:
  • output_path (str | None, optional) – Save the figure here, creating the directory if needed.

  • level ({"neuron", "type_mean", "type_sum"}, default "neuron") – Plot the neuron-level matrix with nested type boundaries, or mean_type_matrix / sum_type_matrix.

  • figsize (tuple[int, int], default (16, 14)) – Figure size in inches.

  • show_neuron_labels (bool, default False) – Label axes with neuron IDs instead of type names. level="neuron" only.

  • vmin_percentile (float, default 0.0 and 100.0) – Color scale range, as percentiles over the strictly positive values – so zeros always map to the bottom, and any negative weights are excluded from the range and clipped. (Negatives reach the matrix through from_connectivity(), which passes weights through unchanged, or through weight_mode="column".) A vmax below 100 clips the strongest connections, making mid-range weights visible.

  • vmax_percentile (float, default 0.0 and 100.0) – Color scale range, as percentiles over the strictly positive values – so zeros always map to the bottom, and any negative weights are excluded from the range and clipped. (Negatives reach the matrix through from_connectivity(), which passes weights through unchanged, or through weight_mode="column".) A vmax below 100 clips the strongest connections, making mid-range weights visible.

  • min_neurons_for_plot (int, default 1) – Drop types with fewer neurons than this. level="neuron" only; the type-level matrices are plotted whole.

  • linewidth_scale (float, default 1.0) – Multiplier on the default boundary line widths.

Return type:

tuple[plt.Figure, plt.Axes]

Examples

>>> fig, ax = matrix.plot(level="type_mean", output_path='conn.png')
property sum_type_matrix: pandas.DataFrame#

Total weight between each pair of cell types (read-only view).

>>> matrix.sum_type_matrix.loc['KC', 'MB']  
property type_boundaries: Mapping[str, tuple[int, int]]#

Read-only mapping from cell type to its matrix slice.

property typed_neurons: tuple[str, ...]#

Neurons carrying a cell type – exactly those inside type_boundaries.

property untyped_neurons: tuple[str, ...]#

Neurons with no cell type, appended after every block.

Present in matrix but excluded from type-level aggregation. Ordered as neurons whose annotation row has a null cell type – which survive the default annotation_scope="annotated_only" – then, under annotation_scope="all", neurons with no annotation row at all, each group sorted by neuron ID as a string (so "30" precedes "7").

class crantpy.queries.nested_connectivity_matrices.NeuropilCollection[source]#

Bases: dict

Dict subclass mapping neuropil names to nested matrix instances.

Provides convenience methods for accessing and plotting individual neuropil/ROI matrices with cleaner syntax.

Examples

>>> matrices = NestedMatrix.from_synapses_by_neuropil(...)
>>> matrices.plot("protocerebral_bridge", level="neuron")
>>> matrices.plot(All)
>>> matrices.plot(All.minus("fan_shaped_body"))
>>> matrices.protocerebral_bridge.sum_type_matrix
plot(name, **kwargs)[source]#

Plot connectivity matrix/matrices.

Parameters:
  • name (str or All selector) – A single neuropil name, or All / All.minus(...) to plot multiple neuropils at once.

  • **kwargs – Forwarded to the contained matrix object’s plot() method.

Returns:

  • tuple[Figure, Axes] – When name is a single neuropil string.

  • dict[str, tuple[Figure, Axes]] – When name is an All selector.

Return type:

tuple[Figure, Axes] | dict[str, tuple[Figure, Axes]]