Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup #71

Merged
merged 4 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions atlas_densities/densities/fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ def fill_in_homogenous_regions(
inhibitory_mask = homogenous_regions["cell_type"] == "inhibitory"

for region_name in homogenous_regions[inhibitory_mask]["brain_region"]:
desc_id_set = hierarchy_info.at[region_name, "descendant_id_set"]
desc_id_set = hierarchy_info.at[region_name, "descendant_ids"]
id_mask = [id_ in desc_id_set for id_ in hierarchy_info["id"]]
for child_region_name in hierarchy_info[id_mask].index:
region_mask = np.isin(
annotation, list(hierarchy_info.at[child_region_name, "descendant_id_set"])
annotation, list(hierarchy_info.at[child_region_name, "descendant_ids"])
)
density = np.mean(neuron_density[region_mask])
densities.at[child_region_name, "inhibitory_neuron"] = density
Expand All @@ -165,7 +165,7 @@ def fill_in_homogenous_regions(
excitatory_mask = homogenous_regions["cell_type"] == "excitatory"

for region_name in homogenous_regions[excitatory_mask]["brain_region"]:
desc_id_set = hierarchy_info.at[region_name, "descendant_id_set"]
desc_id_set = hierarchy_info.at[region_name, "descendant_ids"]
id_mask = [id_ in desc_id_set for id_ in hierarchy_info["id"]]
for child_region_name in hierarchy_info[id_mask].index:
densities.at[child_region_name, "inhibitory_neuron"] = 0.0
Expand Down Expand Up @@ -232,7 +232,7 @@ def compute_average_intensities(
}
where each intensity array is of shape (W, H, D) and where the items of each slice
list range in [0, W - 1].
hierarchy_info: data frame with colums "descendant_id_set" (set[int]) and "brain_region"
hierarchy_info: data frame with colums "descendant_ids" (set[int]) and "brain_region"
(str) and whose index is a list of region ids.
See :fun:`atlas_densities.densities.utils.get_hierarchy_info`.

Expand Down Expand Up @@ -260,7 +260,7 @@ def compute_average_intensities(
region_count,
)
for region_name in tqdm(result.index):
region_mask = np.isin(annotation, list(hierarchy_info.at[region_name, "descendant_id_set"]))
region_mask = np.isin(annotation, list(hierarchy_info.at[region_name, "descendant_ids"]))
for marker, intensity in gene_marker_volumes.items():
result.at[region_name, marker.lower()] = compute_average_intensity(
intensity["intensity"], region_mask, intensity["slices"]
Expand Down
123 changes: 1 addition & 122 deletions atlas_densities/densities/inhibitory_neuron_densities_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
"""

import logging
from typing import List, Optional, Set, Tuple
from typing import List

import numpy as np
import pandas as pd
from atlas_commons.typing import FloatArray

from atlas_densities.exceptions import AtlasDensitiesError

L = logging.getLogger(__name__)
MinMaxPair = Tuple[float, Optional[float]]


def average_densities_to_cell_counts(
Expand All @@ -34,11 +30,6 @@ def average_densities_to_cell_counts(
:func:`atlas_densities.densities.utils.compute_region_volumes`.
The volumes to be used are stored in the "volume" column.


Note: Volumes can refer to volumes of entire regions, including all descendants
subregions, or volumes of single region identifiers, depending on the value of the
option `with_descendants` used when creating `region_volumes`.

Returns:
data frame containing the cell counts of brain regions and their associated standard
deviations. The data frame index is `average_densities.index` (brain region names) and
Expand All @@ -54,35 +45,6 @@ def average_densities_to_cell_counts(
return result


def resize_average_densities(
average_densities: pd.DataFrame, hierarchy_info: pd.DataFrame
) -> pd.DataFrame:
"""
Resize the `average_densities` data frame in such a way that the resized index coincides with
`hierarchy_info["brain_region"]`.

Missing entries are set to ``np.nan``.

average_densities: a data frame whose columns are described in
:func:`atlas_densities.densities.fitting.linear_fitting` containing the average
cell densities of brain regions and their associated standard deviations. Columns are
labelled by T and T_standard_deviation for various cell types T. The index of
`average_densities` is a list of region names.
hierarchy_info: data frame returned by
:func:`atlas_densities.densities.utils.get_hierarchy_info`.

Returns: a data frame containing all the entries of `average_densities` and whose index is
`hierarchy_info["brain_region"]`. New entries are set to ``np.nan``.

"""
resized = pd.DataFrame(
np.nan, index=hierarchy_info["brain_region"], columns=average_densities.columns
)
resized.loc[average_densities.index] = average_densities

return resized


def get_cell_types(data_frame: pd.DataFrame) -> List[str]:
"""
Extract cell types from column labels.
Expand All @@ -96,86 +58,3 @@ def get_cell_types(data_frame: pd.DataFrame) -> List[str]:
"""

return sorted({column.replace("_standard_deviation", "") for column in data_frame.columns})


def check_region_counts_consistency(
region_counts: pd.DataFrame, hierarchy_info: pd.DataFrame, tolerance: float = 0.0
) -> None:
"""
Check that cell counts considered as certain are consistent across the brain regions hierarchy.

Args:
region_counts: data frame returned by
:fun:`densities.inhibitory_densities_helper.average_densities_to_cell_counts`.
A region is understood as a region of the brain hierarchy and includes all descendant
subregions.
hierarchy_info: data frame returned by
:func:`atlas_densities.densities.utils.get_hierarchy_info`.
tolerance: non-negative float number used as tolerance when comparing counts.
Defaults to 0.0.

Raises:
AtlasDensitiesError if the sum of the cell counts of some leaf regions, all given with
certainty, exceeds the cell count of an ancestor, also given with certainty.

"""

def _check_descendants_consistency(
region_counts, hierarchy_info, region_name: str, id_set: Set[int], cell_type: str
):
if region_counts.at[region_name, f"{cell_type}_standard_deviation"] == 0.0:
count = region_counts.at[region_name, cell_type]
descendants_names = hierarchy_info.loc[list(id_set), "brain_region"]
zero_std_mask = (
region_counts.loc[descendants_names, f"{cell_type}_standard_deviation"] == 0.0
)
mask = zero_std_mask & (
region_counts.loc[descendants_names, cell_type] > count + tolerance
)
descendants_counts = region_counts.loc[descendants_names, cell_type][mask]
if not descendants_counts.empty:
raise AtlasDensitiesError(
f"Counts of {cell_type} cells in regions {list(descendants_names)} all exceed "
f"the count of its ancestor region {region_name} and each count is given "
f"for certain. The counts {descendants_counts} are all larger than "
f"{count}."
)
names_with_certainty = descendants_names[zero_std_mask.to_list()].to_list()
leaf_names = [
hierarchy_info.at[id_, "brain_region"]
for id_ in id_set
if len(hierarchy_info.at[id_, "descendant_id_set"]) == 1
and hierarchy_info.at[id_, "brain_region"] in names_with_certainty
]
leaves_count_sum = np.sum(region_counts.loc[leaf_names, cell_type])
if leaves_count_sum > count + tolerance:
raise AtlasDensitiesError(
f"The sum of the counts of {cell_type} cells in leaf regions",
f" which are given with certainty, exceeds the count of the ancestor"
f" region {region_name}, also given with certainty: "
f"{leaves_count_sum} > {count}.",
)

cell_types = get_cell_types(region_counts)
for region_name, id_set in zip(
hierarchy_info["brain_region"], hierarchy_info["descendant_id_set"]
):
for cell_type in cell_types:
_check_descendants_consistency(
region_counts, hierarchy_info, region_name, id_set, cell_type
)


def replace_inf_with_none(bounds: FloatArray) -> List[MinMaxPair]:
"""
Replace the upper bounds equal to ``np.inf`` by None so as to comply with
the `bounds` interface of scipy.optimize.linprog.

Args:
bounds: float array of shape (N, 2). Values in `bounds[..., 1]` can be
``np.inf`` to indicate the absence of a constraining upper bound.

Return:
list of pairs (min, max) where min is a float and max either a float or None.
"""
return [(float(min_), None if np.isinf(max_) else float(max_)) for min_, max_ in bounds]
Loading
Loading