Skip to content

strength

champalimaud.strength

Connection strength from groups of cells to their partners.

A connection table has one row per pair of cells, with the root ids pre_pt_root_id and post_pt_root_id and the synapse count weight. The strength of a group of cells onto a partner is the heaviest single connection, so one strong cell pair marks the partner whether or not the rest of the group connects to it.

CLASSIFIERS = {'max': strong_by_max, 'sum': strong_by_sum} module-attribute

The ways to call a partner strong, by name.

Each takes (connections, *, cutoff, by="pre_type") and returns the strong relationships as a table of by and partner, so a notebook can take any of them. strong_by_filtered_sum also needs min_weight; bind it with functools.partial to use it in the same way.

label_partners(partners, census, proofread_ids, *, lateral_pattern)

Label each partner as proofread or not, by type, and lateral.

Parameters:

Name Type Description Default
partners DataFrame

Has a column partner of root ids.

required
census DataFrame

Has columns root_id and primary_type, the cell type of each census cell.

required
proofread_ids DataFrame

Has a column root_id listing the proofread neurons.

required
lateral_pattern str

Regular expression for the cell types that count as lateral, such as the types of the group being studied.

required

Returns:

Type Description
DataFrame

partners with three columns added:

partner_type The census type; untyped neuron for a proofread neuron the census does not name, unproofread fragment for everything else. proofread Whether the partner is a proofread neuron. lateral Whether partner_type matches lateral_pattern.

See Also

proofread_nonlateral : Keeps the rows that are neither.

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame({"partner": [1, 2, 3]})
>>> census = pl.DataFrame(
...     {"root_id": [1, 2], "primary_type": ["LC9", "Tm3"]}
... )
>>> proofread = pl.DataFrame({"root_id": [1, 2]})
>>> labeled = label_partners(
...     partners, census, proofread, lateral_pattern="^LC"
... )
>>> labeled["partner_type"].to_list()
['LC9', 'Tm3', 'unproofread fragment']
>>> labeled["lateral"].to_list()
[True, False, False]
Source code in champalimaud/strength.py
def label_partners(
    partners: pl.DataFrame,
    census: pl.DataFrame,
    proofread_ids: pl.DataFrame,
    *,
    lateral_pattern: str,
) -> pl.DataFrame:
    """Label each partner as proofread or not, by type, and lateral.

    Parameters
    ----------
    partners : polars.DataFrame
        Has a column ``partner`` of root ids.
    census : polars.DataFrame
        Has columns ``root_id`` and ``primary_type``, the cell type of
        each census cell.
    proofread_ids : polars.DataFrame
        Has a column ``root_id`` listing the proofread neurons.
    lateral_pattern : str
        Regular expression for the cell types that count as lateral,
        such as the types of the group being studied.

    Returns
    -------
    polars.DataFrame
        `partners` with three columns added:

        ``partner_type``
            The census type; ``untyped neuron`` for a proofread neuron
            the census does not name, ``unproofread fragment`` for
            everything else.
        ``proofread``
            Whether the partner is a proofread neuron.
        ``lateral``
            Whether ``partner_type`` matches `lateral_pattern`.

    See Also
    --------
    proofread_nonlateral : Keeps the rows that are neither.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame({"partner": [1, 2, 3]})
    >>> census = pl.DataFrame(
    ...     {"root_id": [1, 2], "primary_type": ["LC9", "Tm3"]}
    ... )
    >>> proofread = pl.DataFrame({"root_id": [1, 2]})
    >>> labeled = label_partners(
    ...     partners, census, proofread, lateral_pattern="^LC"
    ... )
    >>> labeled["partner_type"].to_list()
    ['LC9', 'Tm3', 'unproofread fragment']
    >>> labeled["lateral"].to_list()
    [True, False, False]
    """
    census_types = census.select(
        partner=pl.col("root_id"), partner_type=pl.col("primary_type")
    )
    return (
        partners.join(census_types, on="partner", how="left")
        .with_columns(
            proofread=pl.col("partner").is_in(
                proofread_ids["root_id"].to_list()
            )
        )
        .with_columns(
            partner_type=pl.coalesce(
                "partner_type",
                pl.when("proofread")
                .then(pl.lit("untyped neuron"))
                .otherwise(pl.lit("unproofread fragment")),
            )
        )
        .with_columns(
            lateral=pl.col("partner_type").str.contains(lateral_pattern)
        )
    )

labeled_partners(connections, cells_by_type, census, proofread_ids, *, lateral_pattern)

The partners of each type, with strength and labels.

Parameters:

Name Type Description Default
connections DataFrame

Connections that start at the cells of the types, with pre_type as the label of each presynaptic cell.

required
cells_by_type dict of str to list

Maps a type name to the ids of its cells.

required
census DataFrame

Has columns root_id and primary_type.

required
proofread_ids DataFrame

Has a column root_id listing the proofread neurons.

required
lateral_pattern str

Regular expression for the partner types that count as lateral.

required

Returns:

Type Description
DataFrame

The table of strengths_to_partners_with_cell_fraction with the columns of label_partners added.

See Also

strong_partners_of : Keeps the partners a classifier calls strong.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["T", "T"],
...         "post_pt_root_id": [10, 11],
...         "weight": [12, 4],
...     }
... )
>>> partners = labeled_partners(
...     connections,
...     {"T": [1, 2]},
...     pl.DataFrame({"root_id": [10], "primary_type": ["X"]}),
...     pl.DataFrame({"root_id": [10]}),
...     lateral_pattern="^LC",
... )
>>> partners.select("partner", "s", "partner_type").rows()
[(10, 12, 'X'), (11, 4, 'unproofread fragment')]
Source code in champalimaud/strength.py
def labeled_partners(
    connections: pl.DataFrame,
    cells_by_type: dict[str, list],
    census: pl.DataFrame,
    proofread_ids: pl.DataFrame,
    *,
    lateral_pattern: str,
) -> pl.DataFrame:
    """The partners of each type, with strength and labels.

    Parameters
    ----------
    connections : polars.DataFrame
        Connections that start at the cells of the types, with
        ``pre_type`` as the label of each presynaptic cell.
    cells_by_type : dict of str to list
        Maps a type name to the ids of its cells.
    census : polars.DataFrame
        Has columns ``root_id`` and ``primary_type``.
    proofread_ids : polars.DataFrame
        Has a column ``root_id`` listing the proofread neurons.
    lateral_pattern : str
        Regular expression for the partner types that count as lateral.

    Returns
    -------
    polars.DataFrame
        The table of `strengths_to_partners_with_cell_fraction` with
        the columns of `label_partners` added.

    See Also
    --------
    strong_partners_of : Keeps the partners a classifier calls strong.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["T", "T"],
    ...         "post_pt_root_id": [10, 11],
    ...         "weight": [12, 4],
    ...     }
    ... )
    >>> partners = labeled_partners(
    ...     connections,
    ...     {"T": [1, 2]},
    ...     pl.DataFrame({"root_id": [10], "primary_type": ["X"]}),
    ...     pl.DataFrame({"root_id": [10]}),
    ...     lateral_pattern="^LC",
    ... )
    >>> partners.select("partner", "s", "partner_type").rows()
    [(10, 12, 'X'), (11, 4, 'unproofread fragment')]
    """
    return label_partners(
        strengths_to_partners_with_cell_fraction(connections, cells_by_type),
        census,
        proofread_ids,
        lateral_pattern=lateral_pattern,
    )

partner_populations(partners)

The partners under four ways of choosing them.

Parameters:

Name Type Description Default
partners DataFrame

Has boolean columns proofread and lateral, as label_partners returns them.

required

Returns:

Type Description
dict of str to polars.DataFrame

The rows of partners under four names: "proofread", "proofread, no lateral", "with fragments" (all rows), and "with fragments, no lateral".

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame(
...     {
...         "partner": [1, 2, 3],
...         "proofread": [True, True, False],
...         "lateral": [False, True, False],
...     }
... )
>>> {
...     name: frame["partner"].to_list()
...     for name, frame in partner_populations(partners).items()
... }
{'proofread': [1, 2], 'proofread, no lateral': [1], 'with fragments': [1, 2, 3], 'with fragments, no lateral': [1, 3]}
Source code in champalimaud/strength.py
def partner_populations(partners: pl.DataFrame) -> dict[str, pl.DataFrame]:
    """The partners under four ways of choosing them.

    Parameters
    ----------
    partners : polars.DataFrame
        Has boolean columns ``proofread`` and ``lateral``, as
        `label_partners` returns them.

    Returns
    -------
    dict of str to polars.DataFrame
        The rows of `partners` under four names: ``"proofread"``,
        ``"proofread, no lateral"``, ``"with fragments"`` (all rows),
        and ``"with fragments, no lateral"``.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame(
    ...     {
    ...         "partner": [1, 2, 3],
    ...         "proofread": [True, True, False],
    ...         "lateral": [False, True, False],
    ...     }
    ... )
    >>> {
    ...     name: frame["partner"].to_list()
    ...     for name, frame in partner_populations(partners).items()
    ... }
    {'proofread': [1, 2], 'proofread, no lateral': [1], \
'with fragments': [1, 2, 3], 'with fragments, no lateral': [1, 3]}
    """
    proofread = partners.filter(pl.col("proofread"))
    return {
        "proofread": proofread,
        "proofread, no lateral": proofread.filter(~pl.col("lateral")),
        "with fragments": partners,
        "with fragments, no lateral": partners.filter(~pl.col("lateral")),
    }

proofread_nonlateral(partners)

The proofread, non-lateral rows of a labeled partner table.

Parameters:

Name Type Description Default
partners DataFrame

Has boolean columns proofread and lateral, as label_partners returns them.

required

Returns:

Type Description
DataFrame

The rows with proofread true and lateral false.

See Also

label_partners : Adds the two columns.

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame(
...     {
...         "partner": [1, 2, 3],
...         "proofread": [True, True, False],
...         "lateral": [False, True, False],
...     }
... )
>>> proofread_nonlateral(partners)["partner"].to_list()
[1]
Source code in champalimaud/strength.py
def proofread_nonlateral(partners: pl.DataFrame) -> pl.DataFrame:
    """The proofread, non-lateral rows of a labeled partner table.

    Parameters
    ----------
    partners : polars.DataFrame
        Has boolean columns ``proofread`` and ``lateral``, as
        `label_partners` returns them.

    Returns
    -------
    polars.DataFrame
        The rows with ``proofread`` true and ``lateral`` false.

    See Also
    --------
    label_partners : Adds the two columns.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame(
    ...     {
    ...         "partner": [1, 2, 3],
    ...         "proofread": [True, True, False],
    ...         "lateral": [False, True, False],
    ...     }
    ... )
    >>> proofread_nonlateral(partners)["partner"].to_list()
    [1]
    """
    return partners.filter(pl.col("proofread") & ~pl.col("lateral"))

restrict_to(partners, relationships)

The rows of a partner table that appear in a table of pairs.

Parameters:

Name Type Description Default
partners DataFrame

Has columns type and partner.

required
relationships DataFrame

Has columns type and partner, such as the strong relationships a classifier returns with its group column named type.

required

Returns:

Type Description
DataFrame

The rows of partners whose type and partner are in relationships, with all of partners columns.

See Also

CLASSIFIERS : Where the strong relationships come from.

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame(
...     {
...         "type": ["A", "A", "B"],
...         "partner": [1, 2, 1],
...         "s": [3, 9, 4],
...     }
... )
>>> strong = pl.DataFrame({"type": ["A"], "partner": [2]})
>>> restrict_to(partners, strong).to_dicts()
[{'type': 'A', 'partner': 2, 's': 9}]
Source code in champalimaud/strength.py
def restrict_to(
    partners: pl.DataFrame, relationships: pl.DataFrame
) -> pl.DataFrame:
    """The rows of a partner table that appear in a table of pairs.

    Parameters
    ----------
    partners : polars.DataFrame
        Has columns ``type`` and ``partner``.
    relationships : polars.DataFrame
        Has columns ``type`` and ``partner``, such as the strong
        relationships a classifier returns with its group column named
        ``type``.

    Returns
    -------
    polars.DataFrame
        The rows of `partners` whose ``type`` and ``partner`` are in
        `relationships`, with all of `partners` columns.

    See Also
    --------
    CLASSIFIERS : Where the strong relationships come from.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame(
    ...     {
    ...         "type": ["A", "A", "B"],
    ...         "partner": [1, 2, 1],
    ...         "s": [3, 9, 4],
    ...     }
    ... )
    >>> strong = pl.DataFrame({"type": ["A"], "partner": [2]})
    >>> restrict_to(partners, strong).to_dicts()
    [{'type': 'A', 'partner': 2, 's': 9}]
    """
    return partners.join(relationships, on=["type", "partner"], how="semi")

strengths_to_partners(connections, *, by='pre_type')

Strength from each group of presynaptic cells to each partner.

Parameters:

Name Type Description Default
connections DataFrame

One row per cell pair, with columns post_pt_root_id, weight, and the column named by by.

required
by str

Column that labels the group of each connection's presynaptic cell, usually the cell type. Rows where it is null are dropped.

"pre_type"

Returns:

Type Description
DataFrame

One row per group and partner, sorted by by and partner, with columns:

partner Root id of the postsynaptic cell. s The largest weight onto the partner from one cell. synapses The sum of weights onto the partner. cells The number of presynaptic cells connected to the partner.

See Also

strong_partners : Root ids of the partners at or above a cutoff. strong_share : The share of partners and synapses that are strong.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A", "A"],
...         "post_pt_root_id": [7, 7, 8],
...         "weight": [2, 25, 1],
...     }
... )
>>> strengths_to_partners(connections).to_dicts()
...
[{'pre_type': 'A', 'partner': 7, 's': 25,
  'synapses': 27, 'cells': 2},
 {'pre_type': 'A', 'partner': 8, 's': 1,
  'synapses': 1, 'cells': 1}]
Source code in champalimaud/strength.py
def strengths_to_partners(
    connections: pl.DataFrame, *, by: str = "pre_type"
) -> pl.DataFrame:
    """Strength from each group of presynaptic cells to each partner.

    Parameters
    ----------
    connections : polars.DataFrame
        One row per cell pair, with columns ``post_pt_root_id``,
        ``weight``, and the column named by `by`.
    by : str, default "pre_type"
        Column that labels the group of each connection's presynaptic
        cell, usually the cell type.
        Rows where it is null are dropped.

    Returns
    -------
    polars.DataFrame
        One row per group and partner, sorted by `by` and ``partner``,
        with columns:

        ``partner``
            Root id of the postsynaptic cell.
        ``s``
            The largest weight onto the partner from one cell.
        ``synapses``
            The sum of weights onto the partner.
        ``cells``
            The number of presynaptic cells connected to the partner.

    See Also
    --------
    strong_partners : Root ids of the partners at or above a cutoff.
    strong_share : The share of partners and synapses that are strong.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A", "A"],
    ...         "post_pt_root_id": [7, 7, 8],
    ...         "weight": [2, 25, 1],
    ...     }
    ... )
    >>> strengths_to_partners(connections).to_dicts()
    ... # doctest: +NORMALIZE_WHITESPACE
    [{'pre_type': 'A', 'partner': 7, 's': 25,
      'synapses': 27, 'cells': 2},
     {'pre_type': 'A', 'partner': 8, 's': 1,
      'synapses': 1, 'cells': 1}]
    """
    return (
        connections.drop_nulls(by)
        .group_by(by, "post_pt_root_id")
        .agg(
            s=pl.col("weight").max(),
            synapses=pl.col("weight").sum(),
            cells=pl.len(),
        )
        .rename({"post_pt_root_id": "partner"})
        .sort(by, "partner")
    )

strengths_to_partners_with_cell_fraction(connections, cells_by_type)

Strength of every partner of each type, with the cell fraction.

Parameters:

Name Type Description Default
connections DataFrame

As for strengths_to_partners, with pre_type as the label of each presynaptic cell.

required
cells_by_type dict of str to list

Maps a type name to the ids of its cells. The sizes are the denominators of cell_fraction, so a cell with no connection still counts.

required

Returns:

Type Description
DataFrame

The table of strengths_to_partners with pre_type renamed type, and cell_fraction, the share of the type's cells that connect to the partner.

See Also

strengths_to_partners : The table this adds the fraction to.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A"],
...         "post_pt_root_id": [7, 7],
...         "weight": [2, 25],
...     }
... )
>>> table = strengths_to_partners_with_cell_fraction(
...     connections, {"A": [1, 2, 3, 4]}
... )
>>> table["cell_fraction"].to_list()
[0.5]
Source code in champalimaud/strength.py
def strengths_to_partners_with_cell_fraction(
    connections: pl.DataFrame, cells_by_type: dict[str, list]
) -> pl.DataFrame:
    """Strength of every partner of each type, with the cell fraction.

    Parameters
    ----------
    connections : polars.DataFrame
        As for `strengths_to_partners`, with ``pre_type`` as the label
        of each presynaptic cell.
    cells_by_type : dict of str to list
        Maps a type name to the ids of its cells.
        The sizes are the denominators of ``cell_fraction``, so a cell
        with no connection still counts.

    Returns
    -------
    polars.DataFrame
        The table of `strengths_to_partners` with ``pre_type`` renamed
        ``type``, and ``cell_fraction``, the share of the type's cells
        that connect to the partner.

    See Also
    --------
    strengths_to_partners : The table this adds the fraction to.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A"],
    ...         "post_pt_root_id": [7, 7],
    ...         "weight": [2, 25],
    ...     }
    ... )
    >>> table = strengths_to_partners_with_cell_fraction(
    ...     connections, {"A": [1, 2, 3, 4]}
    ... )
    >>> table["cell_fraction"].to_list()
    [0.5]
    """
    size = {name: len(ids) for name, ids in cells_by_type.items()}
    return (
        strengths_to_partners(connections)
        .rename({"pre_type": "type"})
        .with_columns(
            cell_fraction=pl.col("cells") / pl.col("type").replace_strict(size)
        )
    )

strong_by_filtered_sum(connections, *, cutoff, min_weight, by='pre_type')

Partners whose heavy connections add up to a cutoff.

A partner is strong for a group when the connections of at least min_weight synapses onto it add up to at least cutoff. With min_weight equal to cutoff this is strong_by_max; a lower min_weight lets several lighter connections count.

Parameters:

Name Type Description Default
connections DataFrame

As for strengths_to_partners.

required
cutoff int

Smallest filtered sum, in synapses, that counts as strong.

required
min_weight int

Smallest connection, in synapses, that is added.

required
by str

Column that labels the group of each presynaptic cell.

"pre_type"

Returns:

Type Description
DataFrame

The strong relationships, in the shape strong_by_max returns.

See Also

strong_by_max : The heaviest single connection. strong_by_sum : Every connection added. strong_connection_sums : The filtered sums themselves.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A", "A", "A"],
...         "post_pt_root_id": [7, 7, 8, 8],
...         "weight": [6, 5, 11, 4],
...     }
... )
>>> strong_by_filtered_sum(
...     connections, cutoff=10, min_weight=5
... ).to_dicts()
[{'pre_type': 'A', 'partner': 7}, {'pre_type': 'A', 'partner': 8}]
Source code in champalimaud/strength.py
def strong_by_filtered_sum(
    connections: pl.DataFrame,
    *,
    cutoff: int,
    min_weight: int,
    by: str = "pre_type",
) -> pl.DataFrame:
    """Partners whose heavy connections add up to a cutoff.

    A partner is strong for a group when the connections of at least
    `min_weight` synapses onto it add up to at least `cutoff`.
    With `min_weight` equal to `cutoff` this is `strong_by_max`; a
    lower `min_weight` lets several lighter connections count.

    Parameters
    ----------
    connections : polars.DataFrame
        As for `strengths_to_partners`.
    cutoff : int
        Smallest filtered sum, in synapses, that counts as strong.
    min_weight : int
        Smallest connection, in synapses, that is added.
    by : str, default "pre_type"
        Column that labels the group of each presynaptic cell.

    Returns
    -------
    polars.DataFrame
        The strong relationships, in the shape `strong_by_max` returns.

    See Also
    --------
    strong_by_max : The heaviest single connection.
    strong_by_sum : Every connection added.
    strong_connection_sums : The filtered sums themselves.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A", "A", "A"],
    ...         "post_pt_root_id": [7, 7, 8, 8],
    ...         "weight": [6, 5, 11, 4],
    ...     }
    ... )
    >>> strong_by_filtered_sum(
    ...     connections, cutoff=10, min_weight=5
    ... ).to_dicts()
    [{'pre_type': 'A', 'partner': 7}, {'pre_type': 'A', 'partner': 8}]
    """
    return (
        strong_connection_sums(connections, min_weight=min_weight, by=by)
        .filter(pl.col("s_sum_filtered") >= cutoff)
        .select(by, "partner")
        .sort(by, "partner")
    )

strong_by_max(connections, *, cutoff, by='pre_type')

Partners that one presynaptic cell alone connects to strongly.

A partner is strong for a group when its heaviest single connection from the group has at least cutoff synapses.

Parameters:

Name Type Description Default
connections DataFrame

As for strengths_to_partners.

required
cutoff int

Smallest strength, in synapses, that counts as strong.

required
by str

Column that labels the group of each presynaptic cell.

"pre_type"

Returns:

Type Description
DataFrame

The strong relationships: columns by and partner, one row per strong group and partner, sorted by both.

See Also

strong_by_sum : The same with the strength summed over the group. CLASSIFIERS : Both, by name.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A", "A", "A"],
...         "post_pt_root_id": [7, 7, 8, 8],
...         "weight": [6, 5, 11, 4],
...     }
... )
>>> strong_by_max(connections, cutoff=10).to_dicts()
[{'pre_type': 'A', 'partner': 8}]
Source code in champalimaud/strength.py
def strong_by_max(
    connections: pl.DataFrame, *, cutoff: int, by: str = "pre_type"
) -> pl.DataFrame:
    """Partners that one presynaptic cell alone connects to strongly.

    A partner is strong for a group when its heaviest single
    connection from the group has at least `cutoff` synapses.

    Parameters
    ----------
    connections : polars.DataFrame
        As for `strengths_to_partners`.
    cutoff : int
        Smallest strength, in synapses, that counts as strong.
    by : str, default "pre_type"
        Column that labels the group of each presynaptic cell.

    Returns
    -------
    polars.DataFrame
        The strong relationships: columns `by` and ``partner``, one row
        per strong group and partner, sorted by both.

    See Also
    --------
    strong_by_sum : The same with the strength summed over the group.
    CLASSIFIERS : Both, by name.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A", "A", "A"],
    ...         "post_pt_root_id": [7, 7, 8, 8],
    ...         "weight": [6, 5, 11, 4],
    ...     }
    ... )
    >>> strong_by_max(connections, cutoff=10).to_dicts()
    [{'pre_type': 'A', 'partner': 8}]
    """
    return (
        strengths_to_partners(connections, by=by)
        .filter(pl.col("s") >= cutoff)
        .select(by, "partner")
    )

strong_by_sum(connections, *, cutoff, by='pre_type')

Partners that a group of presynaptic cells drives strongly.

A partner is strong for a group when the connections onto it from the whole group add up to at least cutoff synapses, however many cells they come from.

Parameters:

Name Type Description Default
connections DataFrame

As for strengths_to_partners.

required
cutoff int

Smallest strength, in synapses, that counts as strong.

required
by str

Column that labels the group of each presynaptic cell.

"pre_type"

Returns:

Type Description
DataFrame

The strong relationships, in the shape strong_by_max returns.

See Also

strong_by_max : The same with the heaviest single connection. CLASSIFIERS : Both, by name.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A", "A", "A"],
...         "post_pt_root_id": [7, 7, 8, 8],
...         "weight": [6, 5, 11, 4],
...     }
... )
>>> strong_by_sum(connections, cutoff=10).to_dicts()
[{'pre_type': 'A', 'partner': 7}, {'pre_type': 'A', 'partner': 8}]
Source code in champalimaud/strength.py
def strong_by_sum(
    connections: pl.DataFrame, *, cutoff: int, by: str = "pre_type"
) -> pl.DataFrame:
    """Partners that a group of presynaptic cells drives strongly.

    A partner is strong for a group when the connections onto it from
    the whole group add up to at least `cutoff` synapses, however many
    cells they come from.

    Parameters
    ----------
    connections : polars.DataFrame
        As for `strengths_to_partners`.
    cutoff : int
        Smallest strength, in synapses, that counts as strong.
    by : str, default "pre_type"
        Column that labels the group of each presynaptic cell.

    Returns
    -------
    polars.DataFrame
        The strong relationships, in the shape `strong_by_max` returns.

    See Also
    --------
    strong_by_max : The same with the heaviest single connection.
    CLASSIFIERS : Both, by name.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A", "A", "A"],
    ...         "post_pt_root_id": [7, 7, 8, 8],
    ...         "weight": [6, 5, 11, 4],
    ...     }
    ... )
    >>> strong_by_sum(connections, cutoff=10).to_dicts()
    [{'pre_type': 'A', 'partner': 7}, {'pre_type': 'A', 'partner': 8}]
    """
    return (
        strengths_to_partners(connections, by=by)
        .filter(pl.col("synapses") >= cutoff)
        .select(by, "partner")
    )

strong_connection_sums(connections, *, min_weight, by='pre_type')

Summed weight of the heavy connections onto each partner.

Only connections of at least min_weight synapses are added, so a partner reached only by lighter connections has no row.

Parameters:

Name Type Description Default
connections DataFrame

As for strengths_to_partners.

required
min_weight int

Smallest connection, in synapses, that is added.

required
by str

Column that labels the group of each presynaptic cell.

"pre_type"

Returns:

Type Description
DataFrame

Columns by, partner, and s_sum_filtered, the sum of the connections at or above min_weight.

See Also

strong_by_filtered_sum : Partners where this sum reaches a cutoff.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["A", "A", "A", "A"],
...         "post_pt_root_id": [7, 7, 8, 8],
...         "weight": [6, 5, 11, 4],
...     }
... )
>>> strong_connection_sums(connections, min_weight=10).to_dicts()
[{'pre_type': 'A', 'partner': 8, 's_sum_filtered': 11}]
Source code in champalimaud/strength.py
def strong_connection_sums(
    connections: pl.DataFrame, *, min_weight: int, by: str = "pre_type"
) -> pl.DataFrame:
    """Summed weight of the heavy connections onto each partner.

    Only connections of at least `min_weight` synapses are added, so a
    partner reached only by lighter connections has no row.

    Parameters
    ----------
    connections : polars.DataFrame
        As for `strengths_to_partners`.
    min_weight : int
        Smallest connection, in synapses, that is added.
    by : str, default "pre_type"
        Column that labels the group of each presynaptic cell.

    Returns
    -------
    polars.DataFrame
        Columns `by`, ``partner``, and ``s_sum_filtered``, the sum of
        the connections at or above `min_weight`.

    See Also
    --------
    strong_by_filtered_sum : Partners where this sum reaches a cutoff.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["A", "A", "A", "A"],
    ...         "post_pt_root_id": [7, 7, 8, 8],
    ...         "weight": [6, 5, 11, 4],
    ...     }
    ... )
    >>> strong_connection_sums(connections, min_weight=10).to_dicts()
    [{'pre_type': 'A', 'partner': 8, 's_sum_filtered': 11}]
    """
    return (
        connections.drop_nulls(by)
        .filter(pl.col("weight") >= min_weight)
        .group_by(by, "post_pt_root_id")
        .agg(s_sum_filtered=pl.col("weight").sum())
        .rename({"post_pt_root_id": "partner"})
    )

strong_partners(partners, cutoff)

Root ids of the partners whose strength reaches a cutoff.

Parameters:

Name Type Description Default
partners DataFrame

Has columns partner and s, as strengths_to_partners returns it.

required
cutoff int

Smallest strength, in synapses, that counts as strong.

required

Returns:

Type Description
set of int

The partner values with s at or above cutoff.

See Also

strengths_to_partners : The table this filters.

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame(
...     {"partner": [1, 2, 3], "s": [9, 10, 15]}
... )
>>> sorted(strong_partners(partners, 10))
[2, 3]
Source code in champalimaud/strength.py
def strong_partners(partners: pl.DataFrame, cutoff: int) -> set[int]:
    """Root ids of the partners whose strength reaches a cutoff.

    Parameters
    ----------
    partners : polars.DataFrame
        Has columns ``partner`` and ``s``, as `strengths_to_partners`
        returns it.
    cutoff : int
        Smallest strength, in synapses, that counts as strong.

    Returns
    -------
    set of int
        The ``partner`` values with ``s`` at or above `cutoff`.

    See Also
    --------
    strengths_to_partners : The table this filters.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame(
    ...     {"partner": [1, 2, 3], "s": [9, 10, 15]}
    ... )
    >>> sorted(strong_partners(partners, 10))
    [2, 3]
    """
    return set(partners.filter(pl.col("s") >= cutoff)["partner"].to_list())

strong_partners_of(partners, connections, classify, cutoff)

Proofread, non-lateral partners that a classifier calls strong.

Parameters:

Name Type Description Default
partners DataFrame

Has columns type, partner, proofread, and lateral, as labeled_partners returns them from connections.

required
connections DataFrame

The connections partners came from, with pre_type.

required
classify callable

An entry of CLASSIFIERS.

required
cutoff int

Passed to classify.

required

Returns:

Type Description
DataFrame

The rows of partners that classify calls strong and that are proofread and not lateral.

See Also

CLASSIFIERS : The classifiers to pass. restrict_to : Keeps the rows that are in a table of pairs. proofread_nonlateral : The proofread and lateral filter.

Examples:

>>> import polars as pl
>>> connections = pl.DataFrame(
...     {
...         "pre_type": ["T", "T"],
...         "post_pt_root_id": [10, 11],
...         "weight": [12, 4],
...     }
... )
>>> partners = labeled_partners(
...     connections,
...     {"T": [1, 2]},
...     pl.DataFrame(
...         {"root_id": [10, 11], "primary_type": ["X", "Y"]}
...     ),
...     pl.DataFrame({"root_id": [10, 11]}),
...     lateral_pattern="^LC",
... )
>>> strong_partners_of(
...     partners, connections, CLASSIFIERS["max"], 10
... )["partner"].to_list()
[10]
Source code in champalimaud/strength.py
def strong_partners_of(
    partners: pl.DataFrame,
    connections: pl.DataFrame,
    classify: Callable[..., pl.DataFrame],
    cutoff: int,
) -> pl.DataFrame:
    """Proofread, non-lateral partners that a classifier calls strong.

    Parameters
    ----------
    partners : polars.DataFrame
        Has columns ``type``, ``partner``, ``proofread``, and
        ``lateral``, as `labeled_partners` returns them from
        `connections`.
    connections : polars.DataFrame
        The connections `partners` came from, with ``pre_type``.
    classify : callable
        An entry of `CLASSIFIERS`.
    cutoff : int
        Passed to `classify`.

    Returns
    -------
    polars.DataFrame
        The rows of `partners` that `classify` calls strong and that
        are proofread and not lateral.

    See Also
    --------
    CLASSIFIERS : The classifiers to pass.
    restrict_to : Keeps the rows that are in a table of pairs.
    proofread_nonlateral : The proofread and lateral filter.

    Examples
    --------
    >>> import polars as pl
    >>> connections = pl.DataFrame(
    ...     {
    ...         "pre_type": ["T", "T"],
    ...         "post_pt_root_id": [10, 11],
    ...         "weight": [12, 4],
    ...     }
    ... )
    >>> partners = labeled_partners(
    ...     connections,
    ...     {"T": [1, 2]},
    ...     pl.DataFrame(
    ...         {"root_id": [10, 11], "primary_type": ["X", "Y"]}
    ...     ),
    ...     pl.DataFrame({"root_id": [10, 11]}),
    ...     lateral_pattern="^LC",
    ... )
    >>> strong_partners_of(
    ...     partners, connections, CLASSIFIERS["max"], 10
    ... )["partner"].to_list()
    [10]
    """
    strong = classify(connections, cutoff=cutoff).rename({"pre_type": "type"})
    return proofread_nonlateral(restrict_to(partners, strong))

strong_share(partners, *, cutoff)

The share of each type's partners and output that are strong.

Parameters:

Name Type Description Default
partners DataFrame

Has columns type, s, and synapses, one row per type and partner.

required
cutoff int

Smallest strength, in synapses, that counts as strong.

required

Returns:

Type Description
DataFrame

One row per type, in order of first appearance, with columns:

n_partners The number of partners. n_strong The number with s at or above cutoff. partner_fraction n_strong over n_partners. synapse_fraction The synapses onto strong partners over all synapses onto partners.

See Also

strong_partners : The ids of the strong partners.

Examples:

>>> import polars as pl
>>> partners = pl.DataFrame(
...     {
...         "type": ["A", "A", "A", "B"],
...         "s": [10, 9, 1, 1],
...         "synapses": [30, 10, 10, 4],
...     }
... )
>>> strong_share(partners, cutoff=10).to_dicts()
...
[{'type': 'A', 'n_partners': 3, 'n_strong': 1,
  'partner_fraction': 0.3333333333333333, 'synapse_fraction': 0.6},
 {'type': 'B', 'n_partners': 1, 'n_strong': 0,
  'partner_fraction': 0.0, 'synapse_fraction': 0.0}]
Source code in champalimaud/strength.py
def strong_share(partners: pl.DataFrame, *, cutoff: int) -> pl.DataFrame:
    """The share of each type's partners and output that are strong.

    Parameters
    ----------
    partners : polars.DataFrame
        Has columns ``type``, ``s``, and ``synapses``, one row per
        type and partner.
    cutoff : int
        Smallest strength, in synapses, that counts as strong.

    Returns
    -------
    polars.DataFrame
        One row per type, in order of first appearance, with columns:

        ``n_partners``
            The number of partners.
        ``n_strong``
            The number with ``s`` at or above `cutoff`.
        ``partner_fraction``
            ``n_strong`` over ``n_partners``.
        ``synapse_fraction``
            The synapses onto strong partners over all synapses onto
            partners.

    See Also
    --------
    strong_partners : The ids of the strong partners.

    Examples
    --------
    >>> import polars as pl
    >>> partners = pl.DataFrame(
    ...     {
    ...         "type": ["A", "A", "A", "B"],
    ...         "s": [10, 9, 1, 1],
    ...         "synapses": [30, 10, 10, 4],
    ...     }
    ... )
    >>> strong_share(partners, cutoff=10).to_dicts()
    ... # doctest: +NORMALIZE_WHITESPACE
    [{'type': 'A', 'n_partners': 3, 'n_strong': 1,
      'partner_fraction': 0.3333333333333333, 'synapse_fraction': 0.6},
     {'type': 'B', 'n_partners': 1, 'n_strong': 0,
      'partner_fraction': 0.0, 'synapse_fraction': 0.0}]
    """
    strong = pl.col("s") >= cutoff
    return (
        partners.group_by("type", maintain_order=True)
        .agg(
            n_partners=pl.len(),
            n_strong=strong.sum(),
            synapse_fraction=pl.col("synapses").filter(strong).sum()
            / pl.col("synapses").sum(),
        )
        .with_columns(
            partner_fraction=pl.col("n_strong") / pl.col("n_partners")
        )
        .select(
            "type",
            "n_partners",
            "n_strong",
            "partner_fraction",
            "synapse_fraction",
        )
    )

type_mass(strong)

Synapses between each type and each partner type.

Parameters:

Name Type Description Default
strong DataFrame

Has columns type, partner_type, and synapses, as labeled_partners returns them. A partner that is a proofread neuron with no type in the census is left out.

required

Returns:

Type Description
DataFrame

Columns type, partner_type, and synapses, the heaviest partner type first within a type.

Examples:

>>> import polars as pl
>>> strong = pl.DataFrame(
...     {
...         "type": ["T", "T", "T"],
...         "partner_type": ["X", "X", "Y"],
...         "synapses": [5, 7, 20],
...     }
... )
>>> type_mass(strong).rows()
[('T', 'Y', 20), ('T', 'X', 12)]
Source code in champalimaud/strength.py
def type_mass(strong: pl.DataFrame) -> pl.DataFrame:
    """Synapses between each type and each partner type.

    Parameters
    ----------
    strong : polars.DataFrame
        Has columns ``type``, ``partner_type``, and ``synapses``, as
        `labeled_partners` returns them.
        A partner that is a proofread neuron with no type in the
        census is left out.

    Returns
    -------
    polars.DataFrame
        Columns ``type``, ``partner_type``, and ``synapses``, the
        heaviest partner type first within a type.

    Examples
    --------
    >>> import polars as pl
    >>> strong = pl.DataFrame(
    ...     {
    ...         "type": ["T", "T", "T"],
    ...         "partner_type": ["X", "X", "Y"],
    ...         "synapses": [5, 7, 20],
    ...     }
    ... )
    >>> type_mass(strong).rows()
    [('T', 'Y', 20), ('T', 'X', 12)]
    """
    return (
        strong.filter(pl.col("partner_type") != "untyped neuron")
        .group_by("type", "partner_type")
        .agg(pl.col("synapses").sum())
        .sort(
            "type", "synapses", "partner_type", descending=[False, True, False]
        )
    )