diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..ca9c8f1 --- /dev/null +++ b/404.html @@ -0,0 +1,1154 @@ + + + + + + + + + + + + + + + + + + + + + + + cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-compute.html b/api-compute.html new file mode 100644 index 0000000..448e406 --- /dev/null +++ b/api-compute.html @@ -0,0 +1,2515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.compute - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

cuisto.compute

+ +
+ + + + +
+ +

compute module, part of cuisto.

+

Contains actual computation functions.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ get_distribution(df, col, hue, hue_filter, per_commonnorm, binlim, nbins=100) + +#

+ + +
+ +

Computes distribution of objects.

+

A global distribution using only col is computed, then it computes a distribution +distinguishing values in the hue column. For the latter, it is possible to use a +subset of the data ony, based on another column using hue_filter. This another +column is determined with hue, if the latter is "hemisphere", then hue_filter is +used in the "channel" color and vice-versa. +per_commonnorm controls how they are normalized, either as a whole (True) or +independantly (False).

+

Use cases : +(1) single-channel, two hemispheres : col=x, hue=hemisphere, hue_filter="", +per_commonorm=True. Computes a distribution for each hemisphere, the sum of the +area of both is equal to 1. +(2) three-channels, one hemisphere : col=x, hue=channel, +hue_filter="Ipsi.", per_commonnorm=False. Computes a distribution for each channel +only for points in the ipsilateral hemisphere. Each curve will have an area of 1.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ col + + str + +
+

Key in df, used to compute the distributions.

+
+
+ required +
+ hue + + str + +
+

Key in df. Criterion for additional distributions.

+
+
+ required +
+ hue_filter + + str + +
+

Further filtering for "per" distribution. +- hue = channel : value is the name of one of the hemisphere +- hue = hemisphere : value can be the name of a channel, a list of such or "all"

+
+
+ required +
+ per_commonnorm + + bool + +
+

Use common normalization for all hues (per argument).

+
+
+ required +
+ binlim + + list or tuple + +
+

First bin left edge and last bin right edge.

+
+
+ required +
+ nbins + + int + +
+

Number of bins. Default is 100.

+
+
+ 100 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df_distribution + DataFrame + +
+

DataFrame with bins, distribution, count and their per-hemisphere or +per-channel variants.

+
+
+ +
+ Source code in cuisto/compute.py +
def get_distribution(
+    df: pd.DataFrame,
+    col: str,
+    hue: str,
+    hue_filter: dict,
+    per_commonnorm: bool,
+    binlim: tuple | list,
+    nbins=100,
+) -> pd.DataFrame:
+    """
+    Computes distribution of objects.
+
+    A global distribution using only `col` is computed, then it computes a distribution
+    distinguishing values in the `hue` column. For the latter, it is possible to use a
+    subset of the data ony, based on another column using `hue_filter`. This another
+    column is determined with `hue`, if the latter is "hemisphere", then `hue_filter` is
+    used in the "channel" color and vice-versa.
+    `per_commonnorm` controls how they are normalized, either as a whole (True) or
+    independantly (False).
+
+    Use cases :
+    (1) single-channel, two hemispheres : `col=x`, `hue=hemisphere`, `hue_filter=""`,
+    `per_commonorm=True`. Computes a distribution for each hemisphere, the sum of the
+    area of both is equal to 1.
+    (2) three-channels, one hemisphere : `col=x`, hue=`channel`,
+    `hue_filter="Ipsi.", per_commonnorm=False`. Computes a distribution for each channel
+    only for points in the ipsilateral hemisphere. Each curve will have an area of 1.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    col : str
+        Key in `df`, used to compute the distributions.
+    hue : str
+        Key in `df`. Criterion for additional distributions.
+    hue_filter : str
+        Further filtering for "per" distribution.
+        - hue = channel : value is the name of one of the hemisphere
+        - hue = hemisphere : value can be the name of a channel, a list of such or "all"
+    per_commonnorm : bool
+        Use common normalization for all hues (per argument).
+    binlim : list or tuple
+        First bin left edge and last bin right edge.
+    nbins : int, optional
+        Number of bins. Default is 100.
+
+    Returns
+    -------
+    df_distribution : pandas.DataFrame
+        DataFrame with `bins`, `distribution`, `count` and their per-hemisphere or
+        per-channel variants.
+
+    """
+
+    # - Preparation
+    bin_edges = np.linspace(*binlim, nbins + 1)  # create bins
+    df_distribution = []  # prepare list of distributions
+
+    # - Both hemispheres, all channels
+    # get raw count per bins (histogram)
+    count, bin_edges = np.histogram(df[col], bin_edges)
+    # get normalized count (pdf)
+    distribution, _ = np.histogram(df[col], bin_edges, density=True)
+    # get bin centers rather than edges to plot them
+    bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2
+
+    # make a DataFrame out of that
+    df_distribution.append(
+        pd.DataFrame(
+            {
+                "bins": bin_centers,
+                "distribution": distribution,
+                "count": count,
+                "hemisphere": "both",
+                "channel": "all",
+                "axis": col,  # keep track of what col. was used
+            }
+        )
+    )
+
+    # - Per additional criterion
+    # select data
+    df_sub = select_hemisphere_channel(df, hue, hue_filter, False)
+    hue_values = df[hue].unique()  # get grouping values
+    # total number of datapoints in the subset used for additional distribution
+    length_total = len(df_sub)
+
+    for value in hue_values:
+        # select part and coordinates
+        df_part = df_sub.loc[df_sub[hue] == value, col]
+
+        # get raw count per bins (histogram)
+        count, bin_edges = np.histogram(df_part, bin_edges)
+        # get normalized count (pdf)
+        distribution, _ = np.histogram(df_part, bin_edges, density=True)
+
+        if per_commonnorm:
+            # re-normalize so that the sum of areas of all sub-parts is 1
+            length_part = len(df_part)  # number of datapoints in that hemisphere
+            distribution *= length_part / length_total
+
+        # get bin centers rather than edges to plot them
+        bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2
+
+        # make a DataFrame out of that
+        df_distribution.append(
+            pd.DataFrame(
+                {
+                    "bins": bin_centers,
+                    "distribution": distribution,
+                    "count": count,
+                    hue: value,
+                    "channel" if hue == "hemisphere" else "hemisphere": hue_filter,
+                    "axis": col,  # keep track of what col. was used
+                }
+            )
+        )
+
+    return pd.concat(df_distribution)
+
+
+
+ +
+ +
+ + +

+ get_regions_metrics(df_annotations, object_type, channel_names, meas_base_name, metrics_names) + +#

+ + +
+ +

Get a new DataFrame with cumulated axons segments length in each brain regions.

+

This is the quantification per brain regions for fibers-like objects, eg. axons. The +returned DataFrame has columns "cum. length µm", "cum. length mm", "density µm^-1", +"density mm^-1", "coverage index".

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df_annotations + + DataFrame + +
+

DataFrame with an entry for each brain regions, with columns "Area µm^2", +"Name", "hemisphere", and "{object_type: channel} Length µm".

+
+
+ required +
+ object_type + + str + +
+

Object type (primary classification).

+
+
+ required +
+ channel_names + + dict + +
+

Map between original channel names to something else.

+
+
+ required +
+ meas_base_name + + str + +
+ +
+
+ required +
+ metrics_names + + dict + +
+ +
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df_regions + DataFrame + +
+

DataFrame with brain regions name, area and metrics.

+
+
+ +
+ Source code in cuisto/compute.py +
def get_regions_metrics(
+    df_annotations: pd.DataFrame,
+    object_type: str,
+    channel_names: dict,
+    meas_base_name: str,
+    metrics_names: dict,
+) -> pd.DataFrame:
+    """
+    Get a new DataFrame with cumulated axons segments length in each brain regions.
+
+    This is the quantification per brain regions for fibers-like objects, eg. axons. The
+    returned DataFrame has columns "cum. length µm", "cum. length mm", "density µm^-1",
+    "density mm^-1", "coverage index".
+
+    Parameters
+    ----------
+    df_annotations : pandas.DataFrame
+        DataFrame with an entry for each brain regions, with columns "Area µm^2",
+        "Name", "hemisphere", and "{object_type: channel} Length µm".
+    object_type : str
+        Object type (primary classification).
+    channel_names : dict
+        Map between original channel names to something else.
+    meas_base_name : str
+    metrics_names : dict
+
+    Returns
+    -------
+    df_regions : pandas.DataFrame
+        DataFrame with brain regions name, area and metrics.
+
+    """
+    # get columns names
+    cols = df_annotations.columns
+    # get columns with fibers lengths
+    cols_colors = cols[
+        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)
+    ]
+    # select relevant data
+    cols_to_select = pd.Index(["Name", "hemisphere", "Area µm^2"]).append(cols_colors)
+    # sum lengths and areas of each brain regions
+    df_regions = (
+        df_annotations[cols_to_select]
+        .groupby(["Name", "hemisphere"])
+        .sum()
+        .reset_index()
+    )
+
+    # get measurement for both hemispheres (sum)
+    df_both = df_annotations[cols_to_select].groupby(["Name"]).sum().reset_index()
+    df_both["hemisphere"] = "both"
+    df_regions = (
+        pd.concat([df_regions, df_both], ignore_index=True)
+        .sort_values(by="Name")
+        .reset_index()
+        .drop(columns="index")
+    )
+
+    # rename measurement columns to lower case
+    df_regions = df_regions.rename(
+        columns={
+            k: k.replace(meas_base_name, meas_base_name.lower()) for k in cols_colors
+        }
+    )
+
+    # update names
+    meas_base_name = meas_base_name.lower()
+    cols = df_regions.columns
+    cols_colors = cols[
+        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)
+    ]
+
+    # convert area in mm^2
+    df_regions["Area mm^2"] = df_regions["Area µm^2"] / 1e6
+
+    # prepare metrics
+    if "µm" in meas_base_name:
+        # fibers : convert to mm
+        cols_to_convert = pd.Index([col for col in cols_colors if "µm" in col])
+        df_regions[cols_to_convert.str.replace("µm", "mm")] = (
+            df_regions[cols_to_convert] / 1000
+        )
+        metrics = [meas_base_name, meas_base_name.replace("µm", "mm")]
+    else:
+        # objects : count
+        metrics = [meas_base_name]
+
+    # density = measurement / area
+    metric = metrics_names["density µm^-2"]
+    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[
+        cols_colors
+    ].divide(df_regions["Area µm^2"], axis=0)
+    metrics.append(metric)
+    metric = metrics_names["density mm^-2"]
+    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[
+        cols_colors
+    ].divide(df_regions["Area mm^2"], axis=0)
+    metrics.append(metric)
+
+    # coverage index = measurement² / area
+    metric = metrics_names["coverage index"]
+    df_regions[cols_colors.str.replace(meas_base_name, metric)] = (
+        df_regions[cols_colors].pow(2).divide(df_regions["Area µm^2"], axis=0)
+    )
+    metrics.append(metric)
+
+    # prepare relative metrics columns
+    metric = metrics_names["relative measurement"]
+    cols_rel_meas = cols_colors.str.replace(meas_base_name, metric)
+    df_regions[cols_rel_meas] = np.nan
+    metrics.append(metric)
+    metric = metrics_names["relative density"]
+    cols_dens = cols_colors.str.replace(meas_base_name, metrics_names["density mm^-2"])
+    cols_rel_dens = cols_colors.str.replace(meas_base_name, metric)
+    df_regions[cols_rel_dens] = np.nan
+    metrics.append(metric)
+    # relative metrics should be defined within each hemispheres (left, right, both)
+    for hemisphere in df_regions["hemisphere"].unique():
+        row_indexer = df_regions["hemisphere"] == hemisphere
+
+        # relative measurement = measurement / total measurement
+        df_regions.loc[row_indexer, cols_rel_meas] = (
+            df_regions.loc[row_indexer, cols_colors]
+            .divide(df_regions.loc[row_indexer, cols_colors].sum())
+            .to_numpy()
+        )
+
+        # relative density = density / total density
+        df_regions.loc[row_indexer, cols_rel_dens] = (
+            df_regions.loc[
+                row_indexer,
+                cols_dens,
+            ]
+            .divide(df_regions.loc[row_indexer, cols_dens].sum())
+            .to_numpy()
+        )
+
+    # collect channel names
+    channels = (
+        cols_colors.str.replace(object_type + ": ", "")
+        .str.replace(" " + meas_base_name, "")
+        .values.tolist()
+    )
+    # collect measurements columns names
+    cols_metrics = df_regions.columns.difference(
+        pd.Index(["Name", "hemisphere", "Area µm^2", "Area mm^2"])
+    )
+    for metric in metrics:
+        cols_to_cat = [f"{object_type}: {cn} {metric}" for cn in channels]
+        # make sure it's part of available metrics
+        if not set(cols_to_cat) <= set(cols_metrics):
+            raise ValueError(f"{cols_to_cat} not in DataFrame.")
+        # group all colors in the same colors
+        df_regions[metric] = df_regions[cols_to_cat].values.tolist()
+        # remove original data
+        df_regions = df_regions.drop(columns=cols_to_cat)
+
+    # add a color tag, given their names in the configuration file
+    df_regions["channel"] = len(df_regions) * [[channel_names[k] for k in channels]]
+    metrics.append("channel")
+
+    # explode the dataframe so that each color has an entry
+    df_regions = df_regions.explode(metrics)
+
+    return df_regions
+
+
+
+ +
+ +
+ + +

+ normalize_starter_cells(df, cols, animal, info_file, channel_names) + +#

+ + +
+ +

Normalize data by the number of starter cells.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

Contains the data to be normalized.

+
+
+ required +
+ cols + + list - like + +
+

Columns to divide by the number of starter cells.

+
+
+ required +
+ animal + + str + +
+

Animal ID to parse the number of starter cells.

+
+
+ required +
+ info_file + + str + +
+

Full path to the TOML file with informations.

+
+
+ required +
+ channel_names + + dict + +
+

Map between original channel names to something else.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ DataFrame + +
+

Same df with normalized count.

+
+
+ +
+ Source code in cuisto/compute.py +
def normalize_starter_cells(
+    df: pd.DataFrame, cols: list[str], animal: str, info_file: str, channel_names: dict
+) -> pd.DataFrame:
+    """
+    Normalize data by the number of starter cells.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        Contains the data to be normalized.
+    cols : list-like
+        Columns to divide by the number of starter cells.
+    animal : str
+        Animal ID to parse the number of starter cells.
+    info_file : str
+        Full path to the TOML file with informations.
+    channel_names : dict
+        Map between original channel names to something else.
+
+    Returns
+    -------
+    pd.DataFrame
+        Same `df` with normalized count.
+
+    """
+    for channel in df["channel"].unique():
+        # inverse mapping channel colors : names
+        reverse_channels = {v: k for k, v in channel_names.items()}
+        nstarters = get_starter_cells(animal, reverse_channels[channel], info_file)
+
+        for col in cols:
+            df.loc[df["channel"] == channel, col] = (
+                df.loc[df["channel"] == channel, col] / nstarters
+            )
+
+    return df
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-config-config.html b/api-config-config.html new file mode 100644 index 0000000..fae30ca --- /dev/null +++ b/api-config-config.html @@ -0,0 +1,1294 @@ + + + + + + + + + + + + + + + + + + + + + + + Api config config - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Api config config

+ +

object_type : name of QuPath base classification (eg. without the ": subclass" part) +segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

+

atlas

+

Information related to the atlas used

+

name : brainglobe-atlasapi atlas name
+type : "brain" or "cord" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps.
+midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates.
+outline_structures : structures to show an outline of in heatmaps

+

channels

+

Information related to imaging channels

+

names

+

Must contain all classifications derived from "object_type" you want to process. In the form subclassification name = name to display on the plots

+

"marker+" : classification name = name to display
+"marker-" : add any number of sub-classification

+

colors

+

Must have same keys as "names" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

+

"marker+" : classification name = matplotlib color
+"marker-" : must have the same entries as "names".

+

hemispheres

+

Information related to hemispheres, same structure as channels

+

names

+ +

Left : Left = name to display
+Right : Right = name to display

+

colors

+

Must have same keys as names' keys

+

Left : ff516e" # Left = matplotlib color (either #hex, color name or RGB list)
+Right : 960010" # Right = matplotlib color

+

distributions

+

Spatial distributions parameters

+

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3)
+ap_lim : bins limits for anterio-posterior in mm
+ap_nbins : number of bins for anterio-posterior
+dv_lim : bins limits for dorso-ventral in mm
+dv_nbins : number of bins for dorso-ventral
+ml_lim : bins limits for medio-lateral in mm
+ml_nbins : number of bins for medio-lateral
+hue : color curves with this parameter, must be "hemisphere" or "channel"
+hue_filter : use only a subset of data

+
    +
  • If hue=hemisphere : it should be a channel name, a list of such or "all"
  • +
  • If hue=channel : it should be a hemisphere name or "both"
  • +
+

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

+

display

+

Display parameters

+

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up +cmap : matplotlib color map for 2D heatmaps +cmap_nbins : number of bins for 2D heatmaps +cmap_lim : color limits for 2D heatmaps

+

regions

+

Distributions per regions parameters

+

base_measurement : the name of the measurement in QuPath to derive others from. Usually "Count" or "Length µm"
+hue : color bars with this parameter, must be "hemisphere" or "channel"
+hue_filter : use only a subset of data

+
    +
  • If hue=hemisphere : it should be a channel name, a list of such or "all"
  • +
  • If hue=channel : it should be a hemisphere name or "both"
  • +
+

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter="both", plots the two hemisphere in mirror.
+normalize_starter_cells : normalize non-relative metrics by the number of starter cells

+

metrics

+

Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

+

"density µm^-2" : relevant name
+"density mm^-2" : relevant name
+"coverage index" : relevant name
+"relative measurement" : relevant name
+"relative density" : relevant name

+

display

+ +

nregions : number of regions to display (sorted by max.)
+orientation : orientation of the bars ("h" or "v")
+order : order the regions by "ontology" or by "max". Set to "max" to provide a custom order
+dodge : enforce the bar not being stacked
+log_scale : use log. scale for metrics

+
metrics
+

name of metrics to display

+

"count" : real_name = display_name, with real_name the "values" in [regions.metrics] +"density mm^-2"

+

files

+

Full path to information TOML files and atlas outlines for 2D heatmaps.

+

blacklist
+fusion
+outlines
+infos

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-config.html b/api-config.html new file mode 100644 index 0000000..4704726 --- /dev/null +++ b/api-config.html @@ -0,0 +1,1930 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.config - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

cuisto.config

+ +
+ + + + +
+ +

config module, part of cuisto.

+

Contains the Config class.

+ + + + + + + + +
+ + + + + + + + +
+ + + +

+ Config(config_file) + +#

+ + +
+ + +

The configuration class.

+

Reads input configuration file and provides its constant.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ config_file + + str + +
+

Full path to the configuration file to load.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
cfg + Config object. + +
+ +
+
+ +

Constructor.

+ + + + + + +
+ Source code in cuisto/config.py +
31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
def __init__(self, config_file):
+    """Constructor."""
+    with open(config_file, "rb") as fid:
+        cfg = tomllib.load(fid)
+
+        for key in cfg:
+            setattr(self, key, cfg[key])
+
+    self.config_file = config_file
+    self.bg_atlas = BrainGlobeAtlas(self.atlas["name"], check_latest=False)
+    self.get_blacklist()
+    self.get_leaves_list()
+
+
+ + + +
+ + + + + + + + + +
+ + +

+ get_blacklist() + +#

+ + +
+ +

Wraps cuisto.utils.get_blacklist.

+ +
+ Source code in cuisto/config.py +
44
+45
+46
+47
+48
+49
def get_blacklist(self):
+    """Wraps cuisto.utils.get_blacklist."""
+
+    self.atlas["blacklist"] = utils.get_blacklist(
+        self.files["blacklist"], self.bg_atlas
+    )
+
+
+
+ +
+ +
+ + +

+ get_hue_palette(mode) + +#

+ + +
+ +

Get color palette given hue.

+

Maps hue to colors in channels or hemispheres.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ mode + + (hemisphere, channel) + +
+ +
+
+ "hemisphere" +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
palette + dict + +
+

Maps a hue level to a color, usable in seaborn.

+
+
+ +
+ Source code in cuisto/config.py +
def get_hue_palette(self, mode: str) -> dict:
+    """
+    Get color palette given hue.
+
+    Maps hue to colors in channels or hemispheres.
+
+    Parameters
+    ----------
+    mode : {"hemisphere", "channel"}
+
+    Returns
+    -------
+    palette : dict
+        Maps a hue level to a color, usable in seaborn.
+
+    """
+    params = getattr(self, mode)
+
+    if params["hue"] == "channel":
+        # replace channels by their new names
+        palette = {
+            self.channels["names"][k]: v for k, v in self.channels["colors"].items()
+        }
+    elif params["hue"] == "hemisphere":
+        # replace hemispheres by their new names
+        palette = {
+            self.hemispheres["names"][k]: v
+            for k, v in self.hemispheres["colors"].items()
+        }
+    else:
+        palette = None
+        warnings.warn(f"hue={self.regions["display"]["hue"]} not supported.")
+
+    return palette
+
+
+
+ +
+ +
+ + +

+ get_injection_sites(animals) + +#

+ + +
+ +

Get list of injection sites coordinates for each animals, for each channels.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ animals + + list of str + +
+

List of animals.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
injection_sites + dict + +
+

{"x": {channel0: [x]}, "y": {channel1: [y]}}

+
+
+ +
+ Source code in cuisto/config.py +
56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
def get_injection_sites(self, animals: list[str]) -> dict:
+    """
+    Get list of injection sites coordinates for each animals, for each channels.
+
+    Parameters
+    ----------
+    animals : list of str
+        List of animals.
+
+    Returns
+    -------
+    injection_sites : dict
+        {"x": {channel0: [x]}, "y": {channel1: [y]}}
+
+    """
+    injection_sites = {
+        axis: {channel: [] for channel in self.channels["names"].keys()}
+        for axis in ["x", "y", "z"]
+    }
+
+    for animal in animals:
+        for channel in self.channels["names"].keys():
+            injx, injy, injz = utils.get_injection_site(
+                animal,
+                self.files["infos"],
+                channel,
+                stereo=self.distributions["stereo"],
+            )
+            if injx is not None:
+                injection_sites["x"][channel].append(injx)
+            if injy is not None:
+                injection_sites["y"][channel].append(injy)
+            if injz is not None:
+                injection_sites["z"][channel].append(injz)
+
+    return injection_sites
+
+
+
+ +
+ +
+ + +

+ get_leaves_list() + +#

+ + +
+ +

Wraps utils.get_leaves_list.

+ +
+ Source code in cuisto/config.py +
51
+52
+53
+54
def get_leaves_list(self):
+    """Wraps utils.get_leaves_list."""
+
+    self.atlas["leaveslist"] = utils.get_leaves_list(self.bg_atlas)
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-display.html b/api-display.html new file mode 100644 index 0000000..9977896 --- /dev/null +++ b/api-display.html @@ -0,0 +1,4626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.display - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

cuisto.display

+ +
+ + + + +
+ +

display module, part of cuisto.

+

Contains display functions, essentially wrapping matplotlib and seaborn functions.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ add_data_coverage(df, ax, colors=None, **kwargs) + +#

+ + +
+ +

Add lines below the plot to represent data coverage.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

DataFrame with X_min and X_max on rows for each animals (on columns).

+
+
+ required +
+ ax + + Axes + +
+

Handle to axes where to add the patch.

+
+
+ required +
+ colors + + list or str or None + +
+

Colors for the patches, as a RGB list or hex list. Should be the same size as +the number of patches to plot, eg. the number of columns in df. If None, +default seaborn colors are used. If only one element, used for each animal.

+
+
+ None +
+ **kwargs + + passed to patches.Rectangle() + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + Axes + +
+

Handle to updated axes.

+
+
+ +
+ Source code in cuisto/display.py +
def add_data_coverage(
+    df: pd.DataFrame, ax: plt.Axes, colors: list | str | None = None, **kwargs
+) -> plt.Axes:
+    """
+    Add lines below the plot to represent data coverage.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+        DataFrame with `X_min` and `X_max` on rows for each animals (on columns).
+    ax : Axes
+        Handle to axes where to add the patch.
+    colors : list or str or None, optional
+        Colors for the patches, as a RGB list or hex list. Should be the same size as
+        the number of patches to plot, eg. the number of columns in `df`. If None,
+        default seaborn colors are used. If only one element, used for each animal.
+    **kwargs : passed to patches.Rectangle()
+
+    Returns
+    -------
+    ax : Axes
+        Handle to updated axes.
+
+    """
+    # get colors
+    ncolumns = len(df.columns)
+    if not colors:
+        colors = sns.color_palette(n_colors=ncolumns)
+    elif isinstance(colors, str) or (isinstance(colors, list) & (len(colors) == 3)):
+        colors = [colors] * ncolumns
+    elif len(colors) != ncolumns:
+        warnings.warn(f"Wrong number of colors ({len(colors)}), using default colors.")
+        colors = sns.color_palette(n_colors=ncolumns)
+
+    # get patch height depending on current axis limits
+    ymin, ymax = ax.get_ylim()
+    height = (ymax - ymin) * 0.02
+
+    for animal, color in zip(df.columns, colors):
+        # get patch coordinates
+        ymin, ymax = ax.get_ylim()
+        ylength = ymax - ymin
+        ybottom = ymin - 0.02 * ylength
+        xleft = df.loc["X_min", animal]
+        xright = df.loc["X_max", animal]
+
+        # plot patch
+        ax.add_patch(
+            patches.Rectangle(
+                (xleft, ybottom),
+                xright - xleft,
+                height,
+                label=animal,
+                color=color,
+                **kwargs,
+            )
+        )
+
+        ax.autoscale(tight=True)  # set new axes limits
+
+    ax.autoscale()  # reset scale
+
+    return ax
+
+
+
+ +
+ +
+ + +

+ add_injection_patch(X, ax, **kwargs) + +#

+ + +
+ +

Add a patch representing the injection sites.

+

The patch will span from the minimal coordinate to the maximal. +If plotted in stereotaxic coordinates, coordinates should be converted beforehand.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ X + + list + +
+

Coordinates in mm for each animals. Can be empty to not plot anything.

+
+
+ required +
+ ax + + Axes + +
+

Handle to axes where to add the patch.

+
+
+ required +
+ **kwargs + + passed to Axes.axvspan + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + Axes + +
+

Handle to updated Axes.

+
+
+ +
+ Source code in cuisto/display.py +
18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
def add_injection_patch(X: list, ax: plt.Axes, **kwargs) -> plt.Axes:
+    """
+    Add a patch representing the injection sites.
+
+    The patch will span from the minimal coordinate to the maximal.
+    If plotted in stereotaxic coordinates, coordinates should be converted beforehand.
+
+    Parameters
+    ----------
+    X : list
+        Coordinates in mm for each animals. Can be empty to not plot anything.
+    ax : Axes
+        Handle to axes where to add the patch.
+    **kwargs : passed to Axes.axvspan
+
+    Returns
+    -------
+    ax : Axes
+        Handle to updated Axes.
+
+    """
+    # plot patch
+    if len(X) > 0:
+        ax.axvspan(min(X), max(X), **kwargs)
+
+    return ax
+
+
+
+ +
+ +
+ + +

+ draw_structure_outline(view='sagittal', structures=['root'], outline_file='', ax=None, microns=False, **kwargs) + +#

+ + +
+ +

Plot brain regions outlines in given projection.

+

This requires a file containing the structures outlines.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ view + + str + +
+

Projection, "sagittal", "coronal" or "top". Default is "sagittal".

+
+
+ 'sagittal' +
+ structures + + list[str] + +
+

List of structures acronyms whose outlines will be drawn. Default is ["root"].

+
+
+ ['root'] +
+ outline_file + + str + +
+

Full path the outlines HDF5 file.

+
+
+ '' +
+ ax + + Axes or None + +
+

Axes where to plot the outlines. If None, get current axes (the default).

+
+
+ None +
+ microns + + bool + +
+

If False (default), converts the coordinates in mm.

+
+
+ False +
+ **kwargs + + passed to pyplot.plot() + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + Axes + +
+ +
+
+ +
+ Source code in cuisto/display.py +
def draw_structure_outline(
+    view: str = "sagittal",
+    structures: list[str] = ["root"],
+    outline_file: str = "",
+    ax: plt.Axes | None = None,
+    microns: bool = False,
+    **kwargs,
+) -> plt.Axes:
+    """
+    Plot brain regions outlines in given projection.
+
+    This requires a file containing the structures outlines.
+
+    Parameters
+    ----------
+    view : str
+        Projection, "sagittal", "coronal" or "top". Default is "sagittal".
+    structures : list[str]
+        List of structures acronyms whose outlines will be drawn. Default is ["root"].
+    outline_file : str
+        Full path the outlines HDF5 file.
+    ax : plt.Axes or None, optional
+        Axes where to plot the outlines. If None, get current axes (the default).
+    microns : bool, optional
+        If False (default), converts the coordinates in mm.
+    **kwargs : passed to pyplot.plot()
+
+    Returns
+    -------
+    ax : plt.Axes
+
+    """
+    # get axes
+    if not ax:
+        ax = plt.gca()
+
+    # get units
+    if microns:
+        conv = 1
+    else:
+        conv = 1 / 1000
+
+    with h5py.File(outline_file) as f:
+        if view == "sagittal":
+            for structure in structures:
+                dsets = f["sagittal"][structure]
+
+                for dset in dsets.values():
+                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)
+
+        if view == "coronal":
+            for structure in structures:
+                dsets = f["coronal"][structure]
+
+                for dset in dsets.values():
+                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)
+
+        if view == "top":
+            for structure in structures:
+                dsets = f["top"][structure]
+
+                for dset in dsets.values():
+                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)
+
+    return ax
+
+
+
+ +
+ +
+ + +

+ nice_bar_plot(df, x='', y=[''], hue='', ylabel=[''], orient='h', nx=None, ordering=None, names_list=None, hue_mirror=False, log_scale=False, bar_kws={}, pts_kws={}) + +#

+ + +
+ +

Nice bar plot of per-region objects distribution.

+

This is used for objects distribution across brain regions. Shows the y metric +(count, aeral density, cumulated length...) in each x categories (brain regions). +orient controls wether the bars are shown horizontally (default) or vertically. +Input df must have an additional "hemisphere" column. All y are plotted in the +same figure as different subplots. nx controls the number of displayed regions.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ x + + str + +
+

Key in df.

+
+
+ '' +
+ y + + str + +
+

Key in df.

+
+
+ '' +
+ hue + + str + +
+

Key in df.

+
+
+ '' +
+ ylabel + + list of str + +
+

Y axis labels.

+
+
+ [''] +
+ orient + + h or v + +
+

"h" for horizontal bars (default) or "v" for vertical bars.

+
+
+ 'h' +
+ nx + + None or int + +
+

Number of x to show in the plot. Default is None (no limit).

+
+
+ None +
+ ordering + + None or list[str] or max + +
+

Sorted list of acronyms. Data will be sorted follwowing this order, if "max", +sorted by descending values, if None, not sorted (default).

+
+
+ None +
+ names_list + + list or None + +
+

List of names to display. If None (default), takes the most prominent overall +ones.

+
+
+ None +
+ hue_mirror + + bool + +
+

If there are 2 groups, plot in mirror. Default is False.

+
+
+ False +
+ log_scale + + bool + +
+

Set the metrics in log scale. Default is False.

+
+
+ False +
+ bar_kws + + dict + +
+

Passed to seaborn.barplot().

+
+
+ {} +
+ pts_kws + + dict + +
+

Passed to seaborn.stripplot().

+
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
figs + list + +
+

List of figures.

+
+
+ +
+ Source code in cuisto/display.py +
def nice_bar_plot(
+    df: pd.DataFrame,
+    x: str = "",
+    y: list[str] = [""],
+    hue: str = "",
+    ylabel: list[str] = [""],
+    orient="h",
+    nx: None | int = None,
+    ordering: None | list[str] | str = None,
+    names_list: None | list = None,
+    hue_mirror: bool = False,
+    log_scale: bool = False,
+    bar_kws: dict = {},
+    pts_kws: dict = {},
+) -> list[plt.Axes]:
+    """
+    Nice bar plot of per-region objects distribution.
+
+    This is used for objects distribution across brain regions. Shows the `y` metric
+    (count, aeral density, cumulated length...) in each `x` categories (brain regions).
+    `orient` controls wether the bars are shown horizontally (default) or vertically.
+    Input `df` must have an additional "hemisphere" column. All `y` are plotted in the
+    same figure as different subplots. `nx` controls the number of displayed regions.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    x, y, hue : str
+        Key in `df`.
+    ylabel : list of str
+        Y axis labels.
+    orient : "h" or "v", optional
+        "h" for horizontal bars (default) or "v" for vertical bars.
+    nx : None or int, optional
+        Number of `x` to show in the plot. Default is None (no limit).
+    ordering : None or list[str] or "max", optional
+        Sorted list of acronyms. Data will be sorted follwowing this order, if "max",
+        sorted by descending values, if None, not sorted (default).
+    names_list : list or None, optional
+        List of names to display. If None (default), takes the most prominent overall
+        ones.
+    hue_mirror : bool, optional
+        If there are 2 groups, plot in mirror. Default is False.
+    log_scale : bool, optional
+        Set the metrics in log scale. Default is False.
+    bar_kws : dict
+        Passed to seaborn.barplot().
+    pts_kws : dict
+        Passed to seaborn.stripplot().
+
+    Returns
+    -------
+    figs : list
+        List of figures.
+
+    """
+    figs = []
+    # loop for each features
+    for yi, ylabeli in zip(y, ylabel):
+        # prepare data
+        # get nx first most prominent regions
+        if not names_list:
+            names_list_plt = (
+                df.groupby(["Name"])[yi].mean().sort_values(ascending=False).index[0:nx]
+            )
+        else:
+            names_list_plt = names_list
+        dfplt = df[df["Name"].isin(names_list_plt)]  # limit to those regions
+        # limit hierarchy list if provided
+        if isinstance(ordering, list):
+            order = [el for el in ordering if el in names_list_plt]
+        elif ordering == "max":
+            order = names_list_plt
+        else:
+            order = None
+
+        # reorder keys depending on orientation and create axes
+        if orient == "h":
+            xp = yi
+            yp = x
+            if hue_mirror:
+                nrows = 1
+                ncols = 2
+                sharex = None
+                sharey = "all"
+            else:
+                nrows = 1
+                ncols = 1
+                sharex = None
+                sharey = None
+        elif orient == "v":
+            xp = x
+            yp = yi
+            if hue_mirror:
+                nrows = 2
+                ncols = 1
+                sharex = "all"
+                sharey = None
+            else:
+                nrows = 1
+                ncols = 1
+                sharex = None
+                sharey = None
+        fig, axs = plt.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey)
+
+        if hue_mirror:
+            # two graphs
+            ax1, ax2 = axs
+            # determine what will be mirrored
+            if hue == "channel":
+                hue_filter = "hemisphere"
+            elif hue == "hemisphere":
+                hue_filter = "channel"
+            # select the two types (should be left/right or two channels)
+            hue_filters = dfplt[hue_filter].unique()[0:2]
+            hue_filters.sort()  # make sure it will be always in the same order
+
+            # plot
+            for filt, ax in zip(hue_filters, [ax1, ax2]):
+                dfplt2 = dfplt[dfplt[hue_filter] == filt]
+                ax = sns.barplot(
+                    dfplt2,
+                    x=xp,
+                    y=yp,
+                    hue=hue,
+                    estimator="mean",
+                    errorbar="se",
+                    orient=orient,
+                    order=order,
+                    ax=ax,
+                    **bar_kws,
+                )
+                # add points
+                ax = sns.stripplot(
+                    dfplt2, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws
+                )
+
+                # cosmetics
+                if orient == "h":
+                    ax.set_title(f"{hue_filter}: {filt}")
+                    ax.set_ylabel(None)
+                    ax.set_ylim((nx + 0.5, -0.5))
+                    if log_scale:
+                        ax.set_xscale("log")
+
+                elif orient == "v":
+                    if ax == ax1:
+                        # top title
+                        ax1.set_title(f"{hue_filter}: {filt}")
+                        ax.set_xlabel(None)
+                    elif ax == ax2:
+                        # use xlabel as bottom title
+                        ax2.set_xlabel(
+                            f"{hue_filter}: {filt}", fontsize=ax1.title.get_fontsize()
+                        )
+                    ax.set_xlim((-0.5, nx + 0.5))
+                    if log_scale:
+                        ax.set_yscale("log")
+
+                    for label in ax.get_xticklabels():
+                        label.set_verticalalignment("center")
+                        label.set_horizontalalignment("center")
+
+            # tune axes cosmetics
+            if orient == "h":
+                ax1.set_xlabel(ylabeli)
+                ax2.set_xlabel(ylabeli)
+                ax1.set_xlim(
+                    ax1.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))
+                )
+                ax2.set_xlim(
+                    ax2.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))
+                )
+                ax1.invert_xaxis()
+                sns.despine(ax=ax1, left=True, top=True, right=False, bottom=False)
+                sns.despine(ax=ax2, left=False, top=True, right=True, bottom=False)
+                ax1.yaxis.tick_right()
+                ax1.tick_params(axis="y", pad=20)
+                for label in ax1.get_yticklabels():
+                    label.set_verticalalignment("center")
+                    label.set_horizontalalignment("center")
+            elif orient == "v":
+                ax2.set_ylabel(ylabeli)
+                ax1.set_ylim(
+                    ax1.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))
+                )
+                ax2.set_ylim(
+                    ax2.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))
+                )
+                ax2.invert_yaxis()
+                sns.despine(ax=ax1, left=False, top=True, right=True, bottom=False)
+                sns.despine(ax=ax2, left=False, top=False, right=True, bottom=True)
+                for label in ax2.get_xticklabels():
+                    label.set_verticalalignment("center")
+                    label.set_horizontalalignment("center")
+                ax2.tick_params(axis="x", labelrotation=90, pad=20)
+
+        else:
+            # one graph
+            ax = axs
+            # plot
+            ax = sns.barplot(
+                dfplt,
+                x=xp,
+                y=yp,
+                hue=hue,
+                estimator="mean",
+                errorbar="se",
+                orient=orient,
+                order=order,
+                ax=ax,
+                **bar_kws,
+            )
+            # add points
+            ax = sns.stripplot(
+                dfplt, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws
+            )
+
+            # cosmetics
+            if orient == "h":
+                ax.set_xlabel(ylabeli)
+                ax.set_ylabel(None)
+                ax.set_ylim((nx + 0.5, -0.5))
+                if log_scale:
+                    ax.set_xscale("log")
+            elif orient == "v":
+                ax.set_xlabel(None)
+                ax.set_ylabel(ylabeli)
+                ax.set_xlim((-0.5, nx + 0.5))
+                if log_scale:
+                    ax.set_yscale("log")
+
+        fig.tight_layout(pad=0)
+        figs.append(fig)
+
+    return figs
+
+
+
+ +
+ +
+ + +

+ nice_distribution_plot(df, x='', y='', hue=None, xlabel='', ylabel='', injections_sites={}, channel_colors={}, channel_names={}, ax=None, **kwargs) + +#

+ + +
+ +

Nice plot of 1D distribution of objects.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ x + + str + +
+

Keys in df.

+
+
+ '' +
+ y + + str + +
+

Keys in df.

+
+
+ '' +
+ hue + + str or None + +
+

Key in df. If None, no hue is used.

+
+
+ None +
+ xlabel + + str + +
+

X and Y axes labels.

+
+
+ '' +
+ ylabel + + str + +
+

X and Y axes labels.

+
+
+ '' +
+ injections_sites + + dict + +
+

List of injection sites 1D coordinates in a dict with the channel name as key. +If empty, injection site is not plotted (default).

+
+
+ {} +
+ channel_colors + + dict + +
+

Required if injections_sites is not empty, dict mapping channel names to a +color.

+
+
+ {} +
+ channel_names + + dict + +
+

Required if injections_sites is not empty, dict mapping channel names to a +display name.

+
+
+ {} +
+ ax + + Axes or None + +
+

Axes in which to plot the figure, if None, a new figure is created (default).

+
+
+ None +
+ **kwargs + + passed to seaborn.lineplot() + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + matplotlib axes + +
+

Handle to axes.

+
+
+ +
+ Source code in cuisto/display.py +
def nice_distribution_plot(
+    df: pd.DataFrame,
+    x: str = "",
+    y: str = "",
+    hue: str | None = None,
+    xlabel: str = "",
+    ylabel: str = "",
+    injections_sites: dict = {},
+    channel_colors: dict = {},
+    channel_names: dict = {},
+    ax: plt.Axes | None = None,
+    **kwargs,
+) -> plt.Axes:
+    """
+    Nice plot of 1D distribution of objects.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    x, y : str
+        Keys in `df`.
+    hue : str or None, optional
+        Key in `df`. If None, no hue is used.
+    xlabel, ylabel : str
+        X and Y axes labels.
+    injections_sites : dict, optional
+        List of injection sites 1D coordinates in a dict with the channel name as key.
+        If empty, injection site is not plotted (default).
+    channel_colors : dict, optional
+        Required if injections_sites is not empty, dict mapping channel names to a
+        color.
+    channel_names : dict, optional
+        Required if injections_sites is not empty, dict mapping channel names to a
+        display name.
+    ax : Axes or None, optional
+        Axes in which to plot the figure, if None, a new figure is created (default).
+    **kwargs : passed to seaborn.lineplot()
+
+    Returns
+    -------
+    ax : matplotlib axes
+        Handle to axes.
+
+    """
+    if not ax:
+        # create figure
+        _, ax = plt.subplots(figsize=(10, 6))
+
+    ax = sns.lineplot(
+        df,
+        x=x,
+        y=y,
+        hue=hue,
+        estimator="mean",
+        errorbar="se",
+        ax=ax,
+        **kwargs,
+    )
+
+    for channel in injections_sites.keys():
+        ax = add_injection_patch(
+            injections_sites[channel],
+            ax,
+            color=channel_colors[channel],
+            edgecolor=None,
+            alpha=0.25,
+            label=channel_names[channel] + ": inj. site",
+        )
+
+    ax.legend()
+    ax.set_xlabel(xlabel)
+    ax.set_ylabel(ylabel)
+
+    return ax
+
+
+
+ +
+ +
+ + +

+ nice_heatmap(df, animals, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, **kwargs) + +#

+ + +
+ +

Nice plots of 2D distribution of boutons as a heatmap per animal.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ animals + + list-like of str + +
+

List of animals.

+
+
+ required +
+ x + + str + +
+

Keys in df.

+
+
+ '' +
+ y + + str + +
+

Keys in df.

+
+
+ '' +
+ xlabel + + str + +
+

Labels of x and y axes.

+
+
+ '' +
+ ylabel + + str + +
+

Labels of x and y axes.

+
+
+ '' +
+ invertx + + bool + +
+

Wether to inverse the x or y axes. Default is False.

+
+
+ False +
+ inverty + + bool + +
+

Wether to inverse the x or y axes. Default is False.

+
+
+ False +
+ **kwargs + + passed to seaborn.histplot() + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + Axes or list of Axes + +
+

Handle to axes.

+
+
+ +
+ Source code in cuisto/display.py +
def nice_heatmap(
+    df: pd.DataFrame,
+    animals: tuple[str] | list[str],
+    x: str = "",
+    y: str = "",
+    xlabel: str = "",
+    ylabel: str = "",
+    invertx: bool = False,
+    inverty: bool = False,
+    **kwargs,
+) -> list[plt.Axes] | plt.Axes:
+    """
+    Nice plots of 2D distribution of boutons as a heatmap per animal.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    animals : list-like of str
+        List of animals.
+    x, y : str
+        Keys in `df`.
+    xlabel, ylabel : str
+        Labels of x and y axes.
+    invertx, inverty : bool, optional
+        Wether to inverse the x or y axes. Default is False.
+    **kwargs : passed to seaborn.histplot()
+
+    Returns
+    -------
+    ax : Axes or list of Axes
+        Handle to axes.
+
+    """
+
+    # 2D distribution, per animal
+    _, axs = plt.subplots(len(animals), 1, sharex="all")
+
+    for animal, ax in zip(animals, axs):
+        ax = sns.histplot(
+            df[df["animal"] == animal],
+            x=x,
+            y=y,
+            ax=ax,
+            **kwargs,
+        )
+        ax.set_xlabel(xlabel)
+        ax.set_ylabel(ylabel)
+        ax.set_title(animal)
+
+        if inverty:
+            ax.invert_yaxis()
+
+    if invertx:
+        axs[-1].invert_xaxis()  # only once since all x axes are shared
+
+    return axs
+
+
+
+ +
+ +
+ + +

+ nice_joint_plot(df, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, outline_kws={}, ax=None, **kwargs) + +#

+ + +
+ +

Joint distribution.

+

Used to display a 2D heatmap of objects. This is more qualitative than quantitative, +for display purposes.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ x + + str + +
+

Keys in df.

+
+
+ '' +
+ y + + str + +
+

Keys in df.

+
+
+ '' +
+ xlabel + + str + +
+

Label of x and y axes.

+
+
+ '' +
+ ylabel + + str + +
+

Label of x and y axes.

+
+
+ '' +
+ invertx + + bool + +
+

Whether to inverse the x or y axes. Default is False for both.

+
+
+ False +
+ inverty + + bool + +
+

Whether to inverse the x or y axes. Default is False for both.

+
+
+ False +
+ outline_kws + + dict + +
+

Passed to draw_structure_outline().

+
+
+ {} +
+ ax + + Axes or None + +
+

Axes to plot in. If None, draws in current axes (default).

+
+
+ None +
+ **kwargs + + +
+

Passed to seaborn.histplot.

+
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
ax + Axes + +
+ +
+
+ +
+ Source code in cuisto/display.py +
def nice_joint_plot(
+    df: pd.DataFrame,
+    x: str = "",
+    y: str = "",
+    xlabel: str = "",
+    ylabel: str = "",
+    invertx: bool = False,
+    inverty: bool = False,
+    outline_kws: dict = {},
+    ax: plt.Axes | None = None,
+    **kwargs,
+) -> plt.Figure:
+    """
+    Joint distribution.
+
+    Used to display a 2D heatmap of objects. This is more qualitative than quantitative,
+    for display purposes.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    x, y : str
+        Keys in `df`.
+    xlabel, ylabel : str
+        Label of x and y axes.
+    invertx, inverty : bool, optional
+        Whether to inverse the x or y axes. Default is False for both.
+    outline_kws : dict
+        Passed to draw_structure_outline().
+    ax : plt.Axes or None, optional
+        Axes to plot in. If None, draws in current axes (default).
+    **kwargs
+        Passed to seaborn.histplot.
+
+    Returns
+    -------
+    ax : plt.Axes
+
+    """
+    if not ax:
+        ax = plt.gca()
+
+    # plot outline
+    draw_structure_outline(ax=ax, **outline_kws)
+
+    # plot joint distribution
+    sns.histplot(
+        df,
+        x=x,
+        y=y,
+        ax=ax,
+        **kwargs,
+    )
+
+    # adjust axes
+    if invertx:
+        ax.invert_xaxis()
+    if inverty:
+        ax.invert_yaxis()
+
+    # labels
+    ax.set_xlabel(xlabel)
+    ax.set_ylabel(ylabel)
+
+    return ax
+
+
+
+ +
+ +
+ + +

+ plot_1D_distributions(dfs_distributions, cfg, df_coordinates=None) + +#

+ + +
+ +

Wraps nice_distribution_plot().

+ +
+ Source code in cuisto/display.py +
def plot_1D_distributions(
+    dfs_distributions: list[pd.DataFrame],
+    cfg,
+    df_coordinates: pd.DataFrame = None,
+):
+    """
+    Wraps nice_distribution_plot().
+    """
+    # prepare figures
+    fig, axs_dist = plt.subplots(1, 3, sharey=True, figsize=(13, 6))
+    xlabels = [
+        "Rostro-caudal position (mm)",
+        "Dorso-ventral position (mm)",
+        "Medio-lateral position (mm)",
+    ]
+
+    # get animals
+    animals = []
+    for df in dfs_distributions:
+        animals.extend(df["animal"].unique())
+    animals = set(animals)
+
+    # get injection sites
+    if cfg.distributions["display"]["show_injection"]:
+        injection_sites = cfg.get_injection_sites(animals)
+    else:
+        injection_sites = {k: {} for k in range(3)}
+
+    # get color palette based on hue
+    hue = cfg.distributions["hue"]
+    palette = cfg.get_hue_palette("distributions")
+
+    # loop through each axis
+    for df_dist, ax_dist, xlabel, inj_sites in zip(
+        dfs_distributions, axs_dist, xlabels, injection_sites.values()
+    ):
+        # select data
+        if cfg.distributions["hue"] == "hemisphere":
+            dfplt = df_dist[df_dist["hemisphere"] != "both"]
+        elif cfg.distributions["hue"] == "channel":
+            dfplt = df_dist[df_dist["channel"] != "all"]
+
+        # plot
+        ax_dist = nice_distribution_plot(
+            dfplt,
+            x="bins",
+            y="distribution",
+            hue=hue,
+            xlabel=xlabel,
+            ylabel="normalized distribution",
+            injections_sites=inj_sites,
+            channel_colors=cfg.channels["colors"],
+            channel_names=cfg.channels["names"],
+            linewidth=2,
+            palette=palette,
+            ax=ax_dist,
+        )
+
+        # add data coverage
+        if ("Atlas_AP" in df_dist["axis"].unique()) & (df_coordinates is not None):
+            df_coverage = utils.get_data_coverage(df_coordinates)
+            ax_dist = add_data_coverage(df_coverage, ax_dist, edgecolor=None, alpha=0.5)
+            ax_dist.legend()
+        else:
+            ax_dist.legend().remove()
+
+    # - Distributions, per animal
+    if len(animals) > 1:
+        _, axs_dist = plt.subplots(1, 3, sharey=True)
+
+        # loop through each axis
+        for df_dist, ax_dist, xlabel, inj_sites in zip(
+            dfs_distributions, axs_dist, xlabels, injection_sites.values()
+        ):
+            # select data
+            df_dist_plot = df_dist[df_dist["hemisphere"] == "both"]
+
+            # plot
+            ax_dist = nice_distribution_plot(
+                df_dist_plot,
+                x="bins",
+                y="distribution",
+                hue="animal",
+                xlabel=xlabel,
+                ylabel="normalized distribution",
+                injections_sites=inj_sites,
+                channel_colors=cfg.channels["colors"],
+                channel_names=cfg.channels["names"],
+                linewidth=2,
+                ax=ax_dist,
+            )
+
+    return fig
+
+
+
+ +
+ +
+ + +

+ plot_2D_distributions(df, cfg) + +#

+ + +
+ +

Wraps nice_joint_plot().

+ +
+ Source code in cuisto/display.py +
def plot_2D_distributions(df: pd.DataFrame, cfg):
+    """
+    Wraps nice_joint_plot().
+    """
+    # -- 2D heatmap, all animals pooled
+    # prepare figure
+    fig_heatmap = plt.figure(figsize=(12, 9))
+
+    ax_sag = fig_heatmap.add_subplot(2, 2, 1)
+    ax_cor = fig_heatmap.add_subplot(2, 2, 2, sharey=ax_sag)
+    ax_top = fig_heatmap.add_subplot(2, 2, 3, sharex=ax_sag)
+    ax_cbar = fig_heatmap.add_subplot(2, 2, 4, box_aspect=15)
+
+    # prepare options
+    map_options = dict(
+        bins=cfg.distributions["display"]["cmap_nbins"],
+        cmap=cfg.distributions["display"]["cmap"],
+        rasterized=True,
+        thresh=10,
+        stat="count",
+        vmin=cfg.distributions["display"]["cmap_lim"][0],
+        vmax=cfg.distributions["display"]["cmap_lim"][1],
+    )
+    outline_kws = dict(
+        structures=cfg.atlas["outline_structures"],
+        outline_file=cfg.files["outlines"],
+        linewidth=1.5,
+        color="k",
+    )
+    cbar_kws = dict(label="count")
+
+    # determine which axes are going to be inverted
+    if cfg.atlas["type"] == "brain":
+        cor_invertx = True
+        cor_inverty = False
+        top_invertx = True
+        top_inverty = False
+    elif cfg.atlas["type"] == "cord":
+        cor_invertx = False
+        cor_inverty = False
+        top_invertx = True
+        top_inverty = True
+
+    # - sagittal
+    # no need to invert axes because they are shared with the two other views
+    outline_kws["view"] = "sagittal"
+    nice_joint_plot(
+        df,
+        x="Atlas_X",
+        y="Atlas_Y",
+        xlabel="Rostro-caudal (mm)",
+        ylabel="Dorso-ventral (mm)",
+        outline_kws=outline_kws,
+        ax=ax_sag,
+        **map_options,
+    )
+
+    # - coronal
+    outline_kws["view"] = "coronal"
+    nice_joint_plot(
+        df,
+        x="Atlas_Z",
+        y="Atlas_Y",
+        xlabel="Medio-lateral (mm)",
+        ylabel="Dorso-ventral (mm)",
+        invertx=cor_invertx,
+        inverty=cor_inverty,
+        outline_kws=outline_kws,
+        ax=ax_cor,
+        **map_options,
+    )
+    ax_cor.invert_yaxis()
+
+    # - top
+    outline_kws["view"] = "top"
+    nice_joint_plot(
+        df,
+        x="Atlas_X",
+        y="Atlas_Z",
+        xlabel="Rostro-caudal (mm)",
+        ylabel="Medio-lateral (mm)",
+        invertx=top_invertx,
+        inverty=top_inverty,
+        outline_kws=outline_kws,
+        ax=ax_top,
+        cbar=True,
+        cbar_ax=ax_cbar,
+        cbar_kws=cbar_kws,
+        **map_options,
+    )
+    fig_heatmap.suptitle("sagittal, coronal and top-view projections")
+
+    # -- 2D heatmap per animals
+    # get animals
+    animals = df["animal"].unique()
+    if len(animals) > 1:
+        # Rostro-caudal, dorso-ventral (sagittal)
+        _ = nice_heatmap(
+            df,
+            animals,
+            x="Atlas_X",
+            y="Atlas_Y",
+            xlabel="Rostro-caudal (mm)",
+            ylabel="Dorso-ventral (mm)",
+            invertx=True,
+            inverty=True,
+            cmap="OrRd",
+            rasterized=True,
+            cbar=True,
+        )
+
+        # Medio-lateral, dorso-ventral (coronal)
+        _ = nice_heatmap(
+            df,
+            animals,
+            x="Atlas_Z",
+            y="Atlas_Y",
+            xlabel="Medio-lateral (mm)",
+            ylabel="Dorso-ventral (mm)",
+            inverty=True,
+            invertx=True,
+            cmap="OrRd",
+            rasterized=True,
+        )
+
+    return fig_heatmap
+
+
+
+ +
+ +
+ + +

+ plot_regions(df, cfg, **kwargs) + +#

+ + +
+ +

Wraps nice_bar_plot().

+ +
+ Source code in cuisto/display.py +
def plot_regions(df: pd.DataFrame, cfg, **kwargs):
+    """
+    Wraps nice_bar_plot().
+    """
+    # get regions order
+    if cfg.regions["display"]["order"] == "ontology":
+        regions_order = [d["acronym"] for d in cfg.bg_atlas.structures_list]
+    elif cfg.regions["display"]["order"] == "max":
+        regions_order = "max"
+    else:
+        regions_order = None
+
+    # determine metrics to be plotted and color palette based on hue
+    metrics = [*cfg.regions["display"]["metrics"].keys()]
+    hue = cfg.regions["hue"]
+    palette = cfg.get_hue_palette("regions")
+
+    # select data
+    dfplt = utils.select_hemisphere_channel(
+        df, hue, cfg.regions["hue_filter"], cfg.regions["hue_mirror"]
+    )
+
+    # prepare options
+    bar_kws = dict(
+        err_kws={"linewidth": 1.5},
+        dodge=cfg.regions["display"]["dodge"],
+        palette=palette,
+    )
+    pts_kws = dict(
+        size=4,
+        edgecolor="auto",
+        linewidth=0.75,
+        dodge=cfg.regions["display"]["dodge"],
+        palette=palette,
+    )
+    # draw
+    figs = nice_bar_plot(
+        dfplt,
+        x="Name",
+        y=metrics,
+        hue=hue,
+        ylabel=[*cfg.regions["display"]["metrics"].values()],
+        orient=cfg.regions["display"]["orientation"],
+        nx=cfg.regions["display"]["nregions"],
+        ordering=regions_order,
+        hue_mirror=cfg.regions["hue_mirror"],
+        log_scale=cfg.regions["display"]["log_scale"],
+        bar_kws=bar_kws,
+        pts_kws=pts_kws,
+        **kwargs,
+    )
+
+    return figs
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-io.html b/api-io.html new file mode 100644 index 0000000..b836688 --- /dev/null +++ b/api-io.html @@ -0,0 +1,2756 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.io - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + + + + +

cuisto.io

+ +
+ + + + +
+ +

io module, part of cuisto.

+

Contains loading and saving functions.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ cat_csv_dir(directory, **kwargs) + +#

+ + +
+ +

Scans a directory for csv files and concatenate them into a single DataFrame.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ directory + + str + +
+

Path to the directory to scan.

+
+
+ required +
+ **kwargs + + passed to pandas.read_csv() + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

All CSV files concatenated in a single DataFrame.

+
+
+ +
+ Source code in cuisto/io.py +
def cat_csv_dir(directory, **kwargs) -> pd.DataFrame:
+    """
+    Scans a directory for csv files and concatenate them into a single DataFrame.
+
+    Parameters
+    ----------
+    directory : str
+        Path to the directory to scan.
+    **kwargs : passed to pandas.read_csv()
+
+    Returns
+    -------
+    df : pandas.DataFrame
+        All CSV files concatenated in a single DataFrame.
+
+    """
+    return pd.concat(
+        pd.read_csv(
+            os.path.join(directory, filename),
+            **kwargs,
+        )
+        for filename in os.listdir(directory)
+        if (filename.endswith(".csv"))
+        and not check_empty_file(os.path.join(directory, filename), threshold=1)
+    )
+
+
+
+ +
+ +
+ + +

+ cat_data_dir(directory, segtype, **kwargs) + +#

+ + +
+ +

Wraps either cat_csv_dir() or cat_json_dir() depending on segtype.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ directory + + str + +
+

Path to the directory to scan.

+
+
+ required +
+ segtype + + str + +
+

"synaptophysin" or "fibers".

+
+
+ required +
+ **kwargs + + passed to cat_csv_dir() or cat_json_dir(). + +
+ +
+
+ {} +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

All files concatenated in a single DataFrame.

+
+
+ +
+ Source code in cuisto/io.py +
def cat_data_dir(directory: str, segtype: str, **kwargs) -> pd.DataFrame:
+    """
+    Wraps either cat_csv_dir() or cat_json_dir() depending on `segtype`.
+
+    Parameters
+    ----------
+    directory : str
+        Path to the directory to scan.
+    segtype : str
+        "synaptophysin" or "fibers".
+    **kwargs : passed to cat_csv_dir() or cat_json_dir().
+
+    Returns
+    -------
+    df : pd.DataFrame
+        All files concatenated in a single DataFrame.
+
+    """
+    if segtype in CSV_KW:
+        # remove kwargs for json
+        kwargs.pop("hemisphere_names", None)
+        kwargs.pop("atlas", None)
+        return cat_csv_dir(directory, **kwargs)
+    elif segtype in JSON_KW:
+        kwargs = {k: kwargs[k] for k in ["hemisphere_names", "atlas"] if k in kwargs}
+        return cat_json_dir(directory, **kwargs)
+    else:
+        raise ValueError(
+            f"'{segtype}' not supported, unable to determine if CSV or JSON."
+        )
+
+
+
+ +
+ +
+ + +

+ cat_json_dir(directory, hemisphere_names, atlas) + +#

+ + +
+ +

Scans a directory for json files and concatenate them in a single DataFrame.

+

The json files must be generated with 'workflow_import_export.groovy" from a QuPath +project.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ directory + + str + +
+

Path to the directory to scan.

+
+
+ required +
+ hemisphere_names + + dict + +
+

Maps between hemisphere names in the json files ("Right" and "Left") to +something else (eg. "Ipsi." and "Contra.").

+
+
+ required +
+ atlas + + BrainGlobeAtlas + +
+

Atlas to read regions from.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

All JSON files concatenated in a single DataFrame.

+
+
+ +
+ Source code in cuisto/io.py +
def cat_json_dir(
+    directory: str, hemisphere_names: dict, atlas: BrainGlobeAtlas
+) -> pd.DataFrame:
+    """
+    Scans a directory for json files and concatenate them in a single DataFrame.
+
+    The json files must be generated with 'workflow_import_export.groovy" from a QuPath
+    project.
+
+    Parameters
+    ----------
+    directory : str
+        Path to the directory to scan.
+    hemisphere_names : dict
+        Maps between hemisphere names in the json files ("Right" and "Left") to
+        something else (eg. "Ipsi." and "Contra.").
+    atlas : BrainGlobeAtlas
+        Atlas to read regions from.
+
+    Returns
+    -------
+    df : pd.DataFrame
+        All JSON files concatenated in a single DataFrame.
+
+    """
+    # list files
+    files_list = [
+        os.path.join(directory, filename)
+        for filename in os.listdir(directory)
+        if (filename.endswith(".json"))
+    ]
+
+    data = []  # prepare list of DataFrame
+    for filename in files_list:
+        with open(filename, "rb") as fid:
+            df = pd.DataFrame.from_dict(
+                orjson.loads(fid.read())["paths"], orient="index"
+            )
+            df["Image"] = os.path.basename(filename).split("_detections")[0]
+            data.append(df)
+
+    df = (
+        pd.concat(data)
+        .explode(
+            ["x", "y", "z", "hemisphere"]
+        )  # get an entry for each point of segments
+        .reset_index()
+        .rename(
+            columns=dict(
+                x="Atlas_X",
+                y="Atlas_Y",
+                z="Atlas_Z",
+                index="Object ID",
+                classification="Classification",
+            )
+        )
+        .set_index("Object ID")
+    )
+
+    # change hemisphere names
+    df["hemisphere"] = df["hemisphere"].map(hemisphere_names)
+
+    # add object type
+    df["Object type"] = "Detection"
+
+    # add brain regions
+    df = utils.add_brain_region(df, atlas, col="Parent")
+
+    return df
+
+
+
+ +
+ +
+ + +

+ check_empty_file(filename, threshold=1) + +#

+ + +
+ +

Checks if a file is empty.

+

Empty is defined as a file whose number of lines is lower than or equal to +threshold (to allow for headers).

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ filename + + str + +
+

Full path to the file to check.

+
+
+ required +
+ threshold + + int + +
+

If number of lines is lower than or equal to this value, it is considered as +empty. Default is 1.

+
+
+ 1 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
empty + bool + +
+

True if the file is empty as defined above.

+
+
+ +
+ Source code in cuisto/io.py +
57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
def check_empty_file(filename: str, threshold: int = 1) -> bool:
+    """
+    Checks if a file is empty.
+
+    Empty is defined as a file whose number of lines is lower than or equal to
+    `threshold` (to allow for headers).
+
+    Parameters
+    ----------
+    filename : str
+        Full path to the file to check.
+    threshold : int, optional
+        If number of lines is lower than or equal to this value, it is considered as
+        empty. Default is 1.
+
+    Returns
+    -------
+    empty : bool
+        True if the file is empty as defined above.
+
+    """
+    with open(filename, "rb") as fid:
+        nlines = sum(1 for _ in fid)
+
+    if nlines <= threshold:
+        return True
+    else:
+        return False
+
+
+
+ +
+ +
+ + +

+ get_measurements_directory(wdir, animal, kind, segtype) + +#

+ + +
+ +

Get the directory with detections or annotations measurements for given animal ID.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ wdir + + str + +
+

Base working directory.

+
+
+ required +
+ animal + + str + +
+

Animal ID.

+
+
+ required +
+ kind + + str + +
+

"annotation" or "detection".

+
+
+ required +
+ segtype + + str + +
+

Type of segmentation, eg. "synaptophysin".

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
directory + str + +
+

Path to detections or annotations directory.

+
+
+ +
+ Source code in cuisto/io.py +
24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
def get_measurements_directory(wdir, animal: str, kind: str, segtype: str) -> str:
+    """
+    Get the directory with detections or annotations measurements for given animal ID.
+
+    Parameters
+    ----------
+    wdir : str
+        Base working directory.
+    animal : str
+        Animal ID.
+    kind : str
+        "annotation" or "detection".
+    segtype : str
+        Type of segmentation, eg. "synaptophysin".
+
+    Returns
+    -------
+    directory : str
+        Path to detections or annotations directory.
+
+    """
+    bdir = os.path.join(wdir, animal, animal.lower() + "_segmentation", segtype)
+
+    if (kind == "detection") or (kind == "detections"):
+        return os.path.join(bdir, "detections")
+    elif (kind == "annotation") or (kind == "annotations"):
+        return os.path.join(bdir, "annotations")
+    else:
+        raise ValueError(
+            f"kind = '{kind}' not supported. Choose 'detection' or 'annotation'."
+        )
+
+
+
+ +
+ +
+ + +

+ load_dfs(filepath, fmt, identifiers=['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml']) + +#

+ + +
+ +

Load DataFrames from file.

+

If fmt is "h5" ("xslx"), identifiers are interpreted as h5 group identifier (sheet +name, respectively). +If fmt is "pickle", "csv" or "tsv", identifiers are appended to filename. +Path to the file can't have a dot (".") in it.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ filepath + + str + +
+

Full path to the file(s), without extension.

+
+
+ required +
+ fmt + + (h5, csv, pickle, xlsx) + +
+

File(s) format.

+
+
+ "h5" +
+ identifiers + + list of str + +
+

List of identifiers to load from files. Defaults to the ones saved in +cuisto.process.process_animals().

+
+
+ ['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml'] +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ All requested DataFrames. + +
+ +
+
+ +
+ Source code in cuisto/io.py +
def load_dfs(
+    filepath: str,
+    fmt: str,
+    identifiers: list[str] = [
+        "df_regions",
+        "df_coordinates",
+        "df_distribution_ap",
+        "df_distribution_dv",
+        "df_distribution_ml",
+    ],
+):
+    """
+    Load DataFrames from file.
+
+    If `fmt` is "h5" ("xslx"), identifiers are interpreted as h5 group identifier (sheet
+    name, respectively).
+    If `fmt` is "pickle", "csv" or "tsv", identifiers are appended to `filename`.
+    Path to the file can't have a dot (".") in it.
+
+    Parameters
+    ----------
+    filepath : str
+        Full path to the file(s), without extension.
+    fmt : {"h5", "csv", "pickle", "xlsx"}
+        File(s) format.
+    identifiers : list of str, optional
+        List of identifiers to load from files. Defaults to the ones saved in
+        cuisto.process.process_animals().
+
+    Returns
+    -------
+    All requested DataFrames.
+
+    """
+    # ensure filename without extension
+    base_path = os.path.splitext(filepath)[0]
+    full_path = base_path + "." + fmt
+
+    res = []
+    if (fmt == "h5") or (fmt == "hdf") or (fmt == "hdf5"):
+        for identifier in identifiers:
+            res.append(pd.read_hdf(full_path, identifier))
+    elif fmt == "xlsx":
+        for identifier in identifiers:
+            res.append(pd.read_excel(full_path, sheet_name=identifier))
+    else:
+        for identifier in identifiers:
+            id_path = f"{base_path}_{identifier}.{fmt}"
+            if (fmt == "pickle") or (fmt == "pkl"):
+                res.append(pd.read_pickle(id_path))
+            elif fmt == "csv":
+                res.append(pd.read_csv(id_path))
+            elif fmt == "tsv":
+                res.append(pd.read_csv(id_path, sep="\t"))
+            else:
+                raise ValueError(f"{fmt} is not supported.")
+
+    return res
+
+
+
+ +
+ +
+ + +

+ save_dfs(out_dir, filename, dfs) + +#

+ + +
+ +

Save DataFrames to file.

+

File format is inferred from file name extension.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ out_dir + + str + +
+

Output directory.

+
+
+ required +
+ filename + + _type_ + +
+

File name.

+
+
+ required +
+ dfs + + dict + +
+

DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in +the same file, otherwise identifier is appended to the file name.

+
+
+ required +
+ +
+ Source code in cuisto/io.py +
def save_dfs(out_dir: str, filename, dfs: dict):
+    """
+    Save DataFrames to file.
+
+    File format is inferred from file name extension.
+
+    Parameters
+    ----------
+    out_dir : str
+        Output directory.
+    filename : _type_
+        File name.
+    dfs : dict
+        DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in
+        the same file, otherwise identifier is appended to the file name.
+
+    """
+    if not os.path.isdir(out_dir):
+        os.makedirs(out_dir)
+
+    basename, ext = os.path.splitext(filename)
+    if ext in [".h5", ".hdf", ".hdf5"]:
+        path = os.path.join(out_dir, filename)
+        for identifier, df in dfs.items():
+            df.to_hdf(path, key=identifier)
+    elif ext == ".xlsx":
+        for identifier, df in dfs.items():
+            df.to_excel(path, sheet_name=identifier)
+    else:
+        for identifier, df in dfs.items():
+            path = os.path.join(out_dir, f"{basename}_{identifier}{ext}")
+            if ext in [".pickle", ".pkl"]:
+                df.to_pickle(path)
+            elif ext == ".csv":
+                df.to_csv(path)
+            elif ext == ".tsv":
+                df.to_csv(path, sep="\t")
+            else:
+                raise ValueError(f"{filename} has an unsupported extension.")
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-process.html b/api-process.html new file mode 100644 index 0000000..3262a0a --- /dev/null +++ b/api-process.html @@ -0,0 +1,2231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.process - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

cuisto.process

+ +
+ + + + +
+ +

process module, part of cuisto.

+

Wraps other functions for a click&play behaviour. Relies on the configuration file.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ process_animal(animal, df_annotations, df_detections, cfg, compute_distributions=True) + +#

+ + +
+ +

Quantify objects for one animal.

+

Fetch required files and compute objects' distributions in brain regions, spatial +distributions and gather Atlas coordinates.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ animal + + str + +
+

Animal ID.

+
+
+ required +
+ df_annotations + + DataFrame + +
+

DataFrames of QuPath Annotations and Detections.

+
+
+ required +
+ df_detections + + DataFrame + +
+

DataFrames of QuPath Annotations and Detections.

+
+
+ required +
+ cfg + + Config + +
+

The configuration loaded from TOML configuration file.

+
+
+ required +
+ compute_distributions + + bool + +
+

If False, do not compute the 1D distributions and return an empty list.Default +is True.

+
+
+ True +
+ + +

Returns:

+ + + + + + + + + + + + + + + + + + + + + +
Name TypeDescription
df_regions + DataFrame + +
+

Metrics in brain regions. One entry for each hemisphere of each brain regions.

+
+
df_distribution + list of pandas.DataFrame + +
+

Rostro-caudal distribution, as raw count and probability density function, in +each axis.

+
+
df_coordinates + DataFrame + +
+

Atlas coordinates of each points.

+
+
+ +
+ Source code in cuisto/process.py +
def process_animal(
+    animal: str,
+    df_annotations: pd.DataFrame,
+    df_detections: pd.DataFrame,
+    cfg,
+    compute_distributions: bool = True,
+) -> tuple[pd.DataFrame, list[pd.DataFrame], pd.DataFrame]:
+    """
+    Quantify objects for one animal.
+
+    Fetch required files and compute objects' distributions in brain regions, spatial
+    distributions and gather Atlas coordinates.
+
+    Parameters
+    ----------
+    animal : str
+        Animal ID.
+    df_annotations, df_detections : pd.DataFrame
+        DataFrames of QuPath Annotations and Detections.
+    cfg : cuisto.Config
+        The configuration loaded from TOML configuration file.
+    compute_distributions : bool, optional
+        If False, do not compute the 1D distributions and return an empty list.Default
+        is True.
+
+    Returns
+    -------
+    df_regions : pandas.DataFrame
+        Metrics in brain regions. One entry for each hemisphere of each brain regions.
+    df_distribution : list of pandas.DataFrame
+        Rostro-caudal distribution, as raw count and probability density function, in
+        each axis.
+    df_coordinates : pandas.DataFrame
+        Atlas coordinates of each points.
+
+    """
+    # - Annotations data cleanup
+    # filter regions
+    df_annotations = utils.filter_df_regions(
+        df_annotations, ["Root", "root"], mode="remove", col="Name"
+    )
+    df_annotations = utils.filter_df_regions(
+        df_annotations, cfg.atlas["blacklist"], mode="remove", col="Name"
+    )
+    # add hemisphere
+    df_annotations = utils.add_hemisphere(df_annotations, cfg.hemispheres["names"])
+    # remove objects in non-leaf regions
+    df_annotations = utils.filter_df_regions(
+        df_annotations, cfg.atlas["leaveslist"], mode="keep", col="Name"
+    )
+    # merge regions
+    df_annotations = utils.merge_regions(
+        df_annotations, col="Name", fusion_file=cfg.files["fusion"]
+    )
+    if compute_distributions:
+        # - Detections data cleanup
+        # remove objects not in selected classifications
+        df_detections = utils.filter_df_classifications(
+            df_detections, cfg.object_type, mode="keep", col="Classification"
+        )
+        # remove objects from blacklisted regions and "Root"
+        df_detections = utils.filter_df_regions(
+            df_detections, cfg.atlas["blacklist"], mode="remove", col="Parent"
+        )
+        # add hemisphere
+        df_detections = utils.add_hemisphere(
+            df_detections,
+            cfg.hemispheres["names"],
+            cfg.atlas["midline"],
+            col="Atlas_Z",
+            atlas_type=cfg.atlas["type"],
+        )
+        # add detection channel
+        df_detections = utils.add_channel(
+            df_detections, cfg.object_type, cfg.channels["names"]
+        )
+        # convert coordinates to mm
+        df_detections[["Atlas_X", "Atlas_Y", "Atlas_Z"]] = df_detections[
+            ["Atlas_X", "Atlas_Y", "Atlas_Z"]
+        ].divide(1000)
+        # convert to sterotaxic coordinates
+        if cfg.distributions["stereo"]:
+            (
+                df_detections["Atlas_AP"],
+                df_detections["Atlas_DV"],
+                df_detections["Atlas_ML"],
+            ) = utils.ccf_to_stereo(
+                df_detections["Atlas_X"],
+                df_detections["Atlas_Y"],
+                df_detections["Atlas_Z"],
+            )
+        else:
+            (
+                df_detections["Atlas_AP"],
+                df_detections["Atlas_DV"],
+                df_detections["Atlas_ML"],
+            ) = (
+                df_detections["Atlas_X"],
+                df_detections["Atlas_Y"],
+                df_detections["Atlas_Z"],
+            )
+
+    # - Computations
+    # get regions distributions
+    df_regions = compute.get_regions_metrics(
+        df_annotations,
+        cfg.object_type,
+        cfg.channels["names"],
+        cfg.regions["base_measurement"],
+        cfg.regions["metrics"],
+    )
+    colstonorm = [v for v in cfg.regions["metrics"].values() if "relative" not in v]
+
+    # normalize by starter cells
+    if cfg.regions["normalize_starter_cells"]:
+        df_regions = compute.normalize_starter_cells(
+            df_regions, colstonorm, animal, cfg.files["infos"], cfg.channels["names"]
+        )
+
+    # get AP, DV, ML distributions in stereotaxic coordinates
+    if compute_distributions:
+        dfs_distributions = [
+            compute.get_distribution(
+                df_detections,
+                axis,
+                cfg.distributions["hue"],
+                cfg.distributions["hue_filter"],
+                cfg.distributions["common_norm"],
+                stereo_lim,
+                nbins=nbins,
+            )
+            for axis, stereo_lim, nbins in zip(
+                ["Atlas_AP", "Atlas_DV", "Atlas_ML"],
+                [
+                    cfg.distributions["ap_lim"],
+                    cfg.distributions["dv_lim"],
+                    cfg.distributions["ml_lim"],
+                ],
+                [
+                    cfg.distributions["ap_nbins"],
+                    cfg.distributions["dv_nbins"],
+                    cfg.distributions["dv_nbins"],
+                ],
+            )
+        ]
+    else:
+        dfs_distributions = []
+
+    # add animal tag to each DataFrame
+    df_detections["animal"] = animal
+    df_regions["animal"] = animal
+    for df in dfs_distributions:
+        df["animal"] = animal
+
+    return df_regions, dfs_distributions, df_detections
+
+
+
+ +
+ +
+ + +

+ process_animals(wdir, animals, cfg, out_fmt=None, compute_distributions=True) + +#

+ + +
+ +

Get data from all animals and plot.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ wdir + + str + +
+

Base working directory, containing animals folders.

+
+
+ required +
+ animals + + list-like of str + +
+

List of animals ID.

+
+
+ required +
+ cfg + + +
+

Configuration object.

+
+
+ required +
+ out_fmt + + (None, h5, csv, tsv, xslx, pickle) + +
+

Output file(s) format, if None, nothing is saved (default).

+
+
+ None +
+ compute_distributions + + bool + +
+

If False, do not compute the 1D distributions and return an empty list.Default +is True.

+
+
+ True +
+ + +

Returns:

+ + + + + + + + + + + + + + + + + + + + + +
Name TypeDescription
df_regions + DataFrame + +
+

Metrics in brain regions. One entry for each hemisphere of each brain regions.

+
+
df_distribution + list of pandas.DataFrame + +
+

Rostro-caudal distribution, as raw count and probability density function, in +each axis.

+
+
df_coordinates + DataFrame + +
+

Atlas coordinates of each points.

+
+
+ +
+ Source code in cuisto/process.py +
def process_animals(
+    wdir: str,
+    animals: list[str] | tuple[str],
+    cfg,
+    out_fmt: str | None = None,
+    compute_distributions: bool = True,
+) -> tuple[pd.DataFrame]:
+    """
+    Get data from all animals and plot.
+
+    Parameters
+    ----------
+    wdir : str
+        Base working directory, containing `animals` folders.
+    animals : list-like of str
+        List of animals ID.
+    cfg: cuisto.Config
+        Configuration object.
+    out_fmt : {None, "h5", "csv", "tsv", "xslx", "pickle"}
+        Output file(s) format, if None, nothing is saved (default).
+    compute_distributions : bool, optional
+        If False, do not compute the 1D distributions and return an empty list.Default
+        is True.
+
+
+    Returns
+    -------
+    df_regions : pandas.DataFrame
+        Metrics in brain regions. One entry for each hemisphere of each brain regions.
+    df_distribution : list of pandas.DataFrame
+        Rostro-caudal distribution, as raw count and probability density function, in
+        each axis.
+    df_coordinates : pandas.DataFrame
+        Atlas coordinates of each points.
+
+    """
+
+    # -- Preparation
+    df_regions = []
+    dfs_distributions = []
+    df_coordinates = []
+
+    # -- Processing
+    pbar = tqdm(animals)
+
+    for animal in pbar:
+        pbar.set_description(f"Processing {animal}")
+
+        # combine all detections and annotations from this animal
+        df_annotations = io.cat_csv_dir(
+            io.get_measurements_directory(
+                wdir, animal, "annotation", cfg.segmentation_tag
+            ),
+            index_col="Object ID",
+            sep="\t",
+        )
+        if compute_distributions:
+            df_detections = io.cat_data_dir(
+                io.get_measurements_directory(
+                    wdir, animal, "detection", cfg.segmentation_tag
+                ),
+                cfg.segmentation_tag,
+                index_col="Object ID",
+                sep="\t",
+                hemisphere_names=cfg.hemispheres["names"],
+                atlas=cfg.bg_atlas,
+            )
+        else:
+            df_detections = pd.DataFrame()
+
+        # get results
+        df_reg, dfs_dis, df_coo = process_animal(
+            animal,
+            df_annotations,
+            df_detections,
+            cfg,
+            compute_distributions=compute_distributions,
+        )
+
+        # collect results
+        df_regions.append(df_reg)
+        dfs_distributions.append(dfs_dis)
+        df_coordinates.append(df_coo)
+
+    # concatenate all results
+    df_regions = pd.concat(df_regions, ignore_index=True)
+    dfs_distributions = [
+        pd.concat(dfs_list, ignore_index=True) for dfs_list in zip(*dfs_distributions)
+    ]
+    df_coordinates = pd.concat(df_coordinates, ignore_index=True)
+
+    # -- Saving
+    if out_fmt:
+        outdir = os.path.join(wdir, "quantification")
+        outfile = f"{cfg.object_type.lower()}_{cfg.atlas["type"]}_{'-'.join(animals)}.{out_fmt}"
+        dfs = dict(
+            df_regions=df_regions,
+            df_coordinates=df_coordinates,
+            df_distribution_ap=dfs_distributions[0],
+            df_distribution_dv=dfs_distributions[1],
+            df_distribution_ml=dfs_distributions[2],
+        )
+        io.save_dfs(outdir, outfile, dfs)
+
+    return df_regions, dfs_distributions, df_coordinates
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-script-qupath-script-runner.html b/api-script-qupath-script-runner.html new file mode 100644 index 0000000..6dd5dc2 --- /dev/null +++ b/api-script-qupath-script-runner.html @@ -0,0 +1,1626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + qupath_script_runner - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

qupath_script_runner

+ +
+ + + + +
+ +

Template to show how to run groovy script with QuPath, multi-threaded.

+ + + + + + + + +
+ + + + + + + +
+ + + +

+ EXCLUDE_LIST = [] + + + module-attribute + + +#

+ + +
+ +

Images names to NOT run the script on.

+
+ +
+ +
+ + + +

+ NTHREADS = 5 + + + module-attribute + + +#

+ + +
+ +

Number of threads to use.

+
+ +
+ +
+ + + +

+ QPROJ_PATH = '/path/to/qupath/project.qproj' + + + module-attribute + + +#

+ + +
+ +

Full path to the QuPath project.

+
+ +
+ +
+ + + +

+ QUIET = True + + + module-attribute + + +#

+ + +
+ +

Use QuPath in quiet mode, eg. with minimal verbosity.

+
+ +
+ +
+ + + +

+ QUPATH_EXE = '/path/to/the/qupath/QuPath-0.5.1 (console).exe' + + + module-attribute + + +#

+ + +
+ +

Path to the QuPath executable (console mode).

+
+ +
+ +
+ + + +

+ SAVE = True + + + module-attribute + + +#

+ + +
+ +

Whether to save the project after the script ran on an image.

+
+ +
+ +
+ + + +

+ SCRIPT_PATH = '/path/to/the/script.groovy' + + + module-attribute + + +#

+ + +
+ +

Path to the groovy script.

+
+ +
+ + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-script-segment.html b/api-script-segment.html new file mode 100644 index 0000000..029558c --- /dev/null +++ b/api-script-segment.html @@ -0,0 +1,3313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + segment_images - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

segment_images

+ +
+ + + + +
+ +

Script to segment objects from images.

+

For fiber-like objects, binarize and skeletonize the image, then use skan to extract +branches coordinates. +For polygon-like objects, binarize the image and detect objects and extract contours +coordinates. +For points, treat that as polygons then extract the centroids instead of contours. +Finally, export the coordinates as collections in geojson files, importable in QuPath. +Supports any number of channel of interest within the same image. One file output file +per channel will be created.

+

This script uses cuisto.seg. It is designed to work on probability maps generated +from a pixel classifier in QuPath, but might work on raw images.

+

Usage : fill-in the Parameters section of the script and run it. +A "geojson" folder will be created in the parent directory of IMAGES_DIR. +To exclude objects near the edges of an ROI, specify the path to masks stored as images +with the same names as probabilities images (without their suffix).

+

author : Guillaume Le Goc (g.legoc@posteo.org) @ NeuroPSI +version : 2024.12.10

+ + + + + + + + +
+ + + + + + + +
+ + + +

+ CHANNELS_PARAMS = [{'name': 'cy5', 'target_channel': 0, 'proba_threshold': 0.85, 'qp_class': 'Fibers: Cy5', 'qp_color': [164, 250, 120]}, {'name': 'dsred', 'target_channel': 1, 'proba_threshold': 0.65, 'qp_class': 'Fibers: DsRed', 'qp_color': [224, 153, 18]}, {'name': 'egfp', 'target_channel': 2, 'proba_threshold': 0.85, 'qp_class': 'Fibers: EGFP', 'qp_color': [135, 11, 191]}] + + + module-attribute + + +#

+ + +
+ +

This should be a list of dictionary (one per channel) with keys :

+
    +
  • name: str, used as suffix for output geojson files, not used if only one channel
  • +
  • target_channel: int, index of the segmented channel of the image, 0-based
  • +
  • proba_threshold: float < 1, probability cut-off for that channel
  • +
  • qp_class: str, name of QuPath classification
  • +
  • qp_color: list of RGB values, associated color
  • +
+
+ +
+ +
+ + + +

+ EDGE_DIST = 0 + + + module-attribute + + +#

+ + +
+ +

Distance to brain edge to ignore, in µm. 0 to disable.

+
+ +
+ +
+ + + +

+ FILTERS = {'length_low': 1.5, 'area_low': 10, 'area_high': 1000, 'ecc_low': 0.0, 'ecc_high': 0.9, 'dist_thresh': 30} + + + module-attribute + + +#

+ + +
+ +

Dictionary with keys :

+
    +
  • length_low: minimal length in microns - for lines
  • +
  • area_low: minimal area in µm² - for polygons and points
  • +
  • area_high: maximal area in µm² - for polygons and points
  • +
  • ecc_low: minimal eccentricity - for polygons and points (0 = circle)
  • +
  • ecc_high: maximal eccentricity - for polygons and points (1 = line)
  • +
  • dist_thresh: maximal inter-point distance in µm - for points
  • +
+
+ +
+ +
+ + + +

+ IMAGES_DIR = '/path/to/images' + + + module-attribute + + +#

+ + +
+ +

Full path to the images to segment.

+
+ +
+ +
+ + + +

+ IMG_SUFFIX = '_Probabilities.tiff' + + + module-attribute + + +#

+ + +
+ +

Images suffix, including extension. Masks must be the same name without the suffix.

+
+ +
+ +
+ + + +

+ MASKS_DIR = 'path/to/corresponding/masks' + + + module-attribute + + +#

+ + +
+ +

Full path to the masks, to exclude objects near the brain edges (set to None or empty +string to disable this feature).

+
+ +
+ +
+ + + +

+ MASKS_EXT = 'tiff' + + + module-attribute + + +#

+ + +
+ +

Masks files extension.

+
+ +
+ +
+ + + +

+ MAX_PIX_VALUE = 255 + + + module-attribute + + +#

+ + +
+ +

Maximum pixel possible value to adjust proba_threshold.

+
+ +
+ +
+ + + +

+ ORIGINAL_PIXELSIZE = 0.45 + + + module-attribute + + +#

+ + +
+ +

Original images pixel size in microns. This is in case the pixel classifier uses +a lower resolution, yielding smaller probability maps, so output objects coordinates +need to be rescaled to the full size images. The pixel size is written in the "Image" +tab in QuPath.

+
+ +
+ +
+ + + +

+ QUPATH_TYPE = 'detection' + + + module-attribute + + +#

+ + +
+ +

QuPath object type.

+
+ +
+ +
+ + + +

+ SEGTYPE = 'boutons' + + + module-attribute + + +#

+ + +
+ +

Type of segmentation.

+
+ +
+ + + +
+ + +

+ get_geojson_dir(images_dir) + +#

+ + +
+ +

Get the directory of geojson files, which will be in the parent directory +of images_dir.

+

If the directory does not exist, create it.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ images_dir + + str + +
+ +
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
geojson_dir + str + +
+ +
+
+ +
+ Source code in scripts/segmentation/segment_images.py +
def get_geojson_dir(images_dir: str):
+    """
+    Get the directory of geojson files, which will be in the parent directory
+    of `images_dir`.
+
+    If the directory does not exist, create it.
+
+    Parameters
+    ----------
+    images_dir : str
+
+    Returns
+    -------
+    geojson_dir : str
+
+    """
+
+    geojson_dir = os.path.join(Path(images_dir).parent, "geojson")
+
+    if not os.path.isdir(geojson_dir):
+        os.mkdir(geojson_dir)
+
+    return geojson_dir
+
+
+
+ +
+ +
+ + +

+ get_geojson_properties(name, color, objtype='detection') + +#

+ + +
+ +

Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ name + + str + +
+

Classification name.

+
+
+ required +
+ color + + tuple or list + +
+

Classification color in RGB (3-elements vector).

+
+
+ required +
+ objtype + + str + +
+

Object type ("detection" or "annotation"). Default is "detection".

+
+
+ 'detection' +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
props + dict + +
+ +
+
+ +
+ Source code in scripts/segmentation/segment_images.py +
def get_geojson_properties(name: str, color: tuple | list, objtype: str = "detection"):
+    """
+    Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.
+
+    Parameters
+    ----------
+    name : str
+        Classification name.
+    color : tuple or list
+        Classification color in RGB (3-elements vector).
+    objtype : str, optional
+        Object type ("detection" or "annotation"). Default is "detection".
+
+    Returns
+    -------
+    props : dict
+
+    """
+
+    return {
+        "objectType": objtype,
+        "classification": {"name": name, "color": color},
+        "isLocked": "true",
+    }
+
+
+
+ +
+ +
+ + +

+ get_seg_method(segtype) + +#

+ + +
+ +

Determine what kind of segmentation is performed.

+

Segmentation kind are, for now, lines, polygons or points. We detect that based on +hardcoded keywords.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ segtype + + str + +
+ +
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
seg_method + str + +
+ +
+
+ +
+ Source code in scripts/segmentation/segment_images.py +
def get_seg_method(segtype: str):
+    """
+    Determine what kind of segmentation is performed.
+
+    Segmentation kind are, for now, lines, polygons or points. We detect that based on
+    hardcoded keywords.
+
+    Parameters
+    ----------
+    segtype : str
+
+    Returns
+    -------
+    seg_method : str
+
+    """
+
+    line_list = ["fibers", "axons", "fiber", "axon"]
+    point_list = ["synapto", "synaptophysin", "syngfp", "boutons", "points"]
+    polygon_list = ["cells", "polygon", "polygons", "polygon", "cell"]
+
+    if segtype in line_list:
+        seg_method = "lines"
+    elif segtype in polygon_list:
+        seg_method = "polygons"
+    elif segtype in point_list:
+        seg_method = "points"
+    else:
+        raise ValueError(
+            f"Could not determine method to use based on segtype : {segtype}."
+        )
+
+    return seg_method
+
+
+
+ +
+ +
+ + +

+ parameters_as_dict(images_dir, masks_dir, segtype, name, proba_threshold, edge_dist) + +#

+ + +
+ +

Get information as a dictionnary.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ images_dir + + str + +
+

Path to images to be segmented.

+
+
+ required +
+ masks_dir + + str + +
+

Path to images masks.

+
+
+ required +
+ segtype + + str + +
+

Segmentation type (eg. "fibers").

+
+
+ required +
+ name + + str + +
+

Name of the segmentation (eg. "green").

+
+
+ required +
+ proba_threshold + + float < 1 + +
+

Probability threshold.

+
+
+ required +
+ edge_dist + + float + +
+

Distance in µm to the brain edge that is ignored.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
params + dict + +
+ +
+
+ +
+ Source code in scripts/segmentation/segment_images.py +
def parameters_as_dict(
+    images_dir: str,
+    masks_dir: str,
+    segtype: str,
+    name: str,
+    proba_threshold: float,
+    edge_dist: float,
+):
+    """
+    Get information as a dictionnary.
+
+    Parameters
+    ----------
+    images_dir : str
+        Path to images to be segmented.
+    masks_dir : str
+        Path to images masks.
+    segtype : str
+        Segmentation type (eg. "fibers").
+    name : str
+        Name of the segmentation (eg. "green").
+    proba_threshold : float < 1
+        Probability threshold.
+    edge_dist : float
+        Distance in µm to the brain edge that is ignored.
+
+    Returns
+    -------
+    params : dict
+
+    """
+
+    return {
+        "images_location": images_dir,
+        "masks_location": masks_dir,
+        "type": segtype,
+        "probability threshold": proba_threshold,
+        "name": name,
+        "edge distance": edge_dist,
+    }
+
+
+
+ +
+ +
+ + +

+ process_directory(images_dir, img_suffix='', segtype='', original_pixelsize=1.0, target_channel=0, proba_threshold=0.0, qupath_class='Object', qupath_color=[0, 0, 0], channel_suffix='', edge_dist=0.0, filters={}, masks_dir='', masks_ext='') + +#

+ + +
+ +

Main function, processes the .ome.tiff files in the input directory.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ images_dir + + str + +
+

Animal ID to process.

+
+
+ required +
+ img_suffix + + str + +
+

Images suffix, including extension.

+
+
+ '' +
+ segtype + + str + +
+

Segmentation type.

+
+
+ '' +
+ original_pixelsize + + float + +
+

Original images pixel size in microns.

+
+
+ 1.0 +
+ target_channel + + int + +
+

Index of the channel containning the objects of interest (eg. not the +background), in the probability map (not the original images channels).

+
+
+ 0 +
+ proba_threshold + + float < 1 + +
+

Probability below this value will be discarded (multiplied by MAX_PIXEL_VALUE)

+
+
+ 0.0 +
+ qupath_class + + str + +
+

Name of the QuPath classification.

+
+
+ 'Object' +
+ qupath_color + + list of three elements + +
+

Color associated to that classification in RGB.

+
+
+ [0, 0, 0] +
+ channel_suffix + + str + +
+

Channel name, will be used as a suffix in output geojson files.

+
+
+ '' +
+ edge_dist + + float + +
+

Distance to the edge of the brain masks that will be ignored, in microns. Set to +0 to disable this feature.

+
+
+ 0.0 +
+ filters + + dict + +
+

Filters values to include or excludes objects. See the top of the script.

+
+
+ {} +
+ masks_dir + + str + +
+

Path to images masks, to exclude objects found near the edges. The masks must be +with the same name as the corresponding image to be segmented, without its +suffix. Default is "", which disables this feature.

+
+
+ '' +
+ masks_ext + + str + +
+

Masks files extension, without leading ".". Default is ""

+
+
+ '' +
+ +
+ Source code in scripts/segmentation/segment_images.py +
def process_directory(
+    images_dir: str,
+    img_suffix: str = "",
+    segtype: str = "",
+    original_pixelsize: float = 1.0,
+    target_channel: int = 0,
+    proba_threshold: float = 0.0,
+    qupath_class: str = "Object",
+    qupath_color: list = [0, 0, 0],
+    channel_suffix: str = "",
+    edge_dist: float = 0.0,
+    filters: dict = {},
+    masks_dir: str = "",
+    masks_ext: str = "",
+):
+    """
+    Main function, processes the .ome.tiff files in the input directory.
+
+    Parameters
+    ----------
+    images_dir : str
+        Animal ID to process.
+    img_suffix : str
+        Images suffix, including extension.
+    segtype : str
+        Segmentation type.
+    original_pixelsize : float
+        Original images pixel size in microns.
+    target_channel : int
+        Index of the channel containning the objects of interest (eg. not the
+        background), in the probability map (*not* the original images channels).
+    proba_threshold : float < 1
+        Probability below this value will be discarded (multiplied by `MAX_PIXEL_VALUE`)
+    qupath_class : str
+        Name of the QuPath classification.
+    qupath_color : list of three elements
+        Color associated to that classification in RGB.
+    channel_suffix : str
+        Channel name, will be used as a suffix in output geojson files.
+    edge_dist : float
+        Distance to the edge of the brain masks that will be ignored, in microns. Set to
+        0 to disable this feature.
+    filters : dict
+        Filters values to include or excludes objects. See the top of the script.
+    masks_dir : str, optional
+        Path to images masks, to exclude objects found near the edges. The masks must be
+        with the same name as the corresponding image to be segmented, without its
+        suffix. Default is "", which disables this feature.
+    masks_ext : str, optional
+        Masks files extension, without leading ".". Default is ""
+
+    """
+
+    # -- Preparation
+    # get segmentation type
+    seg_method = get_seg_method(segtype)
+
+    # get output directory path
+    geojson_dir = get_geojson_dir(images_dir)
+
+    # get images list
+    images_list = [
+        os.path.join(images_dir, filename)
+        for filename in os.listdir(images_dir)
+        if filename.endswith(img_suffix)
+    ]
+
+    # write parameters
+    parameters = parameters_as_dict(
+        images_dir, masks_dir, segtype, channel_suffix, proba_threshold, edge_dist
+    )
+    param_file = os.path.join(geojson_dir, "parameters" + channel_suffix + ".txt")
+    if os.path.isfile(param_file):
+        raise FileExistsError("Parameters file already exists.")
+    else:
+        write_parameters(param_file, parameters, filters, original_pixelsize)
+
+    # convert parameters to pixels in probability map
+    pixelsize = hq.seg.get_pixelsize(images_list[0])  # get pixel size
+    edge_dist = int(edge_dist / pixelsize)
+    filters = hq.seg.convert_to_pixels(filters, pixelsize)
+
+    # get rescaling factor
+    rescale_factor = pixelsize / original_pixelsize
+
+    # get GeoJSON properties
+    geojson_props = get_geojson_properties(
+        qupath_class, qupath_color, objtype=QUPATH_TYPE
+    )
+
+    # -- Processing
+    pbar = tqdm(images_list)
+    for imgpath in pbar:
+        # build file names
+        imgname = os.path.basename(imgpath)
+        geoname = imgname.replace(img_suffix, "")
+        geojson_file = os.path.join(
+            geojson_dir, geoname + "_segmentation" + channel_suffix + ".geojson"
+        )
+
+        # checks if output file already exists
+        if os.path.isfile(geojson_file):
+            continue
+
+        # read images
+        pbar.set_description(f"{geoname}: Loading...")
+        img = tifffile.imread(imgpath, key=target_channel)
+        if (edge_dist > 0) & (len(masks_dir) != 0):
+            mask = tifffile.imread(os.path.join(masks_dir, geoname + "." + masks_ext))
+            mask = hq.seg.pad_image(mask, img.shape)  # resize mask
+            # apply mask, eroding from the edges
+            img = img * hq.seg.erode_mask(mask, edge_dist)
+
+        # image processing
+        pbar.set_description(f"{geoname}: IP...")
+
+        # threshold probability and binarization
+        img = img >= proba_threshold * MAX_PIX_VALUE
+
+        # segmentation
+        pbar.set_description(f"{geoname}: Segmenting...")
+
+        if seg_method == "lines":
+            collection = hq.seg.segment_lines(
+                img,
+                geojson_props,
+                minsize=filters["length_low"],
+                rescale_factor=rescale_factor,
+            )
+
+        elif seg_method == "polygons":
+            collection = hq.seg.segment_polygons(
+                img,
+                geojson_props,
+                area_min=filters["area_low"],
+                area_max=filters["area_high"],
+                ecc_min=filters["ecc_low"],
+                ecc_max=filters["ecc_high"],
+                rescale_factor=rescale_factor,
+            )
+
+        elif seg_method == "points":
+            collection = hq.seg.segment_points(
+                img,
+                geojson_props,
+                area_min=filters["area_low"],
+                area_max=filters["area_high"],
+                ecc_min=filters["ecc_low"],
+                ecc_max=filters["ecc_high"],
+                dist_thresh=filters["dist_thresh"],
+                rescale_factor=rescale_factor,
+            )
+        else:
+            # we already printed an error message
+            return
+
+        # save geojson
+        pbar.set_description(f"{geoname}: Saving...")
+        with open(geojson_file, "w") as fid:
+            fid.write(geojson.dumps(collection))
+
+
+
+ +
+ +
+ + +

+ write_parameters(outfile, parameters, filters, original_pixelsize) + +#

+ + +
+ +

Write parameters to outfile.

+

A timestamp will be added. Parameters are written as key = value, +and a [filters] is added before filters parameters.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ outfile + + str + +
+

Full path to the output file.

+
+
+ required +
+ parameters + + dict + +
+

General parameters.

+
+
+ required +
+ filters + + dict + +
+

Filters parameters.

+
+
+ required +
+ original_pixelsize + + float + +
+

Size of pixels in original image.

+
+
+ required +
+ +
+ Source code in scripts/segmentation/segment_images.py +
def write_parameters(
+    outfile: str, parameters: dict, filters: dict, original_pixelsize: float
+):
+    """
+    Write parameters to `outfile`.
+
+    A timestamp will be added. Parameters are written as key = value,
+    and a [filters] is added before filters parameters.
+
+    Parameters
+    ----------
+    outfile : str
+        Full path to the output file.
+    parameters : dict
+        General parameters.
+    filters : dict
+        Filters parameters.
+    original_pixelsize : float
+        Size of pixels in original image.
+
+    """
+
+    with open(outfile, "w") as fid:
+        fid.writelines(f"date = {datetime.now().strftime('%d-%B-%Y %H:%M:%S')}\n")
+
+        fid.writelines(f"original_pixelsize = {original_pixelsize}\n")
+
+        for key, value in parameters.items():
+            fid.writelines(f"{key} = {value}\n")
+
+        fid.writelines("[filters]\n")
+
+        for key, value in filters.items():
+            fid.writelines(f"{key} = {value}\n")
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-seg.html b/api-seg.html new file mode 100644 index 0000000..a258b58 --- /dev/null +++ b/api-seg.html @@ -0,0 +1,3645 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.seg - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

cuisto.seg

+ +
+ + + + +
+ +

seg module, part of cuisto.

+

Functions for segmentating probability map stored as an image.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ convert_to_pixels(filters, pixelsize) + +#

+ + +
+ +

Convert some values in filters in pixels.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ filters + + dict + +
+

Must contain the keys used below.

+
+
+ required +
+ pixelsize + + float + +
+

Pixel size in microns.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
filters + dict + +
+

Same as input, with values in pixels.

+
+
+ +
+ Source code in cuisto/seg.py +
42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
def convert_to_pixels(filters, pixelsize):
+    """
+    Convert some values in `filters` in pixels.
+
+    Parameters
+    ----------
+    filters : dict
+        Must contain the keys used below.
+    pixelsize : float
+        Pixel size in microns.
+
+    Returns
+    -------
+    filters : dict
+        Same as input, with values in pixels.
+
+    """
+
+    filters["area_low"] = filters["area_low"] / pixelsize**2
+    filters["area_high"] = filters["area_high"] / pixelsize**2
+    filters["length_low"] = filters["length_low"] / pixelsize
+    filters["dist_thresh"] = int(filters["dist_thresh"] / pixelsize)
+
+    return filters
+
+
+
+ +
+ +
+ + +

+ erode_mask(mask, edge_dist) + +#

+ + +
+ +

Erode the mask outline so that is is edge_dist smaller from the border.

+

This allows discarding the edges.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ mask + + ndarray + +
+ +
+
+ required +
+ edge_dist + + float + +
+

Distance to edges, in pixels.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
eroded_mask + ndarray of bool + +
+ +
+
+ +
+ Source code in cuisto/seg.py +
def erode_mask(mask: np.ndarray, edge_dist: float) -> np.ndarray:
+    """
+    Erode the mask outline so that is is `edge_dist` smaller from the border.
+
+    This allows discarding the edges.
+
+    Parameters
+    ----------
+    mask : ndarray
+    edge_dist : float
+        Distance to edges, in pixels.
+
+    Returns
+    -------
+    eroded_mask : ndarray of bool
+
+    """
+
+    if edge_dist % 2 == 0:
+        edge_dist += 1  # decomposition requires even number
+
+    footprint = morphology.square(edge_dist, decomposition="sequence")
+
+    return mask * morphology.binary_erosion(mask, footprint=footprint)
+
+
+
+ +
+ +
+ + +

+ get_collection_from_points(coords, properties, rescale_factor=1.0, offset=0.5) + +#

+ + +
+ +

Gather coordinates from coords and put them in GeoJSON format.

+

An entry in coords are pairs of (x, y) coordinates defining the point. +properties is a dictionnary with QuPath properties of each detections.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ coords + + list + +
+ +
+
+ required +
+ properties + + dict + +
+ +
+
+ required +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1.0 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+ +
+
+ +
+ Source code in cuisto/seg.py +
def get_collection_from_points(
+    coords: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5
+) -> geojson.FeatureCollection:
+    """
+    Gather coordinates from `coords` and put them in GeoJSON format.
+
+    An entry in `coords` are pairs of (x, y) coordinates defining the point.
+    `properties` is a dictionnary with QuPath properties of each detections.
+
+    Parameters
+    ----------
+    coords : list
+    properties : dict
+    rescale_factor : float
+        Rescale output coordinates by this factor.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+
+    """
+
+    collection = [
+        geojson.Feature(
+            geometry=shapely.Point(
+                np.flip((coord + offset) * rescale_factor)
+            ),  # shape object
+            properties=properties,  # object properties
+            id=str(uuid.uuid4()),  # object uuid
+        )
+        for coord in coords
+    ]
+
+    return geojson.FeatureCollection(collection)
+
+
+
+ +
+ +
+ + +

+ get_collection_from_poly(contours, properties, rescale_factor=1.0, offset=0.5) + +#

+ + +
+ +

Gather coordinates in the list and put them in GeoJSON format as Polygons.

+

An entry in contours must define a closed polygon. properties is a dictionnary +with QuPath properties of each detections.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ contours + + list + +
+ +
+
+ required +
+ properties + + dict + +
+

QuPatj objects' properties.

+
+
+ required +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1.0 +
+ offset + + float + +
+

Shift coordinates by this amount, typically to get pixel centers or edges. +Default is 0.5.

+
+
+ 0.5 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+

A FeatureCollection ready to be written as geojson.

+
+
+ +
+ Source code in cuisto/seg.py +
def get_collection_from_poly(
+    contours: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5
+) -> geojson.FeatureCollection:
+    """
+    Gather coordinates in the list and put them in GeoJSON format as Polygons.
+
+    An entry in `contours` must define a closed polygon. `properties` is a dictionnary
+    with QuPath properties of each detections.
+
+    Parameters
+    ----------
+    contours : list
+    properties : dict
+        QuPatj objects' properties.
+    rescale_factor : float
+        Rescale output coordinates by this factor.
+    offset : float
+        Shift coordinates by this amount, typically to get pixel centers or edges.
+        Default is 0.5.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+        A FeatureCollection ready to be written as geojson.
+
+    """
+    collection = [
+        geojson.Feature(
+            geometry=shapely.Polygon(
+                np.fliplr((contour + offset) * rescale_factor)
+            ),  # shape object
+            properties=properties,  # object properties
+            id=str(uuid.uuid4()),  # object uuid
+        )
+        for contour in contours
+    ]
+
+    return geojson.FeatureCollection(collection)
+
+
+
+ +
+ +
+ + +

+ get_collection_from_skel(skeleton, properties, rescale_factor=1.0, offset=0.5) + +#

+ + +
+ +

Get the coordinates of each skeleton path as a GeoJSON Features in a +FeatureCollection. +properties is a dictionnary with QuPath properties of each detections.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ skeleton + + Skeleton + +
+ +
+
+ required +
+ properties + + dict + +
+

QuPatj objects' properties.

+
+
+ required +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1.0 +
+ offset + + float + +
+

Shift coordinates by this amount, typically to get pixel centers or edges. +Default is 0.5.

+
+
+ 0.5 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+

A FeatureCollection ready to be written as geojson.

+
+
+ +
+ Source code in cuisto/seg.py +
def get_collection_from_skel(
+    skeleton: Skeleton, properties: dict, rescale_factor: float = 1.0, offset=0.5
+) -> geojson.FeatureCollection:
+    """
+    Get the coordinates of each skeleton path as a GeoJSON Features in a
+    FeatureCollection.
+    `properties` is a dictionnary with QuPath properties of each detections.
+
+    Parameters
+    ----------
+    skeleton : skan.Skeleton
+    properties : dict
+        QuPatj objects' properties.
+    rescale_factor : float
+        Rescale output coordinates by this factor.
+    offset : float
+        Shift coordinates by this amount, typically to get pixel centers or edges.
+        Default is 0.5.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+        A FeatureCollection ready to be written as geojson.
+
+    """
+
+    branch_data = summarize(skeleton, separator="_")
+
+    collection = []
+    for ind in range(skeleton.n_paths):
+        prop = properties.copy()
+        prop["measurements"] = {"skeleton_id": int(branch_data.loc[ind, "skeleton_id"])}
+        collection.append(
+            geojson.Feature(
+                geometry=shapely.LineString(
+                    (skeleton.path_coordinates(ind)[:, ::-1] + offset) * rescale_factor
+                ),  # shape object
+                properties=prop,  # object properties
+                id=str(uuid.uuid4()),  # object uuid
+            )
+        )
+
+    return geojson.FeatureCollection(collection)
+
+
+
+ +
+ +
+ + +

+ get_image_skeleton(img, minsize=0) + +#

+ + +
+ +

Get the image skeleton.

+

Computes the image skeleton and removes objects smaller than minsize.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ img + + ndarray of bool + +
+ +
+
+ required +
+ minsize + + number + +
+

Min. size the object can have, as a number of pixels. Default is 0.

+
+
+ 0 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
skel + ndarray of bool + +
+

Binary image with 1-pixel wide skeleton.

+
+
+ +
+ Source code in cuisto/seg.py +
def get_image_skeleton(img: np.ndarray, minsize=0) -> np.ndarray:
+    """
+    Get the image skeleton.
+
+    Computes the image skeleton and removes objects smaller than `minsize`.
+
+    Parameters
+    ----------
+    img : ndarray of bool
+    minsize : number, optional
+        Min. size the object can have, as a number of pixels. Default is 0.
+
+    Returns
+    -------
+    skel : ndarray of bool
+        Binary image with 1-pixel wide skeleton.
+
+    """
+
+    skel = morphology.skeletonize(img)
+
+    return morphology.remove_small_objects(skel, min_size=minsize, connectivity=2)
+
+
+
+ +
+ +
+ + +

+ get_pixelsize(image_name) + +#

+ + +
+ +

Get pixel size recorded in image_name TIFF metadata.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ image_name + + str + +
+

Full path to image.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
pixelsize + float + +
+

Pixel size in microns.

+
+
+ +
+ Source code in cuisto/seg.py +
18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
def get_pixelsize(image_name: str) -> float:
+    """
+    Get pixel size recorded in `image_name` TIFF metadata.
+
+    Parameters
+    ----------
+    image_name : str
+        Full path to image.
+
+    Returns
+    -------
+    pixelsize : float
+        Pixel size in microns.
+
+    """
+
+    with tifffile.TiffFile(image_name) as tif:
+        # XResolution is a tuple, numerator, denomitor. The inverse is the pixel size
+        return (
+            tif.pages[0].tags["XResolution"].value[1]
+            / tif.pages[0].tags["XResolution"].value[0]
+        )
+
+
+
+ +
+ +
+ + +

+ pad_image(img, finalsize) + +#

+ + +
+ +

Pad image with zeroes to match expected final size.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ img + + ndarray + +
+ +
+
+ required +
+ finalsize + + tuple or list + +
+

nrows, ncolumns

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
imgpad + ndarray + +
+

img with black borders.

+
+
+ +
+ Source code in cuisto/seg.py +
68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
def pad_image(img: np.ndarray, finalsize: tuple | list) -> np.ndarray:
+    """
+    Pad image with zeroes to match expected final size.
+
+    Parameters
+    ----------
+    img : ndarray
+    finalsize : tuple or list
+        nrows, ncolumns
+
+    Returns
+    -------
+    imgpad : ndarray
+        img with black borders.
+
+    """
+
+    final_h = finalsize[0]  # requested number of rows (height)
+    final_w = finalsize[1]  # requested number of columns (width)
+    original_h = img.shape[0]  # input number of rows
+    original_w = img.shape[1]  # input number of columns
+
+    a = (final_h - original_h) // 2  # vertical padding before
+    aa = final_h - a - original_h  # vertical padding after
+    b = (final_w - original_w) // 2  # horizontal padding before
+    bb = final_w - b - original_w  # horizontal padding after
+
+    return np.pad(img, pad_width=((a, aa), (b, bb)), mode="constant")
+
+
+
+ +
+ +
+ + +

+ segment_lines(img, geojson_props, minsize=0.0, rescale_factor=1.0) + +#

+ + +
+ +

Wraps skeleton analysis to get paths coordinates.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ img + + ndarray of bool + +
+

Binary image to segment as lines.

+
+
+ required +
+ geojson_props + + dict + +
+

GeoJSON properties of objects.

+
+
+ required +
+ minsize + + float + +
+

Minimum size in pixels for an object.

+
+
+ 0.0 +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1.0 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+

A FeatureCollection ready to be written as geojson.

+
+
+ +
+ Source code in cuisto/seg.py +
def segment_lines(
+    img: np.ndarray, geojson_props: dict, minsize=0.0, rescale_factor=1.0
+) -> geojson.FeatureCollection:
+    """
+    Wraps skeleton analysis to get paths coordinates.
+
+    Parameters
+    ----------
+    img : ndarray of bool
+        Binary image to segment as lines.
+    geojson_props : dict
+        GeoJSON properties of objects.
+    minsize : float
+        Minimum size in pixels for an object.
+    rescale_factor : float
+        Rescale output coordinates by this factor.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+        A FeatureCollection ready to be written as geojson.
+
+    """
+
+    skel = get_image_skeleton(img, minsize=minsize)
+
+    # get paths coordinates as FeatureCollection
+    skeleton = Skeleton(skel, keep_images=False)
+    return get_collection_from_skel(
+        skeleton, geojson_props, rescale_factor=rescale_factor
+    )
+
+
+
+ +
+ +
+ + +

+ segment_points(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0, ecc_max=1, dist_thresh=0, rescale_factor=1) + +#

+ + +
+ +

Point segmentation.

+

First, segment polygons to apply shape filters, then extract their centroids, +and remove isolated points as defined by dist_thresh.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ img + + ndarray of bool + +
+

Binary image to segment as points.

+
+
+ required +
+ geojson_props + + dict + +
+

GeoJSON properties of objects.

+
+
+ required +
+ area_min + + float + +
+

Minimum and maximum area in pixels for an object.

+
+
+ 0.0 +
+ area_max + + float + +
+

Minimum and maximum area in pixels for an object.

+
+
+ 0.0 +
+ ecc_min + + float + +
+

Minimum and maximum eccentricity for an object.

+
+
+ 0 +
+ ecc_max + + float + +
+

Minimum and maximum eccentricity for an object.

+
+
+ 0 +
+ dist_thresh + + float + +
+

Maximal distance in pixels between objects before considering them as isolated and remove them. +0 disables it.

+
+
+ 0 +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+

A FeatureCollection ready to be written as geojson.

+
+
+ +
+ Source code in cuisto/seg.py +
def segment_points(
+    img: np.ndarray,
+    geojson_props: dict,
+    area_min: float = 0.0,
+    area_max: float = np.inf,
+    ecc_min: float = 0,
+    ecc_max: float = 1,
+    dist_thresh: float = 0,
+    rescale_factor: float = 1,
+) -> geojson.FeatureCollection:
+    """
+    Point segmentation.
+
+    First, segment polygons to apply shape filters, then extract their centroids,
+    and remove isolated points as defined by `dist_thresh`.
+
+    Parameters
+    ----------
+    img : ndarray of bool
+        Binary image to segment as points.
+    geojson_props : dict
+        GeoJSON properties of objects.
+    area_min, area_max : float
+        Minimum and maximum area in pixels for an object.
+    ecc_min, ecc_max : float
+        Minimum and maximum eccentricity for an object.
+    dist_thresh : float
+        Maximal distance in pixels between objects before considering them as isolated and remove them.
+        0 disables it.
+    rescale_factor : float
+        Rescale output coordinates by this factor.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+        A FeatureCollection ready to be written as geojson.
+
+    """
+
+    # get objects properties
+    stats = pd.DataFrame(
+        measure.regionprops_table(
+            measure.label(img), properties=("label", "area", "eccentricity", "centroid")
+        )
+    )
+
+    # keep objects matching filters
+    stats = stats[
+        (stats["area"] >= area_min)
+        & (stats["area"] <= area_max)
+        & (stats["eccentricity"] >= ecc_min)
+        & (stats["eccentricity"] <= ecc_max)
+    ]
+
+    # create an image from centroids only
+    stats["centroid-0"] = stats["centroid-0"].astype(int)
+    stats["centroid-1"] = stats["centroid-1"].astype(int)
+    bw = np.zeros(img.shape, dtype=bool)
+    bw[stats["centroid-0"], stats["centroid-1"]] = True
+
+    # filter isolated objects
+    if dist_thresh:
+        # dilation of points
+        if dist_thresh % 2 == 0:
+            dist_thresh += 1  # decomposition requires even number
+
+        footprint = morphology.square(int(dist_thresh), decomposition="sequence")
+        dilated = measure.label(morphology.binary_dilation(bw, footprint=footprint))
+        stats = pd.DataFrame(
+            measure.regionprops_table(dilated, properties=("label", "area"))
+        )
+
+        # objects that did not merge are alone
+        toremove = stats[(stats["area"] <= dist_thresh**2)]
+        dilated[np.isin(dilated, toremove["label"])] = 0  # remove them
+
+        # apply mask
+        bw = bw * dilated
+
+    # get points coordinates
+    coords = np.argwhere(bw)
+
+    return get_collection_from_points(
+        coords, geojson_props, rescale_factor=rescale_factor
+    )
+
+
+
+ +
+ +
+ + +

+ segment_polygons(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0.0, ecc_max=1.0, rescale_factor=1.0) + +#

+ + +
+ +

Polygon segmentation.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ img + + ndarray of bool + +
+

Binary image to segment as polygons.

+
+
+ required +
+ geojson_props + + dict + +
+

GeoJSON properties of objects.

+
+
+ required +
+ area_min + + float + +
+

Minimum and maximum area in pixels for an object.

+
+
+ 0.0 +
+ area_max + + float + +
+

Minimum and maximum area in pixels for an object.

+
+
+ 0.0 +
+ ecc_min + + float + +
+

Minimum and maximum eccentricity for an object.

+
+
+ 0.0 +
+ ecc_max + + float + +
+

Minimum and maximum eccentricity for an object.

+
+
+ 0.0 +
+ rescale_factor + + float + +
+

Rescale output coordinates by this factor.

+
+
+ 1.0 +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
collection + FeatureCollection + +
+

A FeatureCollection ready to be written as geojson.

+
+
+ +
+ Source code in cuisto/seg.py +
def segment_polygons(
+    img: np.ndarray,
+    geojson_props: dict,
+    area_min: float = 0.0,
+    area_max: float = np.inf,
+    ecc_min: float = 0.0,
+    ecc_max: float = 1.0,
+    rescale_factor: float = 1.0,
+) -> geojson.FeatureCollection:
+    """
+    Polygon segmentation.
+
+    Parameters
+    ----------
+    img : ndarray of bool
+        Binary image to segment as polygons.
+    geojson_props : dict
+        GeoJSON properties of objects.
+    area_min, area_max : float
+        Minimum and maximum area in pixels for an object.
+    ecc_min, ecc_max : float
+        Minimum and maximum eccentricity for an object.
+    rescale_factor: float
+        Rescale output coordinates by this factor.
+
+    Returns
+    -------
+    collection : geojson.FeatureCollection
+        A FeatureCollection ready to be written as geojson.
+
+    """
+
+    label_image = measure.label(img)
+
+    # get objects properties
+    stats = pd.DataFrame(
+        measure.regionprops_table(
+            label_image, properties=("label", "area", "eccentricity")
+        )
+    )
+
+    # remove objects not matching filters
+    toremove = stats[
+        (stats["area"] < area_min)
+        | (stats["area"] > area_max)
+        | (stats["eccentricity"] < ecc_min)
+        | (stats["eccentricity"] > ecc_max)
+    ]
+
+    label_image[np.isin(label_image, toremove["label"])] = 0
+
+    # find objects countours
+    label_image = label_image > 0
+    contours = measure.find_contours(label_image)
+
+    return get_collection_from_poly(
+        contours, geojson_props, rescale_factor=rescale_factor
+    )
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-utils.html b/api-utils.html new file mode 100644 index 0000000..38d2f0a --- /dev/null +++ b/api-utils.html @@ -0,0 +1,4567 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + cuisto.utils - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

cuisto.utils

+ +
+ + + + +
+ +

utils module, part of cuisto.

+

Contains utilities functions.

+ + + + + + + + +
+ + + + + + + + + +
+ + +

+ add_brain_region(df, atlas, col='Parent') + +#

+ + +
+ +

Add brain region to a DataFrame with Atlas_X, Atlas_Y and Atlas_Z columns.

+

This uses Brainglobe Atlas API to query the atlas. It does not use the +structure_from_coords() method, instead it manually converts the coordinates in +stack indices, then get the corresponding annotation id and query the corresponding +acronym -- because brainglobe-atlasapi is not vectorized at all.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

DataFrame with atlas coordinates in microns.

+
+
+ required +
+ atlas + + BrainGlobeAtlas + +
+ +
+
+ required +
+ col + + str + +
+

Column in which to put the regions acronyms. Default is "Parent".

+
+
+ 'Parent' +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

Same DataFrame with a new "Parent" column.

+
+
+ +
+ Source code in cuisto/utils.py +
def add_brain_region(
+    df: pd.DataFrame, atlas: BrainGlobeAtlas, col="Parent"
+) -> pd.DataFrame:
+    """
+    Add brain region to a DataFrame with `Atlas_X`, `Atlas_Y` and `Atlas_Z` columns.
+
+    This uses Brainglobe Atlas API to query the atlas. It does not use the
+    structure_from_coords() method, instead it manually converts the coordinates in
+    stack indices, then get the corresponding annotation id and query the corresponding
+    acronym -- because brainglobe-atlasapi is not vectorized at all.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        DataFrame with atlas coordinates in microns.
+    atlas : BrainGlobeAtlas
+    col : str, optional
+        Column in which to put the regions acronyms. Default is "Parent".
+
+    Returns
+    -------
+    df : pd.DataFrame
+        Same DataFrame with a new "Parent" column.
+
+    """
+    df_in = df.copy()
+
+    res = atlas.resolution  # microns <-> pixels conversion
+    lims = atlas.shape_um  # out of brain
+
+    # set out-of-brain objects at 0 so we get "root" as their parent
+    df_in.loc[(df_in["Atlas_X"] >= lims[0]) | (df_in["Atlas_X"] < 0), "Atlas_X"] = 0
+    df_in.loc[(df_in["Atlas_Y"] >= lims[1]) | (df_in["Atlas_Y"] < 0), "Atlas_Y"] = 0
+    df_in.loc[(df_in["Atlas_Z"] >= lims[2]) | (df_in["Atlas_Z"] < 0), "Atlas_Z"] = 0
+
+    # build the multi index, in pixels and integers
+    ixyz = (
+        df_in["Atlas_X"].divide(res[0]).astype(int),
+        df_in["Atlas_Y"].divide(res[1]).astype(int),
+        df_in["Atlas_Z"].divide(res[2]).astype(int),
+    )
+    # convert i, j, k indices in raveled indices
+    linear_indices = np.ravel_multi_index(ixyz, dims=atlas.annotation.shape)
+    # get the structure id from the annotation stack
+    idlist = atlas.annotation.ravel()[linear_indices]
+    # replace 0 which does not exist to 997 (root)
+    idlist[idlist == 0] = 997
+
+    # query the corresponding acronyms
+    lookup = atlas.lookup_df.set_index("id")
+    df.loc[:, col] = lookup.loc[idlist, "acronym"].values
+
+    return df
+
+
+
+ +
+ +
+ + +

+ add_channel(df, object_type, channel_names) + +#

+ + +
+ +

Add channel as a measurement for detections DataFrame.

+

The channel is read from the Classification column, the latter having to be +formatted as "object_type: channel".

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

DataFrame with detections measurements.

+
+
+ required +
+ object_type + + str + +
+

Object type (primary classification).

+
+
+ required +
+ channel_names + + dict + +
+

Map between original channel names to something else.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ DataFrame + +
+

Same DataFrame with a "channel" column.

+
+
+ +
+ Source code in cuisto/utils.py +
def add_channel(
+    df: pd.DataFrame, object_type: str, channel_names: dict
+) -> pd.DataFrame:
+    """
+    Add channel as a measurement for detections DataFrame.
+
+    The channel is read from the Classification column, the latter having to be
+    formatted as "object_type: channel".
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        DataFrame with detections measurements.
+    object_type : str
+        Object type (primary classification).
+    channel_names : dict
+        Map between original channel names to something else.
+
+    Returns
+    -------
+    pd.DataFrame
+        Same DataFrame with a "channel" column.
+
+    """
+    # check if there is something to do
+    if "channel" in df.columns:
+        return df
+
+    kind = get_df_kind(df)
+    if kind == "annotation":
+        warnings.warn("Annotation DataFrame not supported.")
+        return df
+
+    # add channel, from {class_name: channel} classification
+    df["channel"] = (
+        df["Classification"].str.replace(object_type + ": ", "").map(channel_names)
+    )
+
+    return df
+
+
+
+ +
+ +
+ + +

+ add_hemisphere(df, hemisphere_names, midline=5700, col='Atlas_Z', atlas_type='brain') + +#

+ + +
+ +

Add hemisphere (left/right) as a measurement for detections or annotations.

+

The hemisphere is read in the "Classification" column for annotations. The latter +needs to be in the form "Right: Name" or "Left: Name". For detections, the input +col of df is compared to midline to assess if the object belong to the left or +right hemispheres.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

DataFrame with detections or annotations measurements.

+
+
+ required +
+ hemisphere_names + + dict + +
+

Map between "Left" and "Right" to something else.

+
+
+ required +
+ midline + + float + +
+

Used only for "detections" df. Corresponds to the brain midline in microns, +should be 5700 for CCFv3 and 1610 for spinal cord.

+
+
+ 5700 +
+ col + + str + +
+

Name of the column containing the Z coordinate (medio-lateral) in microns. +Default is "Atlas_Z".

+
+
+ 'Atlas_Z' +
+ atlas_type + + (brain, cord) + +
+

Type of atlas used for registration. Required because the brain atlas is swapped +between left and right while the spinal cord atlas is not. Default is "brain".

+
+
+ "brain" +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

The same DataFrame with a new "hemisphere" column

+
+
+ +
+ Source code in cuisto/utils.py +
def add_hemisphere(
+    df: pd.DataFrame,
+    hemisphere_names: dict,
+    midline: float = 5700,
+    col: str = "Atlas_Z",
+    atlas_type: str = "brain",
+) -> pd.DataFrame:
+    """
+    Add hemisphere (left/right) as a measurement for detections or annotations.
+
+    The hemisphere is read in the "Classification" column for annotations. The latter
+    needs to be in the form "Right: Name" or "Left: Name". For detections, the input
+    `col` of `df` is compared to `midline` to assess if the object belong to the left or
+    right hemispheres.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+        DataFrame with detections or annotations measurements.
+    hemisphere_names : dict
+        Map between "Left" and "Right" to something else.
+    midline : float
+        Used only for "detections" `df`. Corresponds to the brain midline in microns,
+        should be 5700 for CCFv3 and 1610 for spinal cord.
+    col : str, optional
+        Name of the column containing the Z coordinate (medio-lateral) in microns.
+        Default is "Atlas_Z".
+    atlas_type : {"brain", "cord"}, optional
+        Type of atlas used for registration. Required because the brain atlas is swapped
+        between left and right while the spinal cord atlas is not. Default is "brain".
+
+    Returns
+    -------
+    df : pandas.DataFrame
+        The same DataFrame with a new "hemisphere" column
+
+    """
+    # check if there is something to do
+    if "hemisphere" in df.columns:
+        return df
+
+    # get kind of DataFrame
+    kind = get_df_kind(df)
+
+    if kind == "detection":
+        # use midline
+        if atlas_type == "brain":
+            # brain atlas : beyond midline, it's left
+            df.loc[df[col] >= midline, "hemisphere"] = hemisphere_names["Left"]
+            df.loc[df[col] < midline, "hemisphere"] = hemisphere_names["Right"]
+        elif atlas_type == "cord":
+            # cord atlas : below midline, it's left
+            df.loc[df[col] <= midline, "hemisphere"] = hemisphere_names["Left"]
+            df.loc[df[col] > midline, "hemisphere"] = hemisphere_names["Right"]
+
+    elif kind == "annotation":
+        # use Classification name -- this does not depend on atlas type
+        df["hemisphere"] = [name.split(":")[0] for name in df["Classification"]]
+        df["hemisphere"] = df["hemisphere"].map(hemisphere_names)
+
+    return df
+
+
+
+ +
+ +
+ + +

+ ccf_to_stereo(x_ccf, y_ccf, z_ccf=0) + +#

+ + +
+ +

Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in +Paxinos-Franklin atlas).

+

Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be +in mm. +x_ccf corresponds to the anterio-posterior (rostro-caudal) axis. +y_ccf corresponds to the dorso-ventral axis. +z_ccf corresponds to the medio-lateral axis (left-right) axis.

+

Warning : it is a rough estimation.

+

(1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ x_ccf + + floats or ndarray + +
+

Coordinates in CCFv3 space in mm.

+
+
+ required +
+ y_ccf + + floats or ndarray + +
+

Coordinates in CCFv3 space in mm.

+
+
+ required +
+ z_ccf + + float or ndarray + +
+

Coordinate in CCFv3 space in mm. Default is 0.

+
+
+ 0 +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ ap, dv, ml : floats or np.ndarray + +
+

Stereotaxic coordinates in mm.

+
+
+ +
+ Source code in cuisto/utils.py +
def ccf_to_stereo(
+    x_ccf: float | np.ndarray, y_ccf: float | np.ndarray, z_ccf: float | np.ndarray = 0
+) -> tuple:
+    """
+    Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in
+    Paxinos-Franklin atlas).
+
+    Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be
+    in mm.
+    `x_ccf` corresponds to the anterio-posterior (rostro-caudal) axis.
+    `y_ccf` corresponds to the dorso-ventral axis.
+    `z_ccf` corresponds to the medio-lateral axis (left-right) axis.
+
+    Warning : it is a rough estimation.
+
+    (1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858
+
+    Parameters
+    ----------
+    x_ccf, y_ccf : floats or np.ndarray
+        Coordinates in CCFv3 space in mm.
+    z_ccf : float or np.ndarray, optional
+        Coordinate in CCFv3 space in mm. Default is 0.
+
+    Returns
+    -------
+    ap, dv, ml : floats or np.ndarray
+        Stereotaxic coordinates in mm.
+
+    """
+    # Center CCF on Bregma
+    xstereo = -(x_ccf - 5.40)  # anterio-posterior coordinate (rostro-caudal)
+    ystereo = y_ccf - 0.44  # dorso-ventral coordinate
+    ml = z_ccf - 5.70  # medio-lateral coordinate (left-right)
+
+    # Rotate CCF of 5°
+    angle = np.deg2rad(5)
+    ap = xstereo * np.cos(angle) - ystereo * np.sin(angle)
+    dv = xstereo * np.sin(angle) + ystereo * np.cos(angle)
+
+    # Squeeze the dorso-ventral axis by 94.34%
+    dv *= 0.9434
+
+    return ap, dv, ml
+
+
+
+ +
+ +
+ + +

+ filter_df_classifications(df, filter_list, mode='keep', col='Classification') + +#

+ + +
+ +

Filter a DataFrame whether specified col column entries contain elements in +filter_list. Case insensitive.

+

If mode is "keep", keep entries only if their col in is in the list (default). +If mode is "remove", remove entries if their col is in the list.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ filter_list + + list | tuple | str + +
+

List of words that should be present to trigger the filter.

+
+
+ required +
+ mode + + keep or remove + +
+

Keep or remove entries from the list. Default is "keep".

+
+
+ 'keep' +
+ col + + str + +
+

Key in df. Default is "Classification".

+
+
+ 'Classification' +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ DataFrame + +
+

Filtered DataFrame.

+
+
+ +
+ Source code in cuisto/utils.py +
def filter_df_classifications(
+    df: pd.DataFrame, filter_list: list | tuple | str, mode="keep", col="Classification"
+) -> pd.DataFrame:
+    """
+    Filter a DataFrame whether specified `col` column entries contain elements in
+    `filter_list`. Case insensitive.
+
+    If `mode` is "keep", keep entries only if their `col` in is in the list (default).
+    If `mode` is "remove", remove entries if their `col` is in the list.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+    filter_list : list | tuple | str
+        List of words that should be present to trigger the filter.
+    mode : "keep" or "remove", optional
+        Keep or remove entries from the list. Default is "keep".
+    col : str, optional
+        Key in `df`. Default is "Classification".
+
+    Returns
+    -------
+    pd.DataFrame
+        Filtered DataFrame.
+
+    """
+    # check input
+    if isinstance(filter_list, str):
+        filter_list = [filter_list]  # make sure it is a list
+
+    if col not in df.columns:
+        # might be because of 'Classification' instead of 'classification'
+        col = col.capitalize()
+        if col not in df.columns:
+            raise KeyError(f"{col} not in DataFrame.")
+
+    pattern = "|".join(f".*{s}.*" for s in filter_list)
+
+    if mode == "keep":
+        df_return = df[df[col].str.contains(pattern, case=False, regex=True)]
+    elif mode == "remove":
+        df_return = df[~df[col].str.contains(pattern, case=False, regex=True)]
+
+    # check
+    if len(df_return) == 0:
+        raise ValueError(
+            (
+                f"Filtering '{col}' with {filter_list} resulted in an"
+                + " empty DataFrame, check your config file."
+            )
+        )
+    return df_return
+
+
+
+ +
+ +
+ + +

+ filter_df_regions(df, filter_list, mode='keep', col='Parent') + +#

+ + +
+ +

Filters entries in df based on wether their col is in filter_list or not.

+

If mode is "keep", keep entries only if their col in is in the list (default). +If mode is "remove", remove entries if their col is in the list.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ filter_list + + list - like + +
+

List of regions to keep or remove from the DataFrame.

+
+
+ required +
+ mode + + keep or remove + +
+

Keep or remove entries from the list. Default is "keep".

+
+
+ 'keep' +
+ col + + str + +
+

Key in df. Default is "Parent".

+
+
+ 'Parent' +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

Filtered DataFrame.

+
+
+ +
+ Source code in cuisto/utils.py +
def filter_df_regions(
+    df: pd.DataFrame, filter_list: list | tuple, mode="keep", col="Parent"
+) -> pd.DataFrame:
+    """
+    Filters entries in `df` based on wether their `col` is in `filter_list` or not.
+
+    If `mode` is "keep", keep entries only if their `col` in is in the list (default).
+    If `mode` is "remove", remove entries if their `col` is in the list.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    filter_list : list-like
+        List of regions to keep or remove from the DataFrame.
+    mode : "keep" or "remove", optional
+        Keep or remove entries from the list. Default is "keep".
+    col : str, optional
+        Key in `df`. Default is "Parent".
+
+    Returns
+    -------
+    df : pandas.DataFrame
+        Filtered DataFrame.
+
+    """
+
+    if mode == "keep":
+        return df[df[col].isin(filter_list)]
+    if mode == "remove":
+        return df[~df[col].isin(filter_list)]
+
+
+
+ +
+ +
+ + +

+ get_blacklist(file, atlas) + +#

+ + +
+ +

Build a list of regions to exclude from file.

+

File must be a TOML with [WITH_CHILDS] and [EXACT] sections.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ file + + str + +
+

Full path the atlas_blacklist.toml file.

+
+
+ required +
+ atlas + + BrainGlobeAtlas + +
+

Atlas to extract regions from.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
black_list + list + +
+

Full list of acronyms to discard.

+
+
+ +
+ Source code in cuisto/utils.py +
def get_blacklist(file: str, atlas: BrainGlobeAtlas) -> list:
+    """
+    Build a list of regions to exclude from file.
+
+    File must be a TOML with [WITH_CHILDS] and [EXACT] sections.
+
+    Parameters
+    ----------
+    file : str
+        Full path the atlas_blacklist.toml file.
+    atlas : BrainGlobeAtlas
+        Atlas to extract regions from.
+
+    Returns
+    -------
+    black_list : list
+        Full list of acronyms to discard.
+
+    """
+    with open(file, "rb") as fid:
+        content = tomllib.load(fid)
+
+    blacklist = []  # init. the list
+
+    # add regions and their descendants
+    for region in content["WITH_CHILDS"]["members"]:
+        blacklist.extend(
+            [
+                atlas.structures[id]["acronym"]
+                for id in atlas.structures.tree.expand_tree(
+                    atlas.structures[region]["id"]
+                )
+            ]
+        )
+
+    # add regions specified exactly (no descendants)
+    blacklist.extend(content["EXACT"]["members"])
+
+    return blacklist
+
+
+
+ +
+ +
+ + +

+ get_data_coverage(df, col='Atlas_AP', by='animal') + +#

+ + +
+ +

Get min and max in col for each by.

+

Used to get data coverage for each animal to plot in distributions.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

description

+
+
+ required +
+ col + + str + +
+

Key in df, default is "Atlas_X".

+
+
+ 'Atlas_AP' +
+ by + + str + +
+

Key in df , default is "animal".

+
+
+ 'animal' +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ DataFrame + +
+

min and max of col for each by, named "X_min", and "X_max".

+
+
+ +
+ Source code in cuisto/utils.py +
def get_data_coverage(df: pd.DataFrame, col="Atlas_AP", by="animal") -> pd.DataFrame:
+    """
+    Get min and max in `col` for each `by`.
+
+    Used to get data coverage for each animal to plot in distributions.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        _description_
+    col : str, optional
+        Key in `df`, default is "Atlas_X".
+    by : str, optional
+        Key in `df` , default is "animal".
+
+    Returns
+    -------
+    pd.DataFrame
+        min and max of `col` for each `by`, named "X_min", and "X_max".
+
+    """
+    df_group = df.groupby([by])
+    return pd.DataFrame(
+        [
+            df_group[col].min(),
+            df_group[col].max(),
+        ],
+        index=["X_min", "X_max"],
+    )
+
+
+
+ +
+ +
+ + +

+ get_df_kind(df) + +#

+ + +
+ +

Get DataFrame kind, eg. Annotations or Detections.

+

It is based on reading the Object Type of the first entry, so the DataFrame must +have only one kind of object.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
kind + str + +
+

"detection" or "annotation".

+
+
+ +
+ Source code in cuisto/utils.py +
def get_df_kind(df: pd.DataFrame) -> str:
+    """
+    Get DataFrame kind, eg. Annotations or Detections.
+
+    It is based on reading the Object Type of the first entry, so the DataFrame must
+    have only one kind of object.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+
+    Returns
+    -------
+    kind : str
+        "detection" or "annotation".
+
+    """
+    return df["Object type"].iloc[0].lower()
+
+
+
+ +
+ +
+ + +

+ get_injection_site(animal, info_file, channel, stereo=False) + +#

+ + +
+ +

Get the injection site coordinates associated with animal.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ animal + + str + +
+

Animal ID.

+
+
+ required +
+ info_file + + str + +
+

Path to TOML info file.

+
+
+ required +
+ channel + + str + +
+

Channel ID as in the TOML file.

+
+
+ required +
+ stereo + + bool + +
+

Wether to convert coordinates in stereotaxis coordinates. Default is False.

+
+
+ False +
+ + +

Returns:

+ + + + + + + + + + + + + +
TypeDescription
+ x, y, z : floats + +
+

Injection site coordinates.

+
+
+ +
+ Source code in cuisto/utils.py +
40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
def get_injection_site(
+    animal: str, info_file: str, channel: str, stereo: bool = False
+) -> tuple:
+    """
+    Get the injection site coordinates associated with animal.
+
+    Parameters
+    ----------
+    animal : str
+        Animal ID.
+    info_file : str
+        Path to TOML info file.
+    channel : str
+        Channel ID as in the TOML file.
+    stereo : bool, optional
+        Wether to convert coordinates in stereotaxis coordinates. Default is False.
+
+    Returns
+    -------
+    x, y, z : floats
+        Injection site coordinates.
+
+    """
+    with open(info_file, "rb") as fid:
+        info = tomllib.load(fid)
+
+    if channel in info[animal]:
+        x, y, z = info[animal][channel]["injection_site"]
+        if stereo:
+            x, y, z = ccf_to_stereo(x, y, z)
+    else:
+        x, y, z = None, None, None
+
+    return x, y, z
+
+
+
+ +
+ +
+ + +

+ get_leaves_list(atlas) + +#

+ + +
+ +

Get the list of leaf brain regions.

+

Leaf brain regions are defined as regions without childs, eg. regions that are at +the bottom of the hiearchy.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ atlas + + BrainGlobeAtlas + +
+

Atlas to extract regions from.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
leaves_list + list + +
+

Acronyms of leaf brain regions.

+
+
+ +
+ Source code in cuisto/utils.py +
def get_leaves_list(atlas: BrainGlobeAtlas) -> list:
+    """
+    Get the list of leaf brain regions.
+
+    Leaf brain regions are defined as regions without childs, eg. regions that are at
+    the bottom of the hiearchy.
+
+    Parameters
+    ----------
+    atlas : BrainGlobeAtlas
+        Atlas to extract regions from.
+
+    Returns
+    -------
+    leaves_list : list
+        Acronyms of leaf brain regions.
+
+    """
+    leaves_list = []
+    for region in atlas.structures_list:
+        if atlas.structures.tree[region["id"]].is_leaf():
+            leaves_list.append(region["acronym"])
+
+    return leaves_list
+
+
+
+ +
+ +
+ + +

+ get_mapping_fusion(fusion_file) + +#

+ + +
+ +

Get mapping dictionnary between input brain regions and new regions defined in +atlas_fusion.toml file.

+

The returned dictionnary can be used in DataFrame.replace().

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ fusion_file + + str + +
+

Path to the TOML file with the merging rules.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
m + dict + +
+

Mapping as {old: new}.

+
+
+ +
+ Source code in cuisto/utils.py +
def get_mapping_fusion(fusion_file: str) -> dict:
+    """
+    Get mapping dictionnary between input brain regions and new regions defined in
+    `atlas_fusion.toml` file.
+
+    The returned dictionnary can be used in DataFrame.replace().
+
+    Parameters
+    ----------
+    fusion_file : str
+        Path to the TOML file with the merging rules.
+
+    Returns
+    -------
+    m : dict
+        Mapping as {old: new}.
+
+    """
+    with open(fusion_file, "rb") as fid:
+        df = pd.DataFrame.from_dict(tomllib.load(fid), orient="index").set_index(
+            "acronym"
+        )
+
+    return (
+        df.drop(columns="name")["members"]
+        .explode()
+        .reset_index()
+        .set_index("members")
+        .to_dict()["acronym"]
+    )
+
+
+
+ +
+ +
+ + +

+ get_starter_cells(animal, channel, info_file) + +#

+ + +
+ +

Get the number of starter cells associated with animal.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ animal + + str + +
+

Animal ID.

+
+
+ required +
+ channel + + str + +
+

Channel ID.

+
+
+ required +
+ info_file + + str + +
+

Path to TOML info file.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
n_starters + int + +
+

Number of starter cells.

+
+
+ +
+ Source code in cuisto/utils.py +
15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
def get_starter_cells(animal: str, channel: str, info_file: str) -> int:
+    """
+    Get the number of starter cells associated with animal.
+
+    Parameters
+    ----------
+    animal : str
+        Animal ID.
+    channel : str
+        Channel ID.
+    info_file : str
+        Path to TOML info file.
+
+    Returns
+    -------
+    n_starters : int
+        Number of starter cells.
+
+    """
+    with open(info_file, "rb") as fid:
+        info = tomllib.load(fid)
+
+    return info[animal][channel]["starter_cells"]
+
+
+
+ +
+ +
+ + +

+ merge_regions(df, col, fusion_file) + +#

+ + +
+ +

Merge brain regions following rules in the fusion_file.toml file.

+

Apply this merging on col of the input DataFrame. col whose value is found in +the members sections in the file will be changed to the new acronym.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ col + + str + +
+

Column of df on which to apply the mapping.

+
+
+ required +
+ fusion_file + + str + +
+

Path to the toml file with the merging rules.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

Same DataFrame with regions renamed.

+
+
+ +
+ Source code in cuisto/utils.py +
def merge_regions(df: pd.DataFrame, col: str, fusion_file: str) -> pd.DataFrame:
+    """
+    Merge brain regions following rules in the `fusion_file.toml` file.
+
+    Apply this merging on `col` of the input DataFrame. `col` whose value is found in
+    the `members` sections in the file will be changed to the new acronym.
+
+    Parameters
+    ----------
+    df : pandas.DataFrame
+    col : str
+        Column of `df` on which to apply the mapping.
+    fusion_file : str
+        Path to the toml file with the merging rules.
+
+    Returns
+    -------
+    df : pandas.DataFrame
+        Same DataFrame with regions renamed.
+
+    """
+    df[col] = df[col].replace(get_mapping_fusion(fusion_file))
+
+    return df
+
+
+
+ +
+ +
+ + +

+ renormalize_per_key(df, by, on) + +#

+ + +
+ +

Renormalize on column by its sum for each by.

+

Use case : relative density is computed for both hemispheres, so if one wants to +plot only one hemisphere, the sum of the bars corresponding to one channel (by) +should be 1. So :

+
+
+
+

df = df[df["hemisphere"] == "Ipsi."] +df = renormalize_per_key(df, "channel", "relative density") +Then, the sum of "relative density" for each "channel" equals 1.

+
+
+
+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+ +
+
+ required +
+ by + + str + +
+

Key in df. df is normalized for each by.

+
+
+ required +
+ on + + str + +
+

Key in df. Measurement to be normalized.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
df + DataFrame + +
+

Same DataFrame with normalized on column.

+
+
+ +
+ Source code in cuisto/utils.py +
def renormalize_per_key(df: pd.DataFrame, by: str, on: str):
+    """
+    Renormalize `on` column by its sum for each `by`.
+
+    Use case : relative density is computed for both hemispheres, so if one wants to
+    plot only one hemisphere, the sum of the bars corresponding to one channel (`by`)
+    should be 1. So :
+    >>> df = df[df["hemisphere"] == "Ipsi."]
+    >>> df = renormalize_per_key(df, "channel", "relative density")
+    Then, the sum of "relative density" for each "channel" equals 1.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+    by : str
+        Key in `df`. `df` is normalized for each `by`.
+    on : str
+        Key in `df`. Measurement to be normalized.
+
+    Returns
+    -------
+    df : pd.DataFrame
+        Same DataFrame with normalized `on` column.
+
+    """
+    norm = df.groupby(by)[on].sum()
+    bys = df[by].unique()
+    for key in bys:
+        df.loc[df[by] == key, on] = df.loc[df[by] == key, on].divide(norm[key])
+
+    return df
+
+
+
+ +
+ +
+ + +

+ select_hemisphere_channel(df, hue, hue_filter, hue_mirror) + +#

+ + +
+ +

Select relevant data given hue and filters.

+

Returns the DataFrame with only things to be used.

+ + +

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionDefault
+ df + + DataFrame + +
+

DataFrame to filter.

+
+
+ required +
+ hue + + (hemisphere, channel) + +
+

hue that will be used in seaborn plots.

+
+
+ "hemisphere" +
+ hue_filter + + str + +
+

Selected data.

+
+
+ required +
+ hue_mirror + + bool + +
+

Instead of keeping only hue_filter values, they will be plotted in mirror.

+
+
+ required +
+ + +

Returns:

+ + + + + + + + + + + + + +
Name TypeDescription
dfplt + DataFrame + +
+

DataFrame to be used in plots.

+
+
+ +
+ Source code in cuisto/utils.py +
def select_hemisphere_channel(
+    df: pd.DataFrame, hue: str, hue_filter: str, hue_mirror: bool
+) -> pd.DataFrame:
+    """
+    Select relevant data given hue and filters.
+
+    Returns the DataFrame with only things to be used.
+
+    Parameters
+    ----------
+    df : pd.DataFrame
+        DataFrame to filter.
+    hue : {"hemisphere", "channel"}
+        hue that will be used in seaborn plots.
+    hue_filter : str
+        Selected data.
+    hue_mirror : bool
+        Instead of keeping only hue_filter values, they will be plotted in mirror.
+
+    Returns
+    -------
+    dfplt : pd.DataFrame
+        DataFrame to be used in plots.
+
+    """
+    dfplt = df.copy()
+
+    if hue == "hemisphere":
+        # hue_filter is used to select channels
+        # keep only left and right hemispheres, not "both"
+        dfplt = dfplt[dfplt["hemisphere"] != "both"]
+        if hue_filter == "all":
+            hue_filter = dfplt["channel"].unique()
+        elif not isinstance(hue_filter, (list, tuple)):
+            # it is allowed to select several channels so handle lists
+            hue_filter = [hue_filter]
+        dfplt = dfplt[dfplt["channel"].isin(hue_filter)]
+    elif hue == "channel":
+        # hue_filter is used to select hemispheres
+        # it can only be left, right, both or empty
+        if hue_filter == "both":
+            # handle if it's a coordinates DataFrame which doesn't have "both"
+            if "both" not in dfplt["hemisphere"].unique():
+                # keep both hemispheres, don't do anything
+                pass
+            else:
+                if hue_mirror:
+                    # we need to keep both hemispheres to plot them in mirror
+                    dfplt = dfplt[dfplt["hemisphere"] != "both"]
+                else:
+                    # we keep the metrics computed in both hemispheres
+                    dfplt = dfplt[dfplt["hemisphere"] == "both"]
+        else:
+            # hue_filter should correspond to an hemisphere name
+            dfplt = dfplt[dfplt["hemisphere"] == hue_filter]
+    else:
+        # not handled. Just return the DataFrame without filtering, maybe it'll make
+        # sense.
+        warnings.warn(f"{hue} should be 'channel' or 'hemisphere'.")
+
+    # check result
+    if len(dfplt) == 0:
+        warnings.warn(
+            f"hue={hue} and hue_filter={hue_filter} resulted in an empty subset."
+        )
+
+    return dfplt
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/_mkdocstrings.css b/assets/_mkdocstrings.css new file mode 100644 index 0000000..b500381 --- /dev/null +++ b/assets/_mkdocstrings.css @@ -0,0 +1,143 @@ + +/* Avoid breaking parameter names, etc. in table cells. */ +.doc-contents td code { + word-break: normal !important; +} + +/* No line break before first paragraph of descriptions. */ +.doc-md-description, +.doc-md-description>p:first-child { + display: inline; +} + +/* Max width for docstring sections tables. */ +.doc .md-typeset__table, +.doc .md-typeset__table table { + display: table !important; + width: 100%; +} + +.doc .md-typeset__table tr { + display: table-row; +} + +/* Defaults in Spacy table style. */ +.doc-param-default { + float: right; +} + +/* Parameter headings must be inline, not blocks. */ +.doc-heading-parameter { + display: inline; +} + +/* Prefer space on the right, not the left of parameter permalinks. */ +.doc-heading-parameter .headerlink { + margin-left: 0 !important; + margin-right: 0.2rem; +} + +/* Backward-compatibility: docstring section titles in bold. */ +.doc-section-title { + font-weight: bold; +} + +/* Symbols in Navigation and ToC. */ +:root, :host, +[data-md-color-scheme="default"] { + --doc-symbol-parameter-fg-color: #df50af; + --doc-symbol-attribute-fg-color: #953800; + --doc-symbol-function-fg-color: #8250df; + --doc-symbol-method-fg-color: #8250df; + --doc-symbol-class-fg-color: #0550ae; + --doc-symbol-module-fg-color: #5cad0f; + + --doc-symbol-parameter-bg-color: #df50af1a; + --doc-symbol-attribute-bg-color: #9538001a; + --doc-symbol-function-bg-color: #8250df1a; + --doc-symbol-method-bg-color: #8250df1a; + --doc-symbol-class-bg-color: #0550ae1a; + --doc-symbol-module-bg-color: #5cad0f1a; +} + +[data-md-color-scheme="slate"] { + --doc-symbol-parameter-fg-color: #ffa8cc; + --doc-symbol-attribute-fg-color: #ffa657; + --doc-symbol-function-fg-color: #d2a8ff; + --doc-symbol-method-fg-color: #d2a8ff; + --doc-symbol-class-fg-color: #79c0ff; + --doc-symbol-module-fg-color: #baff79; + + --doc-symbol-parameter-bg-color: #ffa8cc1a; + --doc-symbol-attribute-bg-color: #ffa6571a; + --doc-symbol-function-bg-color: #d2a8ff1a; + --doc-symbol-method-bg-color: #d2a8ff1a; + --doc-symbol-class-bg-color: #79c0ff1a; + --doc-symbol-module-bg-color: #baff791a; +} + +code.doc-symbol { + border-radius: .1rem; + font-size: .85em; + padding: 0 .3em; + font-weight: bold; +} + +code.doc-symbol-parameter { + color: var(--doc-symbol-parameter-fg-color); + background-color: var(--doc-symbol-parameter-bg-color); +} + +code.doc-symbol-parameter::after { + content: "param"; +} + +code.doc-symbol-attribute { + color: var(--doc-symbol-attribute-fg-color); + background-color: var(--doc-symbol-attribute-bg-color); +} + +code.doc-symbol-attribute::after { + content: "attr"; +} + +code.doc-symbol-function { + color: var(--doc-symbol-function-fg-color); + background-color: var(--doc-symbol-function-bg-color); +} + +code.doc-symbol-function::after { + content: "func"; +} + +code.doc-symbol-method { + color: var(--doc-symbol-method-fg-color); + background-color: var(--doc-symbol-method-bg-color); +} + +code.doc-symbol-method::after { + content: "meth"; +} + +code.doc-symbol-class { + color: var(--doc-symbol-class-fg-color); + background-color: var(--doc-symbol-class-bg-color); +} + +code.doc-symbol-class::after { + content: "class"; +} + +code.doc-symbol-module { + color: var(--doc-symbol-module-fg-color); + background-color: var(--doc-symbol-module-bg-color); +} + +code.doc-symbol-module::after { + content: "mod"; +} + +.doc-signature .autorefs { + color: inherit; + border-bottom: 1px dotted currentcolor; +} diff --git a/assets/external/cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg/26a0.svg b/assets/external/cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg/26a0.svg new file mode 100644 index 0000000..b9ee297 --- /dev/null +++ b/assets/external/cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg/26a0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/external/fonts.googleapis.com/css.49ea35f2.css b/assets/external/fonts.googleapis.com/css.49ea35f2.css new file mode 100644 index 0000000..68986a1 --- /dev/null +++ b/assets/external/fonts.googleapis.com/css.49ea35f2.css @@ -0,0 +1,594 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: italic; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 700; + font-display: fallback; + src: url(../fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 new file mode 100644 index 0000000..d88dd2b Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc-CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 new file mode 100644 index 0000000..0f8ca12 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc0CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 new file mode 100644 index 0000000..317f651 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc1CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 new file mode 100644 index 0000000..0e37f98 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc2CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 new file mode 100644 index 0000000..e0934d9 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc3CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 new file mode 100644 index 0000000..d95067a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc5CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 new file mode 100644 index 0000000..83874b7 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 new file mode 100644 index 0000000..50a2805 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic-CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 new file mode 100644 index 0000000..efbe79a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic0CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 new file mode 100644 index 0000000..ea329ab Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic1CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 new file mode 100644 index 0000000..993b327 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic2CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 new file mode 100644 index 0000000..d3cb894 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic3CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 new file mode 100644 index 0000000..1283c45 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic5CsTKlA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 new file mode 100644 index 0000000..851fedb Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 new file mode 100644 index 0000000..8f20a2c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xEIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 new file mode 100644 index 0000000..bed8708 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 new file mode 100644 index 0000000..e1f558c Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xGIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 new file mode 100644 index 0000000..688c713 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xHIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 new file mode 100644 index 0000000..9dc0be8 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xIIzI.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 new file mode 100644 index 0000000..3e5facb Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xLIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 new file mode 100644 index 0000000..1125cc0 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOkCnqEu92Fr1Mu51xMIzIFKw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 new file mode 100644 index 0000000..a57fbdc Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 new file mode 100644 index 0000000..72226f5 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 new file mode 100644 index 0000000..b61eed3 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 new file mode 100644 index 0000000..a26ba15 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 new file mode 100644 index 0000000..a69131b Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 new file mode 100644 index 0000000..14af54a Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 new file mode 100644 index 0000000..a7026d4 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 new file mode 100644 index 0000000..41637e5 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 new file mode 100644 index 0000000..22f6f53 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 new file mode 100644 index 0000000..19fc4b1 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 new file mode 100644 index 0000000..98f53f7 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 new file mode 100644 index 0000000..660850e Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 new file mode 100644 index 0000000..327eb66 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 new file mode 100644 index 0000000..c175453 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 new file mode 100644 index 0000000..a7f32b6 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 new file mode 100644 index 0000000..2d7b215 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu4mxK.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 new file mode 100644 index 0000000..a4962e9 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 new file mode 100644 index 0000000..e3d708f Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu72xKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 new file mode 100644 index 0000000..20c87e6 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 new file mode 100644 index 0000000..cfd043d Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 new file mode 100644 index 0000000..47ce460 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/roboto/v32/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 new file mode 100644 index 0000000..022274d Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSV0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 new file mode 100644 index 0000000..48edd1b Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSZ0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 new file mode 100644 index 0000000..cb41535 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSd0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 new file mode 100644 index 0000000..1d988a3 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSh0mQ.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 new file mode 100644 index 0000000..11e6a46 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSt0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 new file mode 100644 index 0000000..50fb8e7 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xTDF4xlVMF-BfR8bXMIhJHg45mwgGEFl0_3vrtSM1J-gEPT5Ese6hmHSx0mf0h.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 new file mode 100644 index 0000000..1f1c97f Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtElOUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 new file mode 100644 index 0000000..1623005 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEleUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 new file mode 100644 index 0000000..6f232c3 Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEluUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 new file mode 100644 index 0000000..a3e5aef Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEm-Ul.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 new file mode 100644 index 0000000..f73f27d Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEmOUlYIw.woff2 differ diff --git a/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 new file mode 100644 index 0000000..135d06e Binary files /dev/null and b/assets/external/fonts.gstatic.com/s/robotomono/v23/L0xdDF4xlVMF-BfR8bXMIjhOsXG-q2oeuFoqFrlnAIe2Imhk1T8rbociImtEn-UlYIw.woff2 differ diff --git a/assets/external/unpkg.com/iframe-worker/shim.js b/assets/external/unpkg.com/iframe-worker/shim.js new file mode 100644 index 0000000..5f1e232 --- /dev/null +++ b/assets/external/unpkg.com/iframe-worker/shim.js @@ -0,0 +1 @@ +"use strict";(()=>{function c(s,n){parent.postMessage(s,n||"*")}function d(...s){return s.reduce((n,e)=>n.then(()=>new Promise(r=>{let t=document.createElement("script");t.src=e,t.onload=r,document.body.appendChild(t)})),Promise.resolve())}var o=class extends EventTarget{constructor(e){super();this.url=e;this.m=e=>{e.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:e.data})),this.onmessage&&this.onmessage(e))};this.e=(e,r,t,i,m)=>{if(r===`${this.url}`){let a=new ErrorEvent("error",{message:e,filename:r,lineno:t,colno:i,error:m});this.dispatchEvent(a),this.onerror&&this.onerror(a)}};let r=document.createElement("iframe");r.hidden=!0,document.body.appendChild(this.iframe=r),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + +

Cells distributions

+ + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo_notebooks/cells_distributions.ipynb b/demo_notebooks/cells_distributions.ipynb new file mode 100644 index 0000000..bf5c953 --- /dev/null +++ b/demo_notebooks/cells_distributions.ipynb @@ -0,0 +1,934 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook shows how to load data exported from QuPath, compute metrics and display them, according to the configuration file. This is meant for a single-animal.\n", + "\n", + "There are some conventions that need to be met in the QuPath project so that the measurements are usable with `cuisto`:\n", + "+ Objects' classifications must be derived, eg. be in the form \"something: else\". The primary classification (\"something\") will be refered to \"object_type\" and the secondary classification (\"else\") to \"channel\" in the configuration file.\n", + "+ Only one \"object_type\" can be processed at once, but supports any numbers of channels.\n", + "+ Annotations (brain regions) must have properly formatted measurements. For punctual objects, it would be the count. Run the \"add_regions_count.groovy\" script to add them. The measurements names must be in the form \"something: else name\", for instance, \"something: else Count\". \"name\" is refered to \"base_measurement\" in the configuration file.\n", + "\n", + "You should copy this notebook, the configuration file and the atlas-related configuration files (blacklist and fusion) elsewhere and edit them according to your need.\n", + "\n", + "The data was generated from QuPath with stardist cell detection on toy data." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "import cuisto" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Full path to your configuration file, edited according to your need beforehand\n", + "config_file = \"../../resources/demo_config_cells.toml\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# - Files\n", + "# animal identifier\n", + "animal = \"animalid0\"\n", + "# set the full path to the annotations tsv file from QuPath\n", + "annotations_file = \"../../resources/cells_measurements_annotations.tsv\"\n", + "# set the full path to the detections tsv file from QuPath\n", + "detections_file = \"../../resources/cells_measurements_detections.tsv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# get configuration\n", + "cfg = cuisto.config.Config(config_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImageObject typeNameClassificationParentROICentroid X µmCentroid Y µmCells: marker+ CountCells: marker- CountIDSideParent IDNum DetectionsNum Cells: marker+Num Cells: marker-Area µm^2Perimeter µm
Object ID
4781ed63-0d8e-422e-aead-b685fbe20eb5animalid0_030.ome.tiffAnnotationRootNaNRoot object (Image)Geometry5372.53922.100NaNNaNNaN2441136230531666431.637111.9
aa4b133d-13f9-42d9-8c21-45f143b41a85animalid0_030.ome.tiffAnnotationrootRight: rootRootPolygon7094.94085.7009970.0NaN128441124315882755.918819.5
42c3b914-91c5-4b65-a603-3f9431717d48animalid0_030.ome.tiffAnnotationgreyRight: greyrootGeometry7256.84290.60080.0997.010092498512026268.749600.3
887af3eb-4061-4f8a-aa4c-fe9b81184061animalid0_030.ome.tiffAnnotationCBRight: CBgreyGeometry7778.73679.20165120.08.054255376943579.030600.2
adaabc05-36d1-4aad-91fe-2e904adc574fanimalid0_030.ome.tiffAnnotationCBNRight: CBNCBGeometry6790.53567.9005190.0512.055154864212.37147.4
\n", + "
" + ], + "text/plain": [ + " Image Object type \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 animalid0_030.ome.tiff Annotation \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 animalid0_030.ome.tiff Annotation \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 animalid0_030.ome.tiff Annotation \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 animalid0_030.ome.tiff Annotation \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f animalid0_030.ome.tiff Annotation \n", + "\n", + " Name Classification \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 Root NaN \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 root Right: root \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 grey Right: grey \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 CB Right: CB \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f CBN Right: CBN \n", + "\n", + " Parent ROI \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 Root object (Image) Geometry \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 Root Polygon \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 root Geometry \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 grey Geometry \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f CB Geometry \n", + "\n", + " Centroid X µm Centroid Y µm \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 5372.5 3922.1 \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 7094.9 4085.7 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 7256.8 4290.6 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 7778.7 3679.2 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 6790.5 3567.9 \n", + "\n", + " Cells: marker+ Count \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 0 \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 0 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 0 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 0 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 0 \n", + "\n", + " Cells: marker- Count ID Side \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 0 NaN NaN \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 0 997 0.0 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 0 8 0.0 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 16 512 0.0 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 0 519 0.0 \n", + "\n", + " Parent ID Num Detections \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 NaN 2441 \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 NaN 1284 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 997.0 1009 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 8.0 542 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 512.0 55 \n", + "\n", + " Num Cells: marker+ Num Cells: marker- \\\n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 136 2305 \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 41 1243 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 24 985 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 5 537 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 1 54 \n", + "\n", + " Area µm^2 Perimeter µm \n", + "Object ID \n", + "4781ed63-0d8e-422e-aead-b685fbe20eb5 31666431.6 37111.9 \n", + "aa4b133d-13f9-42d9-8c21-45f143b41a85 15882755.9 18819.5 \n", + "42c3b914-91c5-4b65-a603-3f9431717d48 12026268.7 49600.3 \n", + "887af3eb-4061-4f8a-aa4c-fe9b81184061 6943579.0 30600.2 \n", + "adaabc05-36d1-4aad-91fe-2e904adc574f 864212.3 7147.4 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImageObject typeNameClassificationParentROIAtlas_XAtlas_YAtlas_Z
Object ID
5ff386a8-5abd-46d1-8e0d-f5c5365457c1animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11523.04272.44276.7
9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11520.24278.44418.6
481a519b-8b40-4450-9ec6-725181807d72animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11506.04317.24356.3
fd28e09c-2c64-4750-b026-cd99e3526a57animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11528.44257.44336.4
3d9ce034-f2ed-4c73-99be-f782363cf323animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11548.74203.34294.3
\n", + "
" + ], + "text/plain": [ + " Image Object type \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection \n", + "481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection \n", + "\n", + " Name Classification Parent ROI \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 NaN Cells: marker- VeCB Polygon \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 NaN Cells: marker- VeCB Polygon \n", + "481a519b-8b40-4450-9ec6-725181807d72 NaN Cells: marker- VeCB Polygon \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 NaN Cells: marker- VeCB Polygon \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 NaN Cells: marker- VeCB Polygon \n", + "\n", + " Atlas_X Atlas_Y Atlas_Z \n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 11523.0 4272.4 4276.7 \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 11520.2 4278.4 4418.6 \n", + "481a519b-8b40-4450-9ec6-725181807d72 11506.0 4317.2 4356.3 \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 11528.4 4257.4 4336.4 \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 11548.7 4203.3 4294.3 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# read data\n", + "df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\n", + "df_detections = pd.read_csv(detections_file, index_col=\"Object ID\", sep=\"\\t\")\n", + "\n", + "# remove annotations that are not brain regions\n", + "df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\n", + "df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n", + "\n", + "# convert atlas coordinates from mm to microns\n", + "df_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[\n", + " [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]\n", + "].multiply(1000)\n", + "\n", + "# have a look\n", + "display(df_annotations.head())\n", + "display(df_detections.head())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NamehemisphereArea µm^2Area mm^2countdensity µm^-2density mm^-2coverage indexrelative countrelative densitychannelanimal
0ACVIILeft8307.10.00830710.00012120.3789530.000120.0021320.205275Positiveanimalid0
0ACVIILeft8307.10.00830710.00012120.3789530.000120.0001890.020671Negativeanimalid0
1ACVIIRight7061.40.00706100.00.00.00.00.0Positiveanimalid0
1ACVIIRight7061.40.00706110.000142141.6149770.0001420.0001440.021646Negativeanimalid0
2ACVIIboth15368.50.01536910.00006565.0681590.0000650.0013620.153797Positiveanimalid0
\n", + "
" + ], + "text/plain": [ + " Name hemisphere Area µm^2 Area mm^2 count density µm^-2 density mm^-2 \\\n", + "0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 \n", + "0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 \n", + "1 ACVII Right 7061.4 0.007061 0 0.0 0.0 \n", + "1 ACVII Right 7061.4 0.007061 1 0.000142 141.614977 \n", + "2 ACVII both 15368.5 0.015369 1 0.000065 65.068159 \n", + "\n", + " coverage index relative count relative density channel animal \n", + "0 0.00012 0.002132 0.205275 Positive animalid0 \n", + "0 0.00012 0.000189 0.020671 Negative animalid0 \n", + "1 0.0 0.0 0.0 Positive animalid0 \n", + "1 0.000142 0.000144 0.021646 Negative animalid0 \n", + "2 0.000065 0.001362 0.153797 Positive animalid0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImageObject typeNameClassificationParentROIAtlas_XAtlas_YAtlas_ZhemispherechannelAtlas_APAtlas_DVAtlas_MLanimal
Object ID
5ff386a8-5abd-46d1-8e0d-f5c5365457c1animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11.52304.27244.2767RightNegative-6.4337163.098278-1.4233animalid0
9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11.52024.27844.4186RightNegative-6.4314493.104147-1.2814animalid0
481a519b-8b40-4450-9ec6-725181807d72animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11.50604.31724.3563RightNegative-6.4206853.141780-1.3437animalid0
fd28e09c-2c64-4750-b026-cd99e3526a57animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11.52844.25744.3364RightNegative-6.4377883.083737-1.3636animalid0
3d9ce034-f2ed-4c73-99be-f782363cf323animalid0_030.ome.tiffDetectionNaNCells: marker-VeCBPolygon11.54874.20334.2943RightNegative-6.4532963.031224-1.4057animalid0
\n", + "
" + ], + "text/plain": [ + " Image Object type \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection \n", + "481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection \n", + "\n", + " Name Classification Parent ROI \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 NaN Cells: marker- VeCB Polygon \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 NaN Cells: marker- VeCB Polygon \n", + "481a519b-8b40-4450-9ec6-725181807d72 NaN Cells: marker- VeCB Polygon \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 NaN Cells: marker- VeCB Polygon \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 NaN Cells: marker- VeCB Polygon \n", + "\n", + " Atlas_X Atlas_Y Atlas_Z hemisphere \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 11.5230 4.2724 4.2767 Right \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 11.5202 4.2784 4.4186 Right \n", + "481a519b-8b40-4450-9ec6-725181807d72 11.5060 4.3172 4.3563 Right \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 11.5284 4.2574 4.3364 Right \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 11.5487 4.2033 4.2943 Right \n", + "\n", + " channel Atlas_AP Atlas_DV Atlas_ML \\\n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 Negative -6.433716 3.098278 -1.4233 \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 Negative -6.431449 3.104147 -1.2814 \n", + "481a519b-8b40-4450-9ec6-725181807d72 Negative -6.420685 3.141780 -1.3437 \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 Negative -6.437788 3.083737 -1.3636 \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 Negative -6.453296 3.031224 -1.4057 \n", + "\n", + " animal \n", + "Object ID \n", + "5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0 \n", + "9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0 \n", + "481a519b-8b40-4450-9ec6-725181807d72 animalid0 \n", + "fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0 \n", + "3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# get distributions per regions, spatial distributions and coordinates\n", + "df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n", + " animal, df_annotations, df_detections, cfg, compute_distributions=True\n", + ")\n", + "\n", + "# have a look\n", + "display(df_regions.head())\n", + "display(df_coordinates.head())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot distributions per regions\n", + "figs_regions = cuisto.display.plot_regions(df_regions, cfg)\n", + "# specify which regions to plot\n", + "# figs_regions = cuisto.display.plot_regions(df_regions, cfg, names_list=[\"GRN\", \"IRN\", \"MDRNv\"])\n", + "\n", + "# save as svg\n", + "# figs_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_count.svg\")\n", + "# figs_regions[1].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_density.svg\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABDYAAAINCAYAAADFvv8YAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAD5ZElEQVR4nOzdeXwUhfk/8M/svbkDuSAEEm5QLlERrOIRC/W2aqmiKP2q1YooyM+WHipqRa0iX89YW6q2WPm2XlQUlSgqihcUQbmPEI6c5D72nPn9sdnJTM7dZHdndvfzfr3y6mR3dvaBxiF58hyCJEkSiIiIiIiIiIiikEHrAIiIiIiIiIiI+oqJDSIiIiIiIiKKWkxsEBEREREREVHUYmKDiIiIiIiIiKIWExtEREREREREFLWY2CAiIiIiIiKiqMXEBhERERERERFFLSY2iIiIiIiIiChqmbQOINJEUcTx48eRnJwMQRC0DoeISEWSJDQ2NmLw4MEwGGI798z7MRHpFe/FRET6EOj9OO4SG8ePH0deXp7WYRAR9ejIkSMYMmSI1mGEFe/HRKR3vBcTEelDb/fjuEtsJCcnA/D9xaSkpGgcDVFwmrxu7Gypx/iEVCQZzVqHQ2HQ0NCAvLw8+V4Vy3g/Jgoc7/+RxXsxUXTgvTH2BXo/jrvEhr/ELiUlhTdvijoGrxuJJhEpCSm8ece4eCgH5v2YKHC8/2uD92IifeO9MX70dj+O7aZBIiIiIiIiIoppTGwQERERERERUdRiYoOIiIiIiIiIolbczdgIhCRJ8Hg88Hq9WodCcchoNMJkMsVFXy8REREREVF/MbHRgcvlQllZGVpaWrQOheJYQkICBg0aBIvFonUoREREREREusbEhoIoijh06BCMRiMGDx4Mi8XC35pTREmSBJfLhaqqKhw6dAijRo2CwcCOMSIiIiIiou4wsaHgcrkgiiLy8vKQkJCgdTgUp+x2O8xmMw4fPgyXywWbzaZ1SERERERERLrFXwV3gb8hJ63xa5CIiIiIiCgw/OmJiIiIiIiIiKIWExsUMfn5+Vi5cqXWYRAREREREVEMYWIjRtx4440QBAGPPPKI6vG33nor4gNQX3rpJaSlpXV6/JtvvsEtt9wS0ViIiIiIiIgotjGxEUNsNhseffRR1NbWah1KlzIzMzmUlYiIiIiIiEKKiY0YUlhYiJycHCxfvrzbczZt2oSzzjoLdrsdeXl5WLhwIZqbm+Xny8rKcNFFF8Fut6OgoACvvvpqpxaSFStWYMKECUhMTEReXh5+9atfoampCQCwceNGzJ8/H/X19RAEAYIg4P777wegbkW59tprMWfOHFVsbrcbGRkZeOWVVwD41u8uX74cBQUFsNvtmDRpEv7973+H4G+KiIiIiIiIYgUTGzHEaDTi4YcfxtNPP42jR492ev7AgQOYPXs2rrzySmzfvh1r1qzBpk2bsGDBAvmcefPm4fjx49i4cSNef/11/PnPf0ZlZaXqOgaDAU899RR++OEHvPzyy/joo49wzz33AABmzJiBlStXIiUlBWVlZSgrK8OSJUs6xTJ37lz85z//kRMiAPD++++jpaUFV1xxBQBg+fLleOWVV1BUVIQffvgBixYtwnXXXYdPPvkkJH9fREREREREFP1MWgcQDXZf9D9wV9VE/H3NmQMwdt1fg3rNFVdcgcmTJ+O+++7DX/+qfu3y5csxd+5c3HXXXQCAUaNG4amnnsLMmTPx/PPPo6SkBBs2bMA333yDU089FQDwl7/8BaNGjVJdx/96wFeF8dBDD+HWW2/Fc889B4vFgtTUVAiCgJycnG7jnDVrFhITE/Hmm2/i+uuvBwC8+uqruPTSS5GcnAyn04mHH34YGzZswPTp0wEAw4cPx6ZNm/DCCy9g5syZQf29EBERERERUWxiYiMA7qoauMurtA4jYI8++ijOO++8TpUS3333HbZv347Vq1fLj0mSBFEUcejQIezduxcmkwmnnHKK/PzIkSORnp6uus6GDRuwfPly7N69Gw0NDfB4PHA4HGhpaQl4hobJZMLPfvYzrF69Gtdffz2am5vx9ttv47XXXgMA7N+/Hy0tLbjgggtUr3O5XJgyZUpQfx9EREREREQUu5jYCIA5c0BUve/ZZ5+NWbNmYenSpbjxxhvlx5uamvDLX/4SCxcu7PSaoUOHYu/evb1eu6SkBBdffDFuu+02/PGPf8SAAQOwadMm/M///A9cLldQw0Hnzp2LmTNnorKyEh9++CHsdjtmz54txwoA69atQ25urup1Vqs14PeINt6WVnhrGyAm2rQOhYiIiIiIKCowsRGAYNtB9OCRRx7B5MmTMWbMGPmxU045BTt37sTIkSO7fM2YMWPg8Xjw3//+F1OnTgXgq5xQblnZsmULRFHEE088AYPBN6Ll//7v/1TXsVgs8Hq9vcY4Y8YM5OXlYc2aNXjvvfdw9dVXw2w2AwDGjx8Pq9WK0tLSuGo7cR0pg+h0wdNk1joUIiIiIiKiqMDERoyaMGEC5s6di6eeekp+7Ne//jXOOOMMLFiwADfddBMSExOxc+dOfPjhh3jmmWcwduxYFBYW4pZbbsHzzz8Ps9mMu+++G3a7HYIgAPC1prjdbjz99NO45JJL8Pnnn6OoqEj13vn5+WhqakJxcTEmTZqEhISEbis5rr32WhQVFWHv3r34+OOP5ceTk5OxZMkSLFq0CKIo4kc/+hHq6+vx+eefIyUlBTfccEMY/ta0JYkiRKcLAHz/y9wGERERERFRr7gVJYY98MADEEVR/nzixIn45JNPsHfvXpx11lmYMmUK7r33XgwePFg+55VXXkF2djbOPvtsXHHFFbj55puRnJwMm83XGjFp0iSsWLECjz76KE4++WSsXr2603rZGTNm4NZbb8WcOXOQmZmJxx57rNsY586di507dyI3Nxdnnnmm6rkHH3wQf/jDH7B8+XKMGzcOs2fPxrp161BQUBCKvx7dkTye9mNJgqT4/46IiIiIiIi6JkiSJGkdRCQ1NDQgNTUV9fX1SElJUT3ncDhw6NAhFBQUyD/Ix7ujR48iLy8PGzZswPnnn691ODHN29wCx4FSAIBTElEueDF89CjV12KT140dLXWYkJCGJCNLOmJRT/eoWBNPf1ai/uL9P7Li6f4UT39Wij28N8a+QO9RbEUhlY8++ghNTU2YMGECysrKcM899yA/Px9nn3221qHFPMntUX8ewJwSIiIiIiKieMfEBqm43W789re/xcGDB5GcnIwZM2Zg9erV8lBPCh8mNoiIiIiIiILHxAapzJo1C7NmzdI6jLjUMbEBJjaIiIiIiIh6xeGhRDohedwdPufwUCIiIiIiot4wsUGkE5KLrShERERERETBYmKDSCeU614BsBWFiIiIiIgoAExsEOmAJEldDA8VEWfbmImIiIiIiILGxAaRHni9nZMYkgRPXYM28RAREREREUUJJjaIdEDsuBGljaeqJsKREBERERFpT5IkNHz2DVr3lWgdCkUBJjaoRxs3boQgCKirq+vxvPz8fKxcuTIiMcUiZRuKIAjysbvyhBbhEBERERFpqvatD7F/7iLs/sl8fk9MvWJiI0bceOONEAQBgiDAYrFg5MiReOCBB+DpOJAySDNmzEBZWRlSU1MBAC+99BLS0tI6nffNN9/glltu6dd7xTNlYsNgt8nHblZsEBEREVEcqi/+HAAgudxo2blP42hI70xaB0ChM3v2bPztb3+D0+nEu+++i9tvvx1msxlLly7t8zUtFgtycnJ6PS8zM7PP70GA5HbLx4YEG9DcDADwVFZrFRIRERERkWZadu6Xj8XGZg0joWjAio0YYrVakZOTg2HDhuG2225DYWEh1q5di9raWsybNw/p6elISEjAT37yE+zb1571PHz4MC655BKkp6cjMTERJ510Et59910A6laUjRs3Yv78+aivr5erQ+6//34A6laUa6+9FnPmzFHF5na7kZGRgVdeeQUAIIoili9fjoKCAtjtdkyaNAn//ve/w/+XpFPKVa+GBLt8zIoNIiIiIoo3YqsDzoNH5M+9TGxQL1ixEcPsdjtOnDiBG2+8Efv27cPatWuRkpKCX//617jwwguxc+dOmM1m3H777XC5XPj000+RmJiInTt3IikpqdP1ZsyYgZUrV+Lee+/Fnj17AKDL8+bOnYurr74aTU1N8vPvv/8+WlpacMUVVwAAli9fjn/84x8oKirCqFGj8Omnn+K6665DZmYmZs6cGca/FX1StaIoExvsJyQiIiKiONO65yAgivLn3sYmDaOhaMDERgAu2r0RVW5HxN8302zDurHnBP06SZJQXFyM999/Hz/5yU/w1ltv4fPPP8eMGTMAAKtXr0ZeXh7eeustXH311SgtLcWVV16JCRMmAACGDx/e5XUtFgtSU1MhCEKP7SmzZs1CYmIi3nzzTVx//fUAgFdffRWXXnopkpOT4XQ68fDDD2PDhg2YPn26/J6bNm3CCy+8ENeJDUEQIJhNEAy+Yip3FRMbRERERBRfWhVtKADgbWrRKBKKFkxsBKDK7UC5BomNYL3zzjtISkqC2+2GKIq49tpr8dOf/hTvvPMOpk2bJp83cOBAjBkzBrt27QIALFy4ELfddhs++OADFBYW4sorr8TEiRP7HIfJZMLPfvYzrF69Gtdffz2am5vx9ttv47XXXgMA7N+/Hy0tLbjgggtUr3O5XJgyZUqf3zeayYkNk8mX3DD5/tN0V9VC8nohGI1ahkdEREREFDEdh4V6G1ixQT1jYiMAmWZb7yfp4H3PPfdcPP/8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a7Dps8+waNm9AHxtKMokiJ8pJQnpl5wPU2qy/Jh/xgbAzShEREREFP3c5VXw1vp+4edvQwHUFRtiU0vE46LooemMjTlz5qCqqgr33nsvysvLMXnyZKxfv14eKFpaWgqDonohLy8P77//PhYtWoSJEyciNzcXd955J379619r9UfQJUmSUFxcjPfffx933HEH9u3bh7Vr1+Lzzz/HjBkzAACrV69GXl4e3nrrLVx99dUoLS3FlVdeiQkTJgAAhg/vur3BYrEgNTUVgiD02AIya9YsJCYm4s0338T1118PAHj11Vdx6aWXIjk5GU6nEw8//DA2bNggV+gMHz4cmzZtwgsvvICZM2cCAEaMGIGMjIyg/vxutxtFRUUYMWIEAGDBggV44IEHgrqGUmlpKRITE3HxxRcjOTkZw4YNw5QpU7o8d8CAATAajUhOTlb9/Sxfvhxz586VKztGjRqFJ+5dhsKrrsDK392H5Iz0gOORhilbUVixQURERETRTTU4dJwisZHC4aEUGM2Hhy5YsAALFizo8rmNGzd2emz69On48ssvwxxVdHrnnXeQlJQEt9sNURRx7bXX4v7770dxcTFMJhOmTZsmnztw4ECMGTMGu3btAgAsXLgQt912Gz744AMUFhbiyiuvxMSJE/sci8lkws9+9jOsXr0a119/PZqbm/H222/jtddeAwDs378fLS0tuOCCC1Svc7lcqqSBslUpUAkJCXJSA/DNZqmsrOzjnwS44IILMGzYMAwfPhyzZ8/G7NmzccUVVyAhIaH3F7f57rvvsH37dqxevVp+TPKKEEURh8uOYfLkkwIPKCkBxoHp8J6oZcUGEREREUW9FsXgUPtJo+RjY6Ji3StnbFAPNE9sUOice+65eP7552GxWDB48OCgtqHcdNNNmDVrFtatW4cPPvgAy5cvxxNPPNGv7SFz587FzJkzUVlZiQ8//BB2ux2zZ88GALlFZd26dcjNzVW9rr8DrZQbSgDf/ApJkvp8veTkZGzduhUbN27EBx98gHvvvRf3338/vvnmG6SlpQV0jaamJvzyl7/EwoULAQCuskp46hsBAMMnnNx5cGgvzAW58J6ohbvyBLzNLaqbPhERERFRNOmuYkMwm2Cw2yC2OpjYoB5pOmODQisxMREjR47E0KFDVUmNcePGwePx4KuvvpIfO3HiBPbs2YPx48fLj+Xl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HopD5eXl4amnnoKvry+kUim6du2K06dPO3pYxIk5+7lJbZmZmZg2bRqio6MhlUoRExODRYsWQafTOXpoN8UVj5V30jHPmY9dFNhwYgMHDkR+fr7N1zPPPIPo6Gj07t3b0cNrlr/++guTJk3C1KlTcf78eRw5cgT/+c9/HD2sm/LOO+/Y/E1efPFFRw/pps2bNw8hISGOHsZNGzJkCP744w+kpKTgr7/+QlpaGh577DFHD4s4od9//x1z587FokWLkJiYiO7du2PEiBEoLCx09NAc4uDBg5gxYwaOHz+OPXv2QK/X4/7774dSqXT00NqEU6dO4dtvv0W3bt0cPRSHKisrw6BBgyAUCrFjxw5cvnwZn376Kby9vR09NOLEnP3cpLYrV67AZDLh22+/RVJSEj7//HOsWLECr7/+uqOH1myueqy8U455Tn/sYonL0Ol0rL+/P/vOO+84eijNotfr2dDQUPaHH35w9FBuWWRkJPv55587ehgtYvv27WzHjh3ZpKQkFgB79uxZRw/plm3evJllGIbV6XSOHgpxMn379mVnzJjB/Ww0GtmQkBB2yZIlDhxV21FYWMgCYA8ePOjooThcVVUVGxsby+7Zs4e999572dmzZzt6SA4zf/589q677nL0MIgLccVzE3s++ugjNjo62tHDaLY75Vjpisc8Vzh2UcaGC9myZQtKSkowdepURw+lWRITE5GXlwcej4cePXogODgYDzzwAC5duuTood2UDz74AL6+vujRowc+/vhjGAwGRw+p2W7cuIFnn30Wq1evhkwmc/RwWkRpaSnWrFmDgQMHQigUOno4xInodDqcOXMGw4cP527j8XgYPnw4jh075sCRtR0VFRUAAB8fHwePxPFmzJiB0aNH2/y/3Km2bNmC3r17Y/z48QgICECPHj3w/fffO3pYxEm54rlJfSoqKpxuPr2TjpWueMxzhWMXBTZcyI8//ogRI0YgLCzM0UNplvT0dADA22+/jYULF2Lr1q3w9vbG4MGDUVpa6uDRNc+sWbOwbt067N+/H88//zwWL16MefPmOXpYzcKyLJ5++mlMnz7d6ZY02TN//nzI5XL4+voiOzsbmzdvdvSQiJMpLi6G0WhEYGCgze2BgYEoKChw0KjaDpPJhJdeegmDBg1Cly5dHD0ch1q3bh0SExOxZMkSRw+lTUhPT8fy5csRGxuL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lpYCAN58801cvnwZO3bsQHJyMpYvXw4/Pz8AwMmTJwEA//zzD/Lz820ODHv37kVKSgr27NmDrVu3QqlUYsSIEfD29sapU6ewfv16/PPPP5g5c2aDY962bRsefvhhjBo1CmfPnsXevXvRt29f7n69Xo93330X58+fx6ZNm5CZmdns1ME//vgDb7/9NhYvXozTp08jODgY33zzjc02VVVVmDJlCv79918cP34csbGxGDVqVIMTmT0///wzBAIBTp48iS+++AKfffYZfvjhB+7+p59+GqdPn8aWLVtw7NgxsCyLUaNGcR8CZsyYAa1Wi0OHDuHixYv48MMP7UZ/Bw4ciKVLl8LDwwP5+fnIz8/HK6+8Umc7k8mEsWPHorS0FAcPHsSePXuQnp6OCRMm2GyXlpaGTZs2YevWrdi6dSsOHjyIDz74oN7XeeHCBVRUVKB379517vv8888xaNAgnD17FqNHj8akSZMwefJkPPXUU0hMTERMTAwmT55sc3BTqVT48ssvsW7dOuzcuRMHDhzAww8/jO3bt2P79u1YvXo1vv322zonGX379sXhw4frHSchjjZ06FB0796dmz+b+p5MTU3FX3/9hQ0bNuDcuXPIz8/Hk08+if/+979ITk7GgQMH8Mgjj3Dvoy+++AKffvopPvnkE1y4cAEjRozAQw89ZHOSaM3DwwNjxozB2rVrbW5fs2YNxo0bB5lMBr1ejxEjRsDd3R2HDx/GkSNH4ObmhpEjR9pkkezfvx9paWnYv38/fv75Z6xatYoL5GzYsAFhYWF45513uLmqmkqlwocffogffvgBSUlJCAgIoLmY5mJCWtR///tf7oIdAPz000+YOnVqne2WLFmCX375BStWrEBSUhLmzJmDp556CgcPHgRgDvI+8sgjePDBB3Hu3Dk888wzeO211xrc98aNGzF79my8/PLLuHTpEp5//nlMnToV+/fvb9Zr4PF4+PLLL5GUlISff/4Z+/btw7x58wA0PAfNnDkTx44dw7p163DhwgWMHz8eI0eOtDku0DxM87DLYIlTmzJlCsvn81m5XM6KxWIWAMvj8dg///yTZVmWVSgUrFAoZNesWcM9RqfTsSEhIexHH33EsizLPvjgg+zUqVPtPn9GRgYLgD179myd/QYGBrJarZa77bvvvmO9vb1ZhULB3bZt2zaWx+OxBQUF9b6GAQMG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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot 1D distributions\n", + "fig_distrib = cuisto.display.plot_1D_distributions(\n", + " dfs_distributions, cfg, df_coordinates=df_coordinates\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If there were several `animal` in the measurement file, it would be displayed as mean +/- sem instead." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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iy++yNdff82WLVs4d86yzNkff/xBxYoVMR0+lBKPIZJu3bx5k7Zt27JmzRoAPv30U7766itcXFzsHJmIiNiFARsue2abakSedWohtzFvb2/u3r2Lt7d3mloCzZYuXLjAnTt3MJvN7N27lxs3bnDnzh0OHDhAWFjYI68pV64c77//PkWKFOH06dM8//zzAHTs2JGpU6cCYDo8HVALuUhCXL58mfr163P48GEMBgPjx4/nww8/tHdYcp9ayEUkNVlbyHf9imfmjLapMzgU74rv631MJJnUQm5jffr0YdCgQdy5c4d///2Xxo0b2zukVOfv74+/vz8AZcqUSdS1JpOJV155xfr6o48+su4rERdJmB07dvD6669z9uxZ/Pz8mD17Ni+99JK9wxIREbuz5XJlaiIXsQVN6mZj/fv3t3YHffXVV+0cTdpiMpkoV64cR48eBWDGjBlUqVLFzlGJpB0xMTF06dKFKlWqcPbsWQoUKMCmTZuUjIuIiIg4KCXkNpYhQwbmzJkDQFhY2DMxuZutLFmyhP379wMwffp03nzzTTtHJJJ2nDt3jrJlyzJu3DgAateuzcaNG8mfP7+dIxMREYehdchFHI4S8hRQtWpV6/4vv/xix0jSjqCgIAYNGgRAnTp1aN9eS5yJJITZbGb27NlUrFiRgwcP4uzszOzZs/nvv//w8/Ozd3giIuJQjDbeRCS59JOUAnx8fMiUKRMAEyZMsHM0js9kMtGyZUsOHDiAp6cnI0eOtHdIImlCVFQU7dq144033uDmzZsUKVKE/fv38/rrr9s7NBERcURqIRdxOErIU0j9+vUBOHr0KO+8846do3FsEyZM4L///gNg/vz5VKxY0c4RiTi+8PBwWrduzaxZswB455132LRpE0WLFrVzZCIi4rhsmYwrIRexBSXkKWTWrFlkzGhZVmLatGn07dvXzhE5pqioKPr06QNAp06dqFu3rp0jEnF8//77LyVLlmTJkiW4ubnxzz//MGXKFLJnz27v0EREREQkEZSQpxA3NzeuXbtGtmzZABg9erSdI3JMH330EeHh4QCMGjXKztGIOLbIyEgGDRrEK6+8wqlTp8icOTPLli17JpdXFBGRpDDYeBOR5FJCnoIyZ85snfE4MjKS7du32zkix/Lff/8xZcoUADp37kyWLFnsG5CIAwsJCaFJkyYMHToUgGbNmhEQ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uXTpEvXq1bNbDCIiIiKSPighF0mkDBky0LVrV0aNGkVISAjffPMNrVu35u2336Z8+fKcPHmSFStW4O3tDVhawT/77DNKly5NjRo1cHJyYvbs2da6Ro8ezcSJE/Hz86N58+aPvW/GjBlZsWIFt2/fplKlSrz66qvUrVuXMWPGPDHeWrVq8ffff7N48WLKli1LnTp1rLO758iRg2nTpvH3339TvHhxvvnmm3hd6bNmzcqff/7Jv//+S6lSpZg1axZffPFFnHNef/11Bg0aRL9+/ahQoQLnzp2jc+fOcc757bffuHPnDuXLl+ftt9+2LhWXGKVKlaJ8+fLMmTMnUdfZ0qxZs2jQoAF58+a1WwwiIiIikj4YzP8/OFRExIH9888/9O3bl4MHD2I0pu5nipGRkRQqVIiZM2fGmchPRERERCQpNKmbiKQpr7zyCidOnODSpUv4+/un6r3Pnz/PgAEDlIyLiIiIiE2ohVxERERERETEDjSGXERERERERMQOlJCLiIiIiIiI2IESchERERERERE7UEIuIiIiIiIiYgdKyEVERERERETsQAm5iIiIiIiIiB0oIRcRERERERGxAyXkIiIiIiIiInaghFxERERERETEDv4HQbyujdWqsBYAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot heatmap (all types of cells pooled)\n", + "fig_heatmap = cuisto.display.plot_2D_distributions(df_coordinates, cfg)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hq", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/demo_notebooks/density_map.html b/demo_notebooks/density_map.html new file mode 100644 index 0000000..173a9c9 --- /dev/null +++ b/demo_notebooks/density_map.html @@ -0,0 +1,2471 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Density map - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + +

Density map

+ + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo_notebooks/density_map.ipynb b/demo_notebooks/density_map.ipynb new file mode 100644 index 0000000..2e2a947 --- /dev/null +++ b/demo_notebooks/density_map.ipynb @@ -0,0 +1,523 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Draw 2D heatmaps as density isolines.\n", + "\n", + "This notebook does not actually use `histoquant` and relies only on [brainglobe-heatmap](https://brainglobe.info/documentation/brainglobe-heatmap/index.html) to extract brain structures outlines.\n", + "\n", + "Only the detections measurements with atlas coordinates exported from QuPath are used.\n", + "\n", + "You need to select the range of data to be used, the regions outlines will be extracted at the centroid of that range. Therefore, a range that is too large will be misleading and irrelevant." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import brainglobe_heatmap as bgh\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# path to the exported measurements from QuPath\n", + "filename = \"../../resources/cells_measurements_detections.tsv\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Settings" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# atlas to use\n", + "atlas_name = \"allen_mouse_10um\"\n", + "# brain regions whose outlines will be plotted\n", + "regions = [\"root\", \"CB\", \"MY\", \"GRN\", \"IRN\"]\n", + "# range to include, in Allen coordinates, in microns\n", + "ap_lims = [9800, 10000] # lims : [0, 13200] for coronal\n", + "ml_lims = [5600, 5800] # lims : [0, 11400] for sagittal\n", + "dv_lims = [3900, 4100] # lims : [0, 8000] for top\n", + "# number of isolines\n", + "nlevels = 5\n", + "# color mapping between classification and matplotlib color\n", + "palette = {\"Cells: marker-\": \"#d8782f\", \"Cells: marker+\": \"#8ccb73\"}" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImageObject IDObject typeNameClassificationParentROIAtlas_XAtlas_YAtlas_Z
0animalid0_030.ome.tiff5ff386a8-5abd-46d1-8e0d-f5c5365457c1DetectionNaNCells: marker-VeCBPolygon11.52304.27244.2767
1animalid0_030.ome.tiff9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0DetectionNaNCells: marker-VeCBPolygon11.52024.27844.4186
2animalid0_030.ome.tiff481a519b-8b40-4450-9ec6-725181807d72DetectionNaNCells: marker-VeCBPolygon11.50604.31724.3563
3animalid0_030.ome.tifffd28e09c-2c64-4750-b026-cd99e3526a57DetectionNaNCells: marker-VeCBPolygon11.52844.25744.3364
4animalid0_030.ome.tiff3d9ce034-f2ed-4c73-99be-f782363cf323DetectionNaNCells: marker-VeCBPolygon11.54874.20334.2943
\n", + "
" + ], + "text/plain": [ + "\n", + " Image Object ID Object type \\\n", + "\u001b[1;36m0\u001b[0m animalid0_030.ome.tiff \u001b[93m5ff386a8-5abd-46d1-8e0d-f5c5365457c1\u001b[0m Detection \n", + "\u001b[1;36m1\u001b[0m animalid0_030.ome.tiff \u001b[93m9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0\u001b[0m Detection \n", + "\u001b[1;36m2\u001b[0m animalid0_030.ome.tiff \u001b[93m481a519b-8b40-4450-9ec6-725181807d72\u001b[0m Detection \n", + "\u001b[1;36m3\u001b[0m animalid0_030.ome.tiff \u001b[93mfd28e09c-2c64-4750-b026-cd99e3526a57\u001b[0m Detection \n", + "\u001b[1;36m4\u001b[0m animalid0_030.ome.tiff \u001b[93m3d9ce034-f2ed-4c73-99be-f782363cf323\u001b[0m Detection \n", + "\n", + " Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z \n", + "\u001b[1;36m0\u001b[0m NaN Cells: marker- VeCB Polygon \u001b[1;36m11.5230\u001b[0m \u001b[1;36m4.2724\u001b[0m \u001b[1;36m4.2767\u001b[0m \n", + "\u001b[1;36m1\u001b[0m NaN Cells: marker- VeCB Polygon \u001b[1;36m11.5202\u001b[0m \u001b[1;36m4.2784\u001b[0m \u001b[1;36m4.4186\u001b[0m \n", + "\u001b[1;36m2\u001b[0m NaN Cells: marker- VeCB Polygon \u001b[1;36m11.5060\u001b[0m \u001b[1;36m4.3172\u001b[0m \u001b[1;36m4.3563\u001b[0m \n", + "\u001b[1;36m3\u001b[0m NaN Cells: marker- VeCB Polygon \u001b[1;36m11.5284\u001b[0m \u001b[1;36m4.2574\u001b[0m \u001b[1;36m4.3364\u001b[0m \n", + "\u001b[1;36m4\u001b[0m NaN Cells: marker- VeCB Polygon \u001b[1;36m11.5487\u001b[0m \u001b[1;36m4.2033\u001b[0m \u001b[1;36m4.2943\u001b[0m " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df = pd.read_csv(filename, sep=\"\\t\")\n", + "display(df.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we can filter out classifications we don't wan't to display." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# select objects\n", + "# df = df[df[\"Classification\"] == \"example: classification\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# get outline coordinates in coronal (=frontal) orientation\n", + "coords_coronal = bgh.get_structures_slice_coords(\n", + " regions,\n", + " orientation=\"frontal\",\n", + " atlas_name=atlas_name,\n", + " position=(np.mean(ap_lims), 0, 0),\n", + ")\n", + "# get outline coordinates in sagittal orientation\n", + "coords_sagittal = bgh.get_structures_slice_coords(\n", + " regions,\n", + " orientation=\"sagittal\",\n", + " atlas_name=atlas_name,\n", + " position=(0, 0, np.mean(ml_lims)),\n", + ")\n", + "# get outline coordinates in top (=horizontal) orientation\n", + "coords_top = bgh.get_structures_slice_coords(\n", + " regions,\n", + " orientation=\"horizontal\",\n", + " atlas_name=atlas_name,\n", + " position=(0, np.mean(dv_lims), 0),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;35mText\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2\u001b[0m, \u001b[1;36m7.9\u001b[0m, \u001b[32m'1 mm'\u001b[0m\u001b[1m)\u001b[0m"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "\u001b[1m<\u001b[0m\u001b[1;95mFigure\u001b[0m\u001b[39m size 64\u001b[0m\u001b[1;36m0x480\u001b[0m\u001b[39m with \u001b[0m\u001b[1;36m1\u001b[0m\u001b[39m Axes\u001b[0m\u001b[1m>\u001b[0m"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# Coronal projection\n",
+    "# select objects within the rostro-caudal range\n",
+    "df_coronal = df[\n",
+    "    (df[\"Atlas_X\"] >= ap_lims[0] / 1000) & (df[\"Atlas_X\"] <= ap_lims[1] / 1000)\n",
+    "]\n",
+    "\n",
+    "plt.figure()\n",
+    "\n",
+    "for struct_name, contours in coords_coronal.items():\n",
+    "    for cont in contours:\n",
+    "        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n",
+    "\n",
+    "# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\n",
+    "ax = sns.kdeplot(\n",
+    "    df_coronal,\n",
+    "    x=\"Atlas_Z\",\n",
+    "    y=\"Atlas_Y\",\n",
+    "    hue=\"Classification\",\n",
+    "    levels=nlevels,\n",
+    "    common_norm=False,\n",
+    "    palette=palette,\n",
+    ")\n",
+    "ax.invert_yaxis()\n",
+    "sns.despine(left=True, bottom=True)\n",
+    "plt.axis(\"equal\")\n",
+    "plt.xlabel(None)\n",
+    "plt.ylabel(None)\n",
+    "plt.xticks([])\n",
+    "plt.yticks([])\n",
+    "plt.plot([2, 3], [8, 8], \"k\", linewidth=3)\n",
+    "plt.text(2, 7.9, \"1 mm\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;35mText\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2\u001b[0m, \u001b[1;36m7\u001b[0m, \u001b[32m'1 mm'\u001b[0m\u001b[1m)\u001b[0m"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "\u001b[1m<\u001b[0m\u001b[1;95mFigure\u001b[0m\u001b[39m size 64\u001b[0m\u001b[1;36m0x480\u001b[0m\u001b[39m with \u001b[0m\u001b[1;36m1\u001b[0m\u001b[39m Axes\u001b[0m\u001b[1m>\u001b[0m"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# Sagittal projection\n",
+    "# select objects within the medio-lateral range\n",
+    "df_sagittal = df[\n",
+    "    (df[\"Atlas_Z\"] >= ml_lims[0] / 1000) & (df[\"Atlas_Z\"] <= ml_lims[1] / 1000)\n",
+    "]\n",
+    "\n",
+    "plt.figure()\n",
+    "\n",
+    "for struct_name, contours in coords_sagittal.items():\n",
+    "    for cont in contours:\n",
+    "        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n",
+    "\n",
+    "# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\n",
+    "ax = sns.kdeplot(\n",
+    "    df_sagittal,\n",
+    "    x=\"Atlas_X\",\n",
+    "    y=\"Atlas_Y\",\n",
+    "    hue=\"Classification\",\n",
+    "    levels=nlevels,\n",
+    "    common_norm=False,\n",
+    "    palette=palette,\n",
+    ")\n",
+    "ax.invert_yaxis()\n",
+    "sns.despine(left=True, bottom=True)\n",
+    "plt.axis(\"equal\")\n",
+    "plt.xlabel(None)\n",
+    "plt.ylabel(None)\n",
+    "plt.xticks([])\n",
+    "plt.yticks([])\n",
+    "plt.plot([2, 3], [7.1, 7.1], \"k\", linewidth=3)\n",
+    "plt.text(2, 7, \"1 mm\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "\u001b[1;35mText\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m0.5\u001b[0m, \u001b[1;36m0.4\u001b[0m, \u001b[32m'1 mm'\u001b[0m\u001b[1m)\u001b[0m"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAGFCAYAAABg2vAPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADDpElEQVR4nOzdd3iTZdvA4V9W03TvvSi0ZZUtUxmyEQRxoShuRVTcA0FFX+V1viqKfoiKKCAgCChLkL1kjwKF0kJL915Jm/18fwQitYOCbVPgPo+jhzTPuhLT5Hrucd0ySZIkBEEQBEG4bskdHYAgCIIgCI4lkgFBEARBuM6JZEAQBEEQrnMiGRAEQRCE65xIBgRBEAThOieSAUEQBEG4zolkQBAEQRCucyIZEARBEITrnEgGBEEQBOE6J5IBQRAEQbjOiWRAEARBEK5zIhkQBEEQhOucSAYEQRAE4TonkgFBEARBuM4pHR2AIAjC9cBqtWI0Gh0dhnCNUalUKBSKf30ekQwIgiA0MqPRyNmzZ7FarY4ORbgGeXl5ERQUhEwmu+JziGRAEAShEUmSRHZ2NgqFgvDwcORy0TsrNAxJkqioqCAvLw+A4ODgKz6XSAYEQRAakdlspqKigpCQEFxcXBwdjnCN0Wg0AOTl5REQEHDFXQYiRRUEQWhEFosFACcnJwdHIlyrLiSZJpPpis8hkgFBEIQm8G/6cwWhLg3x3hLJgCAIgiBc50QyIAiCIAjXOZEMCIIgCMhkMlasWNHo19myZQsymYySkhL7YytWrKBVq1YoFAqee+45fvjhB7y8vBo9lv79+/Pcc881+nWuBiIZEARBuA7k5OTwzDPPEB0djVqtJjw8nFGjRrFx48YmjaN3795kZ2fj6elpf+yJJ57gjjvuID09nf/85z/cfffdJCUlNdg1a0pAAH799Vf+85//NNh1rmZiaqEgXGUKCws5fPgw586dw2w2YzKZMJvNWK1W+48kSdV+APt/ZTIZKpUKJycnNBoN/v7+tGrVirZt217xPHiLxcKhQ4c4ffo0ZWVlGI1GLBYLFoulxtguJkmSfZtMJkOtVuPs7IxGoyEoKIjWrVvTsmXLBqm0dj1KTU2lT58+eHl58dFHHxEfH4/JZOKPP/7gqaee4uTJk00Wi5OTE0FBQfbftVoteXl5DB06lJCQEPvjF6bMNSYfH59Gv8ZVQxIEodmrrKyUfvjhB6l79+4SUOVHpVJJzs7Okqurq+Tu7i55enpKXl5ekre3t+Tj4yP5+vpKfn5+kp+fn+Tv7y/5+/tLfn5+kqenp6TRaKqcy9PTU5o8ebJUVFR0WfGtWrVKCg0NtZ9HJpNJTk5Okqurq+Th4WGP5eI4AgICqvwEBwdLISEhUlBQkOTt7S1pNBpJJpPZz+ns7CwNHDhQWrJkiWQ2mxvplW54lZWV0okTJ6TKykqHxTB8+HApNDRU0mq11bYVFxdLkiRJgLR8+XL746+88ooUExMjaTQaqUWLFtK0adMko9Fo33748GGpf//+kpubm+Tu7i516dJF2rdvnyRJkpSamiqNHDlS8vLyklxcXKS2bdtKq1evliRJkjZv3iwBUnFxsf3fF/9s3rxZmjt3ruTp6Vklzt9++03q1q2bpFarJV9fX2nMmDH2bT/++KPUtWtXyc3NTQoMDJTuueceKTc3V5IkSTp79my1azzwwAOSJElSv379pGeffdZ+nqKiIun++++XvLy8JI1GIw0bNkxKSkqyb78Q17p166TWrVtLrq6u0tChQ6WsrKzL/n/SkBriPSaSAeGStm7dKo0cOVIKDg6u9oEhNK6SkhJp+vTpUkBAgARIQ4YMkebPny+dPHlSMplMDXINs9ks5eTkSJs2bZJef/11ycPDQ4qKipISExPrdfxnn30mAdKIESOk7du3S6WlpZLVam2Q2KxWq5Seni79+eef0ieffCL169dPAqQ2bdpIv/zyi2SxWBrkOo3J0clAYWGhJJPJpBkzZtS53z//tv/zn/9IO3fulM6ePSv99ttvUmBgoPTBBx/Yt7dr10667777pMTERCkpKUlasmSJdPjwYUmSJOmWW26RBg8eLB09elRKSUmRfv/9d2nr1q2SJFVNBgwGg3Tq1CkJkJYtWyZlZ2dLBoOhWjKwatUqSaFQSG+++aZ04sQJ6fDhw1Wez3fffSetWbNGSklJkXbv3i316tVLGj58uCRJtvf3smXLJEA6deqUlJ2dLZWUlEiSVD0ZuPXWW6U2bdpI27Ztkw4fPiwNHTpUatWqlT0Jmjt3rqRSqaRBgwZJ+/btkw4cOCC1adNGuvfeey//f0wDEsmA0CTWrFkjTZ06Vfr1119FMtBErFar9NNPP0mBgYGSRqORJk2aJJ08ebJJrp2amiq1a9dO8vf3v+Q158yZIwHSyy+/3GAJwKX89ddf0pAhQyRA6tSpk7Rt27Ymue6VcnQysGfPHgmQfv311zr3u9Tf9kcffSR17drV/ru7u7v0ww8/1LhvfHy8NH369Bq3XZwMSJKtZeJCi8AF/0wGevXqJY0fP77O+C+2b98+CZDKy8trvOYFFycDSUlJEiDt3LnTvr2goEDSaDTSkiVL7HEBUnJysn2fWbNmSYGBgfWOrTE0xHtMDCAULmn48OG8++673HbbbfU+Zvr06XTq1Invv/+eiIgI3NzcmDRpEhaLhQ8//JCgoCACAgJ47733qhwnk8mYPXs2I0eOxMXFhTZt2rB7926Sk5Pp378/rq6u9O7dm5SUlIZ+ms1GVlYWgwcP5v7776dv376cOnWKWbNmERcX1yTXj4yMZMuWLfj7+zN06FCys7Nr3G/16tU88cQTTJo0iQ8++KDJiur06NGDP/74g23btqHRaOjfvz9vv/22vdKfUJX0j/EZ9bV48WL69OlDUFAQbm5uTJs2jXPnztm3v/DCCzz66KMMGjSI999/v8rf5OTJk3n33Xfp06cPb731FkePHv1Xz+Hw4cMMHDiw1u0HDhxg1KhRRERE4O7uTr9+/QCqxHspiYmJKJVKevToYX/M19eXuLg4EhMT7Y+5uLjQsmVL++/BwcH2tQGuZiIZEBpNSkoKa9euZd26dfz8889899133HLLLWRkZLB161Y++OADpk2bxp49e6oc95///IcJEyZw+PBhWrduzb333ssTTzzBlClT2L9/P5Ik8fTTTzvoWTWu3bt307VrVxITE1m3bh1LliwhPDy8yePw8/Nj3bp1mEwmRo0ahU6nq7J9//793H333YwaNYqZM2c6pLreTTfdxPbt23nrrbd45513GDx4MEVFRU0eR3MXExODTCa7rEGCu3fvZvz48YwYMYJVq1Zx6NAhpk6dWmUJ5unTp3P8+HFuueUWNm3aRNu2bVm+fDkAjz76KGfOnOH+++8nISGBbt268cUXX1zxc6hrMKFOp2Po0KF4eHiwYMEC9u3bZ4+jMZaMVqlUVX6XyWRXnHA1Kw3VTCFcH6hnN8Fbb70lubi4SGVlZfbHhg4dKkVFRVXp542Li5P++9//Vjn/tGnT7L/v3r1bAqTvvvvO/tjPP/8sOTs7/8tn0vxs2LBB0mg00o033ijl5OQ4OhxJkiTp0KFDkpubmzRmzBj7/7fExETJ399f6tmzp6TT6Rwcoc2WLVskX19fKS4uTkpPT3d0OFU4uptAkiRp2LBhlzWA8OOPP5aio6Or7PfII49UG9R3sXHjxkmjRo2qcdtrr70mxcfHS5J0Zd0E/fv3r7WbYP/+/RIgnTt3zv7YTz/9JAHSoUOHJEmSpJ07d0qAVFBQUOXY+nYT/PLLLzXGJUmStHz5csnRX6Wim0Bo1qKionB3d7f/HhgYWG3qWmBgYLUmtg4dOlTZDhAfH1/lMb1eT1lZWWOF3uQ2bNjAyJEj6d+/P+vXr7c/b0fr1KkTP//8MytXruSOO+5gzZo1DBgwgICAAFatWtVsVuHr168fu3fvRq/XM2TIEIqLix0dUrMya9YsLBYL3bt3Z9myZZw+fZrExERmzpxJr169qu0fExPDuXPnWLRoESkpKcycOdN+tw1QWVnJ008/zZYtW0hLS2Pnzp3s27ePNm3aAPDcc8/xxx9/cPbsWQ4ePMjmzZvt267EW2+9xc8//8xbb71FYmIiCQkJfPDBBwBERETg5OTEF198wZkzZ/jtt9+q1Q6IjIxEJpOxatUq8vPz0Wq1NT7n0aNH89hjj7Fjxw6OHDnCfffdR2hoKKNHj77i2K8WIhkQGk1NzWk1PWa1Wms97kLzc02P/fO4q9XRo0cZO3YsN998M8uXL2+S+dWXY+TIkSxfvpx169Zxyy23EB0dzaZNm/D19XV0aFXExMSwfv168vLyuO222zAYDI4OqdmIjo7m4MGDDBgwgBdffJH27dszePBgNm7cyNdff11t/1tvvZXnn3+ep59+mk6dOrFr1y7eeOMN+3aFQkFhYSETJkwgNjaWu+66i+HDh/P2228DtpoTTz31FG3atGHYsGHExsby1VdfXXH8/fv355dffuG3336jU6dO3HzzzezduxcAf39/fvjhB3755Rfatm3L+++/z8cff1zl+NDQUN5++21ee+01AgMDa+1mnDt3Ll27dmXkyJH06tULSZJYs2ZNtc+ta1LDNVQI1wMuo5ugY8eOVR574IEHpNGjR1d57J9Te/55/gtzhC8090lS7SODr0bZ2dlSeHi41LlzZ/vI5+YqPz9f2rNnT4NNaWwsO3bskNRqtfTwww832QyHujSHbgLh2tYQ7zFRgVC4JK1WS3Jysv33s2fPcvjwYXx8fIiIiHBgZFc3k8nEnXfeiclk4vfff8fNzc3RIdXJz88PPz8/R4dxSX369OGbb77hgQceoGPHjkyePNnRIQlCsyeSAaEaq9VKYWGh/fedO3dWmVb4wgsvAHD33XfXOkJYp9NhNpvJz8+3P6bX6zEYDFUeM5lMVFZWVnnsevHaa6/x119/sWXLFkJDQx0dzjXlwmyUF198kV69enHDDTc4OiRBaNZkknQtzIkQGlJ+fj4BAQEOuXZeXh7+/v4OuXZTWr9+PUOHDuV///sfzz//vKPDuSYZjUZuvPFGioqKOHLkCK6urg6JQ6/Xc/bsWVq0aIGzs7NDYhCubQ3xHhMDCAWhiRUVFfHAAw8wZMgQnn32WUeHc81ycnJiwYIFZGVlVRn8JghCdSIZEIQmNmXKFCoqKpg7d+4VrxAo1E9MTAzvvPMOn3/+uX30uSAI1YlPIkFoQnv37uWbb77hvffeq7Jcq9B4nnvuOTp37syjjz6KyWRydDiC0CyJMQNCNf8cQNiUfH19r9m7ZUmS6NOnDzqdjoMHD6JQKBwd0nXj0KFDdOvWjRkzZvDqq6826bXFmAGhsTXEe0zMJhCqkcvl18Ugvqa2YMECdu/ezaZNm0Qi0MQ6d+7Mc889x9tvv82dd95JdHS0o0MShGbl2rwFE4RmpqysjJdffpnbb7+dAQMGODqc69Lbb7+Nv78/Tz755LWxsMxV4sIKphc8+OCDjBkzxmHx/Fv9+/fnueeec3QYDU4kA4LQBKZPn05ZWRmffvqpo0O5brm5uTFr1izWr19fpc6+ULucnByeeeYZoqOjUavVhIeHM2rUKDZu3Ojo0IQGJpIBQWhkBw8e5PPPP+fNN990yHLEwt9GjhzJiBEjeOmll8TaBZeQmppK165d2bRpEx999BEJCQmsW7eOAQMG8NRTTzk6vCbXGMshN+Z5L5dIBgShEVmtVp544gni4+PtlRsFx/r4449JS0tj9uzZjg6lWZs0aRIymYy9e/dy++23ExsbS7t27XjhhRf466+/7PuVlJTw6KOP4u/vj4eHBzfffDNHjhyp93WWLl1KfHw8Go0GX19fBg0ahE6nq/fxF7odZsyYQWBgIF5eXrzzzjuYzWZefvllfHx8CAsLY+7cuVWOe/XVV4mNjcXFxYXo6GjeeOONKrNNLnRvfPvtt3UOzFu9ejWenp4sWLAAgPT0dO666y68vLzw8fFh9OjRpKamVov3woyiuLi4ej/XxiQGEApCI1qxYgX79+9ny5Yt18fKZ1eBNm3aMGHCBN577z0eeeSRJq9MKEkSkknfpNe8QKZytq/6WZeioiLWrVvHe++9V+Pr4+XlZf/3nXfeiUajYe3atXh6ejJ79mwGDhxIUlISPj4+dV4nOzube+65hw8//JDbbruN8vJytm/fbh/TsWXLFgYMGMDZs2eJioqq9TybNm0iLCyMbdu2sXPnTh555BF27dpF37592bNnD4sXL+aJJ55g8ODBhIWFAeDu7s4PP/xASEgICQkJPPbYY7i7u/PKK6/Yz5ucnMyyZcv49ddfaxz0u3DhQiZOnMjChQsZOXIkJpOJoUOH0qtXL7Zv345SqeTdd99l2LBhHD16FCcnJwA2btyIh4cHGzZsqPP1aUoiGRCERvThhx/Sv39/+vXr5+hQhIu89dZbLFy4kC+++ILXXnutSa8tmfScfqtXk17zgpi3dyNzuvQS2cnJyUiSROvWrevcb8eOHezdu5e8vDzUajVga3lZsWIFS5cu5fHHH6/z+OzsbMxmM2PHjiUyMhKA+Ph4+3YXFxfi4uIumUj7+Pgwc+ZM5HI5cXFxfPjhh1RUVPD6668DtkJf77//Pjt27GDcuHEATJs2zX58VFQUL730EosWLaqSDBiNRn788ccaZ1fNmjWLqVOn8vvvv9v/vhcvXozVauXbb7+1J11z587Fy8uLLVu2MGTIEABcXV359ttv7clBcyCSAUFoJAcOHGDPnj2sXLnS0aEI/xAVFcUDDzzA559/zvPPP2//IhNs6jvb4siRI2i1Wnx9fas8XllZSUpKyiWP79ixIwMHDiQ+Pp6hQ4cyZMgQ7rjjDry9vQHo3r07J0+evOR52rVrV6U+SWBgIO3bt7f/rlAo8PX1JS8vz/7Y4sWLmTlzJikpKWi1WsxmMx4eHlXOGxkZWWMisHTpUvLy8ti5c2eVRbCOHDlCcnIy7u7uVfbX6/VVXo/4+Hh7IrBgwQKeeOIJ+7a1a9dy0003XfI5NzSRDAhCI/nmm28IDQ1lxIgRjg5FqMGzzz7LnDlzWLt2bZNOdZOpnIl5e3eTXe+f166PmJgYZDLZJb+ItVotwcHBbNmypdq2i7sSaqNQKNiwYQO7du1i/fr1fPHFF0ydOpU9e/bQokWLesUKVGs5kMlkNT5mtVoB2L17N+PHj+ftt99m6NCheHp6smjRIj755JMqx9TWhdS5c2cOHjzI999/T7du3eytAFqtlq5du9rHD1zs4qTi4vPeeuut9OjRw/67o1YwFcmAIDQCo9HI4sWLefrpp1EqxZ9Zc9SuXTvat2/P0qVLmzYZkMnq1VTvSD4+PgwdOpRZs2YxefLkal+KJSUleHl50aVLF3JyclAqlXX26ddFJpPRp08f+vTpw5tvvklkZCTLly9v1AG3u3btIjIykqlTp9ofS0tLq/fxLVu25JNPPqF///4oFAq+/PJLALp06cLixYsJCAio1spQG3d392otCY4gZhMIQiPYs2cPpaWl3HbbbY4ORajDmDFjWL16tVizoAazZs3CYrHQvXt3li1bxunTp0lMTGTmzJn06mUb8zBo0CB69erFmDFjWL9+PampqezatYupU6eyf//+S15jz549zJgxg/3793Pu3Dl+/fVX8vPzadOmDWBby6N169ZkZmY26HOLiYnh3LlzLFq0iJSUFGbOnHnZtSdiY2PZvHkzy5YtsxchGj9+PH5+fowePZrt27dz9uxZtmzZwuTJk8nIyGjQ59DQRDIgCI1g8+bNeHp6Vqm8JjQ/o0ePpqSkpMpUOcEmOjqagwcPMmDAAF588UXat2/P4MGD2bhxI19//TVgu6tfs2YNffv25aGHHiI2NpZx48aRlpZGYGDgJa/h4eHBtm3bGDFiBLGxsUybNo1PPvmE4cOHA1BRUcGpU6caPFm79dZbef7553n66afp1KkTu3btuqJlruPi4ti0aRM///wzL774Ii4uLmzbto2IiAjGjh1LmzZteOSRR9Dr9fVuKXAUsVCRIDSCgQMH4urqym+//eboUIQ6WCwWPDw8eOedd3jxxRcb5RpioSKhsTXEe0y0DAhCA5MkicOHD9O9e3dHhyJcgkKhoF27dhw7dszRoQiCQ4lkQBAaWGFhIUVFRZecoy00D9HR0Zw5c8bRYQiCQ4lkQBAa2Llz5wCueHS10LTatWvH8ePHHR2GIDiUSAYEoYFdGPnsqPnCwuWJiIigsLCw2SwYIwiOIJIBQWhg+fn5ADVWLhOanwvV7oqLix0ciSA4jkgGBKGBmUwmFAqFKDZ0lbhQFla0DAjXM5EMCEIDk8vlWCwWR4ch1NOF1egulKoVhOuRSAYEoYGJO82rkyi5IlzPRDIgCA3M09MTgNLSUgdHItTHhbECF8YOCML1SCQDgtDAfHx8AFu9AaH5y8/PR6VSNftysVer6dOnVynL/eCDDzbpwlANrX///va1CK4lIhkQhAYWEhICQHp6uoMjEeojJSWFsLAw+zK0wt9ycnJ45plniI6ORq1WEx4ezqhRo9i4caOjQxMamEgGBKGBRUdH4+npyd69ex0dilAP+/fvp1u3bo4Oo9lJTU2la9eubNq0iY8++oiEhATWrVvHgAEDeOqppxwdXpNrrDFAtZ03KiqKLVu2NMo1ayKSAUFoYHK5nO7du7Nr1y5HhyJcgtFoZP/+/fTo0cPRoTQ7kyZNQiaTsXfvXm6//XZiY2Np164dL7zwQpVVHktKSnj00Ufx9/fHw8ODm2++mSNHjtT7OkuXLiU+Ph6NRoOvry+DBg1Cp9PV+/gL3Q4zZswgMDAQLy8v3nnnHcxmMy+//DI+Pj6EhYUxd+7cKse9+uqrxMbG4uLiQnR0NG+88UaV1REvdG98++23dS4AtHr1ajw9PVmwYAFgaxG866678PLywsfHh9GjR5Oamlot3vfee4+QkBDi4uLq/Vwbk0gGBKERDBw4kC1btqDX6x0dilCHPXv2UFlZSb9+/ZrsmpIkYbIYHPJT3xkTRUVFrFu3jqeeegpXV9dq2728vOz/vvPOO8nLy2Pt2rUcOHCALl26MHDgQIqKii55nezsbO655x4efvhhEhMT2bJlC2PHjrXHuWXLFmQyWZUv05ps2rSJrKwstm3bxv/+9z/eeustRo4cibe3N3v27GHixIk88cQTZGRk2I9xd3fnhx9+4MSJE3z++efMmTOHTz/9tMp5k5OTWbZsGb/++iuHDx+udt2FCxdyzz33sGDBAsaPH4/JZGLo0KG4u7uzfft2du7ciZubG8OGDavSArBx40ZOnTrFhg0bWLVq1SVfp6YgqqIIQiMYOXIkr732Gps2bWLEiBGODkeoxW+//Ya/vz+dO3dusmuarUZmHpraZNe72OTO76FSqC+5X3JyMpIkXXKxrR07drB3717y8vJQq23n/fjjj1mxYgVLly7l8ccfr/P47OxszGYzY8eOJTIyEoD4+Hj7dhcXF+Li4lCpVHWex8fHh5kzZyKXy4mLi+PDDz+koqKC119/HYApU6bw/vvvs2PHDsaNGwfAtGnT7MdHRUXx0ksvsWjRIl555RX740ajkR9//LHGaqKzZs1i6tSp/P777/ZkcvHixVitVr799lv7GJS5c+fi5eXFli1bGDJkCACurq58++239mnIzYFIBgShEbRt25bWrVvz008/iWSgmZIkiaVLlzJ27Fh74SHBpr4tCEeOHEGr1eLr61vl8crKSlJSUi55fMeOHRk4cCDx8fEMHTqUIUOGcMcdd9ineXbv3p2TJ09e8jzt2rVDLv+7oTswMJD27dvbf1coFPj6+pKXl2d/bPHixcycOZOUlBS0Wi1ms7najJLIyMgaE4GlS5eSl5fHzp07ueGGG+yPHzlyhOTkZNzd3avsr9frq7we8fHx1RKBiRMnMn/+fPvvFRUVDB8+vMp7U6vVXvK1uFIiGRCERiCTyXj44Yd54403KCoqsk83FJqPAwcOkJqaytixY5v0ukq5E5M7v9ek17z42vURExODTCa75BexVqslODi4xoFuF3cl1EahULBhwwZ27drF+vXr+eKLL5g6dSp79uyhRYsW9YoVqNZyIJPJanzsQpXJ3bt3M378eN5++22GDh2Kp6cnixYt4pNPPqlyTE1dJACdO3fm4MGDfP/993Tr1s3eCqDVaunatat9/MDFLk4qajrvO++8w0svvWT/vX///nzwwQdNNp5FJAOC0EgmTJjA1KlT+f7776v8kQvNw1dffUVYWBg333xzk15XJpPVq6nekXx8fBg6dCizZs1i8uTJ1b68SkpK8PLyokuXLuTk5KBUKq94yW6ZTEafPn3o06cPb775JpGRkSxfvpwXXnihAZ5JzXbt2kVkZCRTp/7dXZOWllbv41u2bMknn3xC//79USgUfPnllwB06dKFxYsXExAQcNl1KwICAggICLD/rlQqCQ0NpVWrVpd1nislBhAKQiMJDAxk/PjxfPbZZ6I0cTNz5swZfvrpJ5599lmxoFQtZs2ahcVioXv37ixbtozTp0+TmJjIzJkz6dWrFwCDBg2iV69ejBkzhvXr15OamsquXbuYOnUq+/fvv+Q19uzZw4wZM9i/fz/nzp3j119/JT8/nzZt2gCwd+9eWrdubV8WvKHExMRw7tw5Fi1aREpKCjNnzmT58uWXdY7Y2Fg2b97MsmXL7EWIxo8fj5+fH6NHj2b79u2cPXuWLVu2MHny5CqDF5sjkQwIQiN6+eWXyczMZN68eY4ORbjIe++9h6+vL5MmTXJ0KM1WdHQ0Bw8eZMCAAbz44ou0b9+ewYMHs3HjRr7++mvAdle/Zs0a+vbty0MPPURsbCzjxo0jLS2NwMDAS17Dw8ODbdu2MWLECGJjY5k2bRqffPIJw4cPB2z95qdOnaoy5a8h3HrrrTz//PM8/fTTdOrUiV27dvHGG29c9nni4uLYtGkTP//8My+++CIuLi5s27aNiIgIxo4dS5s2bXjkkUfQ6/XNvsKlTBKrcwhCoxo3bhw7d+7k9OnTtc5VFppOXl4eYWFhzJgxo0m6b/R6PWfPnq1zrrog/BsN8R4TLQOC0MjefvttMjIyWLRokaNDEYDZs2ejUCh46KGHHB2KIDQbIhkQhEYWFxfH4MGD+f777x0dynXPbDYza9YsHnjggWrT4QTheiaSAUFoAvfeey87duygoKDA0aFc17Zs2UJubi6PPPKIo0MRhGZFJAOC0AQCAwORJImSkhJHh3Jd27dvH0qlkrZt2zo6FEFoVkQyIAiNyGKxsGbNGiZNmkRsbOwVz8UWGsaAAQNQqVS0bt2a2bNnYzAYHB2SIDQLIhkQhEZQUVHBp59+SkxMDLfccguhoaH8/vvvV/Wc9uTkZL7++msqKysdHcoV69mzJwcPHuTGG2/kySefpGXLlvzvf/+joqKi0a8tJm4JjeVCZcV/Q0wtFIQGZDab+fLLL5kxYwbFxcXcc889PPnkk/Ts2dNesvRqJEkS3bp14+DBg7z66qu8//77jg7pX0tMTOTDDz9k/vz5BAYG8p///IcHHnigSo37hmCxWDh9+jQuLi74+/tf1e8DoXmRJAmj0Uh+fj4Wi4WYmJgrfv+KZEAQGsiRI0d45JFHOHjwII8++ihTpky5rPrqzdnhw4fp3Lkz0dHRGAwG0tPTr5kvtZSUFKZOncrixYsZMmQI8+bNIygoqEGvodVqycjIEK0DQqNwcXEhODj4X62CKJIBQfiXJElizpw5TJ48mZiYGL799tsmW1ykqXz22WdMmTKF+fPnc8cdd5CRkUFoaKijw2pQ69evZ8KECchkMn7++Wf69+/foOe3WCwNXklPEBQKBUql8l8n51dvB6YgNAM6nY4nn3ySn376iUmTJvG///3Pvq77taSgoAB/f39iY2MB26Iu11oyMGTIEA4fPsy9997LwIEDmT17No8++miDnV+hUIilkoVmSyQDgnCFsrKyuOWWW0hKSmLBggXce++9jg6p0fj5+ZGfn8/BgwcBCA4OdnBEjSMoKIgNGzYwefJkHnvsMYqLi3nppZeumS4RQaiN6CYQhCtw7NgxRowYgdVqZc2aNXTo0MHRITWq06dP07lzZ3Q6Hb1792bnzp2ODqlRSZLEG2+8wXvvvcezzz7LJ598Iu7qhWuaSAYE4TJt3LiR22+/naioKFavXn3NNZfXZv/+/WzevJmHH374uinl+/XXX/P0009z2223MX/+fLHQkHDNEsmAIFyGn376iYcffpiBAweyZMmSZr8sqfDvrVy5knHjxtGxY0eWL19+zXaRCNc3UXRIEOrBarXy7rvvMmHCBB544AF+//13kQhcJ0aPHs327dtJT0+ne/fu9nETgnAtEcmAIFxCWVkZt99+O2+88QZvv/02c+bMQaVSOTosoQl169aNvXv3EhQURO/evfn6669FzQDhmiK6CQShDgcOHOCee+4hNzeX+fPnM2rUKEeHJDiQXq/npZdeYtasWdx+++3Mnj37uhk/IVzbRMuAINTAYrHwwQcf0KtXLzw8PDhw4IBIBAScnZ358ssvWbZsGZs2baJDhw5s2LDB0WEJwr8mkgFB+IdTp05x4403MmXKFJ577jl27dpFq1atHB2W0IyMHTuWhIQE2rZty5AhQ3jyySfRarWODksQrphIBgThPIvFwkcffUTHjh0pLCxkx44dfPjhh/+q3rdw7QoNDeWPP/5g1qxZ/Pjjj3To0IFt27Y5OixBuCIiGRAEbIvV9OvXj1dffZWnn36aw4cP07t3b0eHJTRzcrmcSZMmceTIEUJDQ+nfvz+vv/66WINAuOqIAYTCdW/p0qU8/PDD+Pn5MW/ePG666SZHhyRchSwWCx9++CFvvvkmXbp0YeHChbRs2dLRYQlCvYiWAeG6ZbFYeOGFF7jzzjsZPnw4hw8fFomAcMUUCgVTpkxh586dFBYW0rlzZ1auXOnosAShXkQyIFyXtFotY8aMYebMmcycOZNFixaJIkJCg7hQmGjw4MHcdtttfPTRR6ImgdDsiW4C4bqTl5fH8OHDOX36NL/88gtDhw51dEjCNchqtfLmm2/y3nvv8cwzz/DZZ58hl4v7L6F5EksYC9eVzMxMBg4cSGlpKdu3b6djx46ODkm4Rsnlct59913CwsKYNGkSRUVFzJ07V1SvFJolkQwI143U1FRuvvlmLBYL27dvF7UDhCYxceJEfHx8GD9+PHq9nkWLFqFUio9eoXkR3QTCdSEjI4O+ffsik8nYtGkTkZGRjg5JuM78/vvvjB07lrvvvpt58+ahUCgcHZIg2In0VLjmZWVlMWDAACwWC9u2bROJgOAQo0aNYuHChYwbNw65XM73338vWgiEZkO8E4Vr2oVEQK/Xs3XrVpEICA515513YrVaGT9+PAaDgfnz54sxBEKzILoJhGtWbm4uffv2pbKyks2bN4sCMEKzsXz5cu6++27GjBnDwoULRQuB4HBinotwTSosLGTQoEGUl5eLREBodm677TZ++eUXli9fzoMPPojFYnF0SMJ1TqSjwjWnrKyMYcOGkZOTw9atW0UiIDRLo0ePto8hcHJy4ttvvxV1CASHEcmAcE2pqKhg1KhRnD59ms2bN9O2bVtHhyQItbrzzjsxGAxMmDABDw8PPv30U2QymaPDEq5DIhkQrhlGo5E77riD/fv3s2HDBjp37uzokAThku677z7Ky8uZNGkSrq6uvPvuuyIhEJqcSAaEa4LFYuG+++5j48aNrFq1Siw/LFxVnnzySXQ6HS+//DJOTk689dZbjg5JuM6IZEC46kmSxFNPPcWyZctYtmwZgwcPdnRIgnDZXnrpJUwmE6+//jp+fn489dRTjg5JuI6IZEC46r3xxhvMnj2b77//njFjxjg6HEG4Yq+99hr5+fk888wzBAUFcfvttzs6JOE6IeoMCFe1r7/+mkmTJvHhhx/y8ssvOzocQfjXLhQlWr58OevXr6dv376ODkm4DohkQLhqrVmzhlGjRvHUU0/x+eefi0FXwjXDYDAwfPhwDh06xO7du2ndurWjQxKucSIZEK5KCQkJ9O7dm5tvvplff/1VLPoiXHNKS0vp3bs3RqORPXv24OPj4+iQhGuYSAaEq05BQQE33HADnp6e7NixAzc3N0eHJAiN4syZM3Tv3p1OnTqxbt06UbZYaDSi3JVwVTGbzYwbNw6tVsvKlStFIiBc06Kjo1m6dClbtmzh9ddfd3Q4wjVMJAPCVWX69Ols3ryZJUuWiBUIhetC//79ef/99/noo49Yu3ato8MRrlGim0C4amzatIlBgwbx7rvvirsk4bpitVq55ZZbOHDgAEeOHCE4ONjRIQnXGJEMCFeFvLw8OnbsSNu2bdmwYYNY0EW47lz4G4iPj2fdunXib0BoUOLdJDR7kiTx0EMPYbFYmD9/vvgQFK5LAQEB/Pjjj2zYsIFPPvnE0eEI1xjxqSo0ezNnzmTNmjX88MMPonlUuK4NHjyYl19+malTp3Lw4EFHhyNcQ0Q3gdCsHT58mB49evDkk0/y2WefOTocQXA4o9FIr1690Ol0HDhwAFdXV0eHJFwDRDIgNFsVFRV07doVtVrNnj17UKvVjg5JEJqFU6dO0aVLF8aPH88333zj6HCEa4DoJhCarRdeeIG0tDR+/vlnkQgIwkXi4uL4/PPPmTNnDsuWLXN0OMI1QLQMCM3S6tWrGTlyJF9//TUTJ050dDiC0OxIksSdd97Jpk2bSEhIIDQ01NEhCVcxkQwIzU5hYSHt27enS5curFq1SixAJAi1KCoqon379nTq1InVq1eLvxXhioluAqHZefrppzEYDMyZM0d8uAlCHXx8fJgzZw5r167l+++/d3Q4wlVMtAwIzcqSJUu4++67WbhwIffcc4+jwxGEq8LDDz/M0qVLOXbsGBEREY4OR7gKiWRAaDby8/Np27YtAwYMYPHixaJVQBDqqbS0lHbt2tGhQwfRXSBcEdFNIDQbzzzzDJIkMWvWLPFhJgiXwdPTk6+//pq1a9eyYMECR4cjXIVEy4DQLKxcuZIxY8awYMEC7r33XkeHIwhXpXvvvZf169eTmJiIv7+/o8MRriIiGRAcrqysjDZt2tC5c2d+//130SogCFcoPz+f1q1bM2LECH766SdHhyNcRUQ3geBwb775JiUlJaJ7QBD+JX9/fz7++GPmz5/Pxo0bHR2OcBURLQOCQx05coQuXbrw3//+l1deecXR4QjCVU+SJPr3709ubi4JCQmoVCpHhyRcBUQyIDiMJEkMGDCA3Nxcjh49Kj60BKGBHD58mC5duvDVV1+JCp5CvYhkQHCYZcuWcccdd7B27VqGDRvm6HAE4ZoyYcIENmzYQEpKCi4uLo4OR2jmRDIgOITFYqF9+/ZERkaybt06R4cjCNecM2fO0Lp1a6ZPn87rr7/u6HCEZk4MIBQcYuHChZw8eZJ3333X0aEIwjUpOjqaSZMm8f7775Ofn+/ocIRmTrQMCE1Or9fTrl074uPjWbFihaPDEYRrVkFBAbGxsfTt25fly5eL2TpCrUTLgNDkPvjgA86dO8d///tfR4ciCNc0Pz8/5s6dy8qVK/nss88cHY7QjIlkQGhSmzdv5p133mHKlCm0adPG0eEIwjVv9OjRvPjii7zyyits377d0eEIzZToJhCaTFZWFp07dyY+Pp4//vgDhULh6JAE4bpgMpkYPHgwJ0+eJCEhQZQqFqoRLQNCk9Dr9YwdOxaVSsXChQtFIiAITUilUrF48WJMJhPPPfeco8MRmiGRDAhN4qmnnuLIkSMsX76cgIAAR4cjCNedwMBAPv30UxYuXMiqVascHY7QzIhuAqHRrVmzhltuuYXvvvuOhx9+2NHhCMJ1S5IkRo4cyaFDhzh58iQeHh6ODkloJkQyIDQqnU5H27Ztad26NevWrRNTmwTBwdLT02nTpg2PP/44//vf/xwdjtBMiG4CoVG9++675Obm8tVXX4lEQBCagfDwcF5//XW+/PJLzpw54+hwhGZCtAwIjSYzM5OWLVvy6quv8vbbbzs6HEEQzquoqKBVq1YMHDiQn376ydHhCM2AaBkQGs0HH3yAi4sLL774oqNDEQThIi4uLkybNo0FCxaQmJjo6HCEZkAkA0KjyM7OZs6cOTz33HNikJIgNEOPPPIIoaGhYn0QARDJgNBI/vvf/+Ls7MzkyZMdHYogCDVQq9VMmTKFRYsWcfLkSUeHIziYSAaEBpeZmcns2bN58cUX8fLycnQ4giDU4pFHHiE4OFi0DggiGRAa3qeffoqLi4toFRCEZu5C68DPP/9McnKyo8MRHEgkA0KD0mq1zJkzh4kTJ4qxAoJwFXj44Yfx8fHhiy++cHQoggOJZEBoUPPnz0er1TJp0iRHhyIIQj1oNBoee+wx5s6dS3l5uaPDERxEJANCg/rmm28YNWoU4eHhjg5FEIR6mjRpEhUVFcybN8/RoQgOIpIBocEcPXqUQ4cO8dBDDzk6FEEQLkNYWBi33nor33//vaNDERxEJANCg5k/fz6+vr4MHz7c0aEIgnCZJkyYwKFDhzh27JijQxEcQCQDQoOwWq0sWrSIu+++GycnJ0eHIwjCZRoxYgQ+Pj6iPPF1SiQDQoPYs2cP6enp3HXXXY4ORRCEK+Dk5MTtt9/O8uXLHR2K4AAiGRAaxOLFiwkODubGG290dCiCIFyhUaNGcfr0aU6dOuXoUIQmJpIB4V+zWq0sWbKEO++8E4VC4ehwBEG4QgMHDkSj0bBy5UpHhyI0MZEMCP/agQMHyM7OZuzYsY4ORRCEf8HFxYVhw4axdOlSR4ciNDGRDAj/2rp16/Dw8KB3796ODkUQhH/p9ttvZ9++fWRnZzs6FKEJiWRA+Nf++OMPBg4ciEqlcnQogiD8S0OGDEEmk7FhwwZHhyI0IZEMCP9KSUkJf/31F8OGDXN0KIIgNAB/f3+6du3KunXrHB2K0IREMiD8K9u3b8disTBo0CBHhyIIQgMZNmwYf/zxB1ar1dGhCE1EJAPCv7J161bCwsJo0aKFo0MRBKGB3HzzzRQVFYlqhNcRkQwI/8q2bdvo168fMpnM0aEIgtBAevTogVKpZMeOHY4ORWgiIhkQrlh5eTkHDx6kX79+jg5FEIQG5OLiQpcuXdi5c6ejQxGaiEgGhCu2a9cuLBYLffv2dXQogiA0sJtuuolt27YhSZKjQxGagEgGhCu2Y8cO/P39iY2NdXQogiA0sH79+pGRkUFqaqqjQxGagEgGhCu2c+dOevfuLcYLCMI1qE+fPgBi3MB1QiQDwhUxm83s3btXVB0UhGuUj48PrVu3ZteuXY4ORWgCIhkQrkhCQgI6nU4kA4JwDevTp49IBq4TIhkQrshff/2FUqmka9eujg5FEIRG0qdPHxISEigpKXF0KEIjE8mAcEV2795Np06d0Gg0jg5FEIRG0qdPHyRJYs+ePY4ORWhkIhkQrsiFwYOCIFy7YmJi8Pf3F/UGrgMiGRAuW1ZWFmfOnOGmm25ydCiCIDQimUxG7969xbiB64BIBoTLdmGq0YWpR4IgXLt69+7NX3/9hcVicXQoQiMSyYBw2Xbv3k2LFi0IDg52dCiCIDSyXr16odPpSEhIcHQoQiMSyYBw2f766y969Ojh6DAEQWgC3bp1Q6lUsnv3bkeHIjQikQwIl8VgMHDw4EF69uzp6FAEQWgCGo2GTp068ddffzk6FKERiWRAuCyHDx/GaDTSq1cvR4ciCEIT6dGjh0gGrnEiGRAuy969e3FycqJjx46ODkUQhCbSvXt3kpKSKC0tdXQoQiMRyYBwWfbv30/Hjh1Rq9WODkUQhCZyodLo4cOHHRuI0GhEMiBclv3794sSxIJwnYmLi0Oj0XDgwAFHhyI0EpEMCPWm1Wo5efKkSAYE4TqjVCrp2LEjBw8edHQoQiMRyYBQbwcPHsRqtdK9e3dHhyIIQhPr1q0b+/fvd3QYQiMRyYBQbwcOHECj0dC2bVtHhyIIQhPr1q0bp06dEoMIr1EiGRDq7cLgQaVS6ehQBEFoYhe6Bw8dOuTgSITGIJIBod7279/PDTfc4OgwBEFwgNatW4tBhNcwkQwI9VJSUkJSUhLdunVzdCiCIDiAUqmkc+fOYtzANUokA0K9XPgAEIMHBeH61bVrV9EycI0SyYBQL0eOHMHFxYWYmBhHhyIIgoN06dKF06dPU1ZW5uhQhAYmkgGhXg4cOEDHjh1RKBSODkUQBAfp1KkTgFjO+BokkgGhXg4cOCAGDwrCda5t27aoVCqOHDni6FCEBiaSAeGSKisrSU5OpkOHDo4ORRAEB3JycqJly5acOnXK0aEIDUwkA8IlHTt2DKvVSnx8vKNDEQTBwWJjY0UycA0SyYBwSRf+8Nu0aePgSARBcLR27dpx7NgxR4chNDCRDAiXlJycTGBgIO7u7o4ORRAEB2vXrh2ZmZliRsE1RiQDwiWdOXOGli1bOjoMQRCagbi4OADRVXCNEcmAcElpaWlEREQ4OgxBEJqBVq1aAZCSkuLgSISGJJIB4ZKSkpKIjY11dBiCIDQDXl5e+Pj4iGTgGiOSAaFOlZWV5OTk0KJFC0eHIghCM9GiRQtSU1MdHYbQgEQyINQpOTkZ+LtpUBAEISwsjMzMTEeHITQgkQwIdTp9+jSA6CYQBMEuODiY7OxsR4chNCCRDAh1Onv2LK6urvj7+zs6FEEQmonIyEjOnj2LJEmODkVoICIZEOqUmppKVFQUMpnM0aEIgtBMxMXFUVpaSl5enqNDERqISAaEOqWlpREVFeXoMARBaEZCQ0MBRFfBNUQkA0KdcnNzCQwMdHQYgiA0I76+vgAUFhY6OBKhoYhkQKhTUVERPj4+jg5DEIRmxM/PD4CCggIHRyI0FJEMCHUqLi7G29vb0WEIgtCMeHh4oFQqRcvANUQkA0KtJEmipKQELy8vR4ciCEIzIpPJ8PLyoqSkxNGhCA1EJANCrQwGAxaLBQ8PD0eHIghCM+Pl5UVpaamjwxAaiEgGhFpptVoA3NzcHByJIAjNjZeXF8XFxY4OQ2ggIhkQaiWSAUEQauPh4UFZWZmjwxAaiEgGhFpdSAZcXV0dHIkgCM2NRqOhsrLS0WEIDUQkA0KtRMuAIAi1cXNzQ6fTOToMoYGIZECo1YU/dNEyIAjCP7m5udlvGISrn0gGhFqZTCYAnJycHByJIAjNjaurq0gGriEiGRBqdWFFMrlcvE0EQahKoVBgtVodHYbQQMSnvFCrC3/oYsVCQRD+SSaTiSWMryEiGRBqdSEZEC0DgiD8k1wuFy0D1xDxKS9ckmgZEAThn8xmM0ql0tFhCA1EJANCrS60CFgsFgdHIghCc6PT6cRMo2uISAaEWqlUKuDvWQWCIAgX6HQ6XFxcHB2G0EBEMiDUytnZGQC9Xu/gSARBaG4qKipEMnANEcmAUKsLqxWKlckEQfgn0U1wbRHJgFArHx8fAIqKihwciSAIzY1Wq8Xd3d3RYQgNRCQDQq1EMiAIQm3Ky8vFuiXXEJEMCLW60AQoFiMRBOGfiouL8fLycnQYQgMRyYBQK5lMhpubm1izXBCEakpKSkQycA0RyYBQJ19fXwoLCx0dhiAIzYjJZEKn0+Ht7e3oUIQGIpIBoU4BAQHk5uY6OgxBEJqRCzOMRDJw7RDJgFCn4OBgsrKyHB2GIAjNSEFBAfD3IGPh6ieSAaFOYWFhpKenOzoMQRCakdTUVAAiIyMdG4jQYEQyINQpMjKStLQ0sVSpIAh2KSkpqFQqwsLCHB2K0EBEMiDUKSYmhvLycvLy8hwdiiAIzURycjItWrRAoVA4OhShgYhkQKhTTEwMAElJSQ6ORBCE5uLkyZO0bt3a0WEIDUgkA0KdYmJiUCqVJCQkODoUQRCaiVOnThEXF+foMIQGJJIBoU5qtZp27dpx6NAhR4ciCEIzoNVqSU1NFS0D1xiRDAiX1KVLFw4cOODoMARBaAYOHTqEJEl069bN0aEIDUgkA8Il9erVi6NHj4qljAVB4MCBAzg7O9O2bVtHhyI0IJEMCJc0aNAgLBYLW7dudXQogiA42K5du+jcuTNKpdLRoQgNSCQDwiW1aNGC6Oho1q5d6+hQBEFwILPZzJ9//sngwYMdHYrQwEQyINTL6NGjWb58ORaLxdGhCILgIH/99RfFxcUMHz7c0aEIDUwkA0K93HXXXeTm5rJhwwZHhyIIgoPMnTuXiIgIbrjhBkeHIjQwkQwI9dKjRw86derEJ5984uhQBEFwgPLycpYsWcIjjzwiKg9eg0QyINSLTCZj6tSp/Pnnn2zbts3R4QiC0MTmzp1LZWUlDz/8sKNDERqBTBIr0Aj1ZLVaueGGG3BycmLXrl3IZLImj0GSrBgtBgxWAyaLAZPViNlqxGw1Y7KasEgmLFYzFsmCVbJglaxYJSsSViRJQqLq212GDJlMjvz8j0KmRC5ToJQrUcpUKOVOqBROOMnVqBVqnBQa1Ao1MpnIowGsJgPmkhxMpTmYS3Mwl+Vj0RZhrijBWlmO1aDFaqxEMhuRLCaQAJkMmVKFXKlGpnZB4eyOwsUThasPSg9/lJ6BqLxDUPmEonB2d/RTFICioiLi4uIYMWIE8+bNc3Q4QiMQyYBwWbZs2cKAAQNYuHAh99xzz78+nyRJ6C0VlBtL0BpL0ZrK0JnKqDBpqTBrqTTr0JsrMVgu/BgAx75lZchQKzVoFK5oVK64KN1wVbnjqnLHTeWJu5MX7k5eeDh5o1I4XdE1JEnCqi/HUlGKtbIMi0GHZKjAatLbvlitFs5/syKTK5ApnZApnZCrXZA7uSJ3dkXh7I5c445c5XzFz1WyWrFoCzGVZGMqysBUlImxKB1TYQamonTMZflXfO76ULj54OTfAnVgK9RBMahDWqMOikGuUjfqdYWqnnrqKRYsWMDJkycJCgpydDhCIxDJgHDZxo4dy/79+0lOTsbJqX5fdkaLgcLKHAr0uRRV5lJiKKTEUEipoRCT1XjZMchlcpzkavudu+0uXoVSrkQhU6KQK8/f7SuQI0cmk9lbAS4mSVYkpPMtCBZbi4LVglkynW9tMGKyGjFa9BgtBiyS+bLidFG64aX2w8vZFy+1H77OAfhoAvGQnLGW5GAqysRUnIW5JBtTaS7msjzbj7YQLJd3rdrIlE7INZ4oNLbkQKF2Q+akQa5yRqZQgkwOkoRkMWE16bEadFgrSjFrCzGXF4K17jhkKmdUXsEovYJsd/ZufrY7fRdP5M5uyFUaZConkCuRyWRIViuSxYRkNmA1VJxPekowa4swl+VjLs3FVJSBRVdc8wUVSpyDYnGO6IhLi85oorqidPdtkNdKqO706dO0adOG999/n5deesnR4QiNRCQDwmVLTEykXbt2fPPNNzz66KPVtlusFvIqMsjSpZGtO0euLoMSQ0Gd59QoXXF38rLfXbuq3NEoXdEoXXFWuuCs0KBWalArNKgVzihkSod0U5itJvTmSvQWHXpzBRVmHRWmcnQmLVpT6fnWjVLKjCUYLfpazyOzWnHVVuBRosWjtBzPEtuPk9FUdT+VMwqNh+1L1ckFuZMGmdIJ5ApkMjmSZAWrBclsxGoyYDVW2L7M9VqsBh1I1n//pGVylB4BqHxCUfmE4eQTdv7f4bamfFfvRvl/YTXoMBakYchNwZCbjCE7CUPWyRqTBKeAaFxa9cA1phcu0Tcgd9I0eDzXqwkTJrBx40aSk5PRaMTreq0SyYBwRe644w6OHTvGyZMnASjRF5BSeoLU0lNkas/WeLfvqnLH1zkIX00g3s5+eKl98VT74eHkhVKuauqn0OAkScJUcA5dyh4qzx6kLPsYpaZSKlw16Nxc0Lm5oPVwRevuillVc/U2d5mGAKdAgt0iCfWOI8gjGqX8yiq9SZJkSwwqS7FUlGHRl2OtLLM9ZqxEMumRLGbs3Q0KJTKVM3InFxQuXijcvFG6+6N097O1IDQDkiRhLsmi8lwClWmHqUw9iCHnNFz0MSZTqnFpeQNubfrj1qYvSo8AB0Z8dTt9+jStW7fms88+45lnnnF0OEIjEsmAcEV+++03Jjx+Hz+um02xKouCyuwq250VLoS4RRHiFkmgSxgBLqG4qNwcFG3j0mcmUnZkLdpjGzEVZ1bbrvIJQx0cizqwFU7+Uaj8ojB4eFJkLSO/Mov8imzyKjIorqH1RCFTEuQaTqhbC8Lcowl1i8JJceVjAK5FFl0JFWf2oTu9G93p3ZhL/vFeDI/HrW1/3Nr0wymgpUNalK5WU6dO5f/+7//IzMzE2Vm8765lIhkQLoskSZwrP82+7K2cLT2JXG77YJUhJ9w9mhaerYn0iMVPE3RNj7iXLCbKjqyjeOcCDFkn7Y/LFCo0kZ3QRHdDE9kR57B29R4RrzdXkleRQbbuHNm6c2RpU6k066rsI0NOkGsY4e6tiPBoRYhbC1TXQKtKQ5EkCWNuCtqTW9Ge2II+PaHKdpV3CC4xvXFt1R1NVBeU7n4OivTqMGDAAHx9fVm6dKmjQxEamUgGhHo7V3aa7ZlryNGl2x/T51i5tcfdtPKOR6N0cWB0TUOSJLQnNpO/5lNMRbbXQaZQ4dZ2AO4dhuIa0wu5umFeB0mSKDYUkKU9S0b5GTLKz1BqLKqyj0KmIMQtikiPWCI9YghwCUN+DSdhl8tclo82cSvaE5upOLMPyVy1+0rlHYI6tC3qoFjUQa1w8otE5RuOXHlls0CuNZGRkYwfP54ZM2Y4OhShkYlkQLgkrbGMTeeWc7rEdpellKuI9+vBJy98jZfajwULFjR6DAaL/vz0wzIqzOXnpxxWYDg/yt9Wb8CERTLb6wtcYJtFILPPMrgw88BJocZJrsZJoUatcEatdEGjdMFF6YaLyg2N0q3KF6tZW0Tu8nfQntgCgMLVG+8b78PrhttRuHo1+msAUGYo4lx5CunlyZwrS0ZrqrqstLNCQ7hHKyLcY4jwiMFb7dfozeKSxYyxMB1jQSqmgnOYSnIwl+djqSixTYe0mECSbLManDQoXL1Revij8g5F7d8CdXAMCnf/Ro/Taqyk4sw+Kk7/RcWZ/Rhyq441sJPJUHoG2QZK+oah8o3AyTccJ78oVH4R11Wi4OnpyRtvvCFmEVwHmseoIKHZSi09xeqzC9CbK5Ahp2NAL3oFD8JF5c6H2v9DL9U+Yv5KVJjKydFlkF+ZRWFlLkX6PEoNhegtlQ16nfqQIcNF5YarygMXiwJZ8kGcTUW4hAUR3How4b0fQa3xatKYPNQ+tFf70Na9LSbXPArKzpFekUqGKYcsqQi9pZLTxQmcLrYlbq5yDWHOYYS5tyTCpx3eLkH/6kvXrCvGeH5kvz77FIasUxjzztgKCv0LCnc/NOHxaFp0wSX6BtRBscjkDdvCIXfS4Na6L26t+wJg0ZejzziBIeskhpzTGPPOYCxIw2rQYS7Jto09OLPvHydR4uQfiXNIG5zD26OJ6ow6MKbBY20uDAYDarWo6XA9EC0DQq0S8vewIW0pEhL+mhCGtxiHv0uIffvgwYPx9vZmyZIlV3yNSrOO1NJTpJUl1dgMfjG1QoObyuP8tEM3nM9PNXRSOKOSO9nrDMhlcuTI4fyXnnS+CqFVsmKRzJitJlv9AIsRo9WA0aJHb6nEYK6k0qyj0qyjwqyjPsWN3FSe+DgH4KsJxE8TjL8mGD9N0BUXG/onyWrBkJuC/twR9JmJGHKTMRWcw1JRUm1fq0xGqbc7+QG+FPp7U+zrhVVR9UtKrTfiozXiq5fhZ9XgK/fA1dn7fD0AZ1CcH39gMWE1VmDRlWIuL8BUnIWpKL3Wuf8ylTNO/i1w8otA5R2K0t0Phas3cmdXZAoVyGS26Y+GCiy6YsylubbWhPyzGPNTq02BVLh649KqJ65xN+Ia0wulm09DvJyXJEkSFm0hxsJ0Ww2IonTbvwvOYcxPxWrQVjtG4eaDa2wf3NsPxjWmFzLltTOGQ6VS8fnnnzNp0iRHhyI0MpEMCDVKLDzEmrO25v/2ft0ZGHFbtel/o0aNQiaT8dtvv13WuU0WA6eKj5JYeID08pR/lAiW4ePsT4BLKH6aIHycA/BS++Gp9m7SUfRWyUqlWUtByk7O/fk5FWoF5pBorLFdKDeXU2woQG+uqPFYGXJ8NYEEuYYT7BpBiFsUvs4B9R5QadGXo03chi5xK7rkv7BWltW4n1ztisLVx1Zl0EnzdwEhqxXJYsRoNlDgbCHfTUmBp4YSb49qyQGAWm/ArUyHq64CF20lzpUGnPUG1HojKqMJlcmM3GrlQnuCyjsUdXAM6uDWtlkSwbGovEKu+O7YaqxEn3XSNlXw7AEqzh5EMl702spkOIe1xzXuRtzibkQd0sYhd+KSJGEuzcWQk4Q+4ziVaUeoPHcEyfh3q5XC1RvPbrfh3XvcVT+lUZIkFAoF//d//8fjjz/u6HCERiaSAaGawso85p/4H2bJTOeAGxkQPrrGpuV7772X7OxsNm/eXK/zVporOJCzlcP5uzBc1OzvrwkmyrM14e4tCXGLQt1Mps5VnD1IxtxJSCY9bm37E3zPh8gUKpYtW8aaNWsYc8etdOvbiSJ9HgWVOeRXZFNQmU2Fufrdo7PChTD3aMLdWxHpEYOPc0CV11SyWqlI/ouSfb+iS9xapdld5uSCJqIDzmFtUQfH2aYneoeicK7/VE3JasVYUUx28Umyys6Sa8ihwFJMGQaoR6+BDFDKVCjkKhRyBbKLqzois603ABf9W2ar/iiTo5ApUMiU51tubGM1VHL1+UJSzjgrXNAoXXFRueGicsdFpsGcmYguaSe6UzsxZJ+qEovCzRfXmF62VoNWPRt1vIbVauWzzz4jKSmJp556ivj4+CrbJbOJyrTDlJ/YRPnR9Vi0hbbXS6HCs/sd+A58HKWrd6PF15h0Oh1ubm4sWLCAe++919HhCI1MJANCNUuTviGtLIlIj1huj3m01jvap59+mm3btnH06NE6zydJEkfzd7M9c609CfBU+9Le9wZa+3bGS/3vS8lKkoTBUkmFWYveXInRYsBsNZ5fsMjWBG0bRGj7YrIvPqTU4KxwQa1wrvLlXJl+jIzvJmI1aHGN7UPI/Z8iU6h44YUX+Oyzz/Dz80Ov11NcXIxSqawSh9ZURo4unVxdOlm6VLJ15zBbq/apezh508KzDdFusXgmn6B0xwJMBWn27U4B0bi1uxm3uBtxDmvfaEV/jBYDRfpcivT5lOgLKDUWUW4sQWcqp8KkxWCprLa4U1NwVmhwc/LCw8kLd5kGdXERTplnUJ4+gqakCIX1fEwyGeqQNri26oFL9A1oIjs12GwOgJkzZ/Lss8/i4+NDRUUFv/32G4MHD65xX8liRntyG8U7fqIy9RAAco0HASNewKNrzQl1c5aXl0dgYCArVqxg9OjRjg5HaGRiAKFQRa4ug7SyJOQyBYMib6+zaTsoKIicnJw6z2ew6FlzZgFnShMB8NME0ztkCC292l3RFDhJslKozyNHl05BZTZFlXmUGAopNxZjvsx1Ay4mlylwUbrhpvLAxSKHxL/QhHnj7dYO/5Gvg0LJ119/zWeffcasWbOIjIxk5MiRZGdnEx4ebj+PTCbD3ckTdydPYrzbA3+XZz53fgZApvYMZcZijuTv4kj+LpQWE0GRroQ5hxIdfhPe3cagDo5rki8PJ4WaINcIglwjatwuSVaMViMmi+Gi2Rr/XAkSOJ8y2O4tJNs4DSTMxgpMFcWYDOWYTJWYLHpMVjNmmQWjTMIot2KQWdBjpsKspcJUjlkyo7dUoq+s/LuYlQwIk0NYZ2TIcDPLcS0rxzU/D/fSIjwO/4Lbth+Qy+Q4h7TGOaIDmvB4nEPbovINRyZXXNHrc+LECTp06MCePXsYM2YM99xzDwkJCQQHB1fbV6ZQ4t7uZtzb3YwueQ/5qz/BkJNEzrLpaE9uI+j26Sg0HlcUhyPk59sWofLxaZrxGoJjiWRAqCKp2HaXH+MVf8k79vDwcPLz89HpdLi6ulbbbrTo+eXU/5FbkYFSpuSmsFvoFNDnspMAk8VISukJkouPkVaeVGtfPYCTXI2z0uX8oELV+SWJbdeTkLDYFyEy2QcOmq0mrJLFtrbAhal60cGA7QN/x8lPkaMgwyuHt35+jh4D2nN423FUaiV+fpcuWqOQKwh2iyTYLZIewQMpSd7FiZ1fkakxkxvij8FZTUZUCBlRISSoDLS1JhNv8MXb2b/O80pWC8b8VIx5Z2yLHZUXYDVobSWGZTLkSrVtYSIX7ypLAyvd/evd5y6TyW3TLuvourEaKzHmn8WQdxZj/llMBWn2AXhWfTkywOn8T52vk5sPSu9Q8A/D7B+K0ccfvYcHWqWVUkMRpYZCig0FGC16ypUWyn1cwCfq71itVtzLdHiWlOORux2vk6vxKNGiVDjZBjf6R6LyCbMtj+wRiMLDVmpZ4eJV6+vh7u6OTqfD2dmZBQsW0LZtW5555plLFuFxbdUDl6cXUrTjJwo2zEJ7fBPn8s4Q+uCXOPmEXeKVaB6OHz8OQGxsrIMjEZqC6CYQqrjQRTA48k46+Peoc9/du3fTu3dv9u/fT9euXatskySJVWd+Iqn4KBqlK2NjHiXINbyWM9Ws3FjKvpzNHC/cX2XRH6VcRaBLGIEuYfhqAvFS++Gh9sZN5XFFaxyYrSZ0pnJyDywl++AyKp1VmEKisbbqSImphBJ9fo2tDlaLlWD3CELdWhDu3pIw95Y4K2tfyMVSUUreqo8oO7QKALnGE++bH6WifXeSSo9xqvhIlUQnwj2GroE30cKztb2FxlJZhvb4JspPbKbyzIEaR7dfikzpZPtC9A5F6R2CyjMQpYc/CldvFBpP5GpX24h4ucI2GNFsxGrQYaksxXJ+ZUFTSRamwgyMhecwl+bWfT2VMwoXr/MzC5yQyeVIFjOS2YBFr8WiK6lzZUS5xhNNeHucIzqiieyEJaQFJeZSivS5FFTmUlBpG6thqGFhKJnVinupFu+iUryLyvAqKsVVW1F1mIRcYat94OZ7UdIUipNfJAvX7uCltz+iXGt7nRctWsQ999zDunXrGDp0aL1eb33GcTLnv4i5NAeFmy/hj81BHRBdr2Md6bnnnmPVqlUkJyc7OhShCYhkQKjipxOfkleRydiYR2jh2abOfQ0GA97e3rz55pu89tprVballp5i2ek5yGVyxsU9RbBbZL1jkCQr+3O3sitrvb2v3dPJhzifTkR7tSXIJRxFDc2+ZqvZ/sVQrC+gzFhMhUmL3lJhX37YKtlGxctlir8LD6FClpWCIvccznoDvgHtiOw7EW/XIJwUarZs3cId48fw4awZtL6hFXkVmZzMTEDlWvVuUoaMYNdIWni2pqVXu/MlmW1fO7qkXWQvfRNLeQHIZHj1uAu/IU9VaTa2WM2cKU0koWAPZ0tPcWFqo49zAF08uxJwYDflB1chmf7+0pM5aVAHtkLlE2b7Qnd2B4XStiSxSY9FX45FW4y5PN++TDJWS73/X9SXwtUbp4BonPyjcPKLsk0x9AlF6Rl0yYGOkiTZljAuzcVUlImxIA1j3hkMOUkY8s5UW8pZplDhHNnRNogwtg/q4DgAyozF5FVkkVeRQW5FBjm69GrlnAGczBI+ZZX45BfhlZ2NZ3HZ32MQalBSaSaoY3882/XHtc0ABo0cS15eHkeOHKn3Et7msjwy5j6NIScJhZsvEU98j5Nf/f8mHKFTp060b9+e+fPnOzoUoQmIZECoYmHiF2Tr0hjVcgKx3h0uuf/dd9/NiRMnOHr0aJU+7t+S53G6JIHOATdyc8SYel/fYjWz+swCe7XDENcoeoUMJtIjpsbxCzpTOSeLDpFScpwsbRqWfzFuoCbuKi9OHkihJEPLa0+/Qah7FK4qD2677TZwtjDjy7fJ1J7hXFkyxYb8Ksd6qf2I9Yon6GQi1k22D1SngGiCbp+OJqLu17bUUMjhvF0czf8Lo9UAgIuugpjEs0RXavDsOBzXONsX4eX0h0sWM6bSHNsc+uJMW/dCWT7msnwsumKs+nKsBh2S2YgkWZHJ5OcrB7og13igdPP5++7ZJ8xema+xRvRbzUaMOacvWqXwAOayqq+z0sMf19Z9cWs7AJeW3e0VAiVJotxYYl/rIVuXRq4uo9p7RCFTEKDyJ0jyIMCoxLekAoqyMeSfpTIrCfnF+8uVWMK6ccc7P3H/5GlMmTKl3s/Foish/dvHMeQkofINJ+LJH5vtTIPjx4/Tvn17fvnlF+644w5HhyM0AZEMCFWsObOQxKKD9AoeTO/QSzeD/vHHHwwbNoyNGzdy88032x//+vB0Ksxa7mn9DCGX0SrwZ9oyjuTvRiFTcnPEGOL9etQ4kE5nKmNn5h8cL9yPVfr7TtdZ6UKAJhQfZ3881D7nCxS5oJI72wsSSZKEoSSLgl3zKc8+gUmlwuobhCK+HxVOCsqNxXXWEfBS+3J8VzLl54zMfPv/0Cht4yXKDEWcLTvFmZITnCs7XaVrwbO4jDiCueGmF3B29qzXa2E1VpL280ucsGZwNiYCg7OtEpyvcyD9w28lyjOu3q9rU5OsVtvdfnkBFl0RlopSrJXlWI0VSGYDklWyTU1UOiF3dkPh4mUrUewThsLVu9bBk/ZlopP/Qnd6FxUpe6vM85er3XBt0xf3+MG4xvapVjrYYjWTV5FJpvYsmdpUsrSp1aaCymVyAl1sVRsLkop597Gn+OWjaSgyD2LISjwfByxLKGbgaz/Q86YB9X5dzOWFpH11H+aSbDRRXQh/dLatKFMz88QTT/D777+Tmppa79YP4eomkgGhiqP5f7EhbSkBLqHc3/b5S+4vSRI33HADGo2Gbdu22T/EPz3wClbJyuMdpuHu5FWvaxdUZjPv+CcA3NbqYaK92ta4X0Z5Cr+l/GhvAg5yDaeNTxeiPOPwVtdd496i11K0+VuKdy6wzeVXKPHt+xA+Ax5FrqpadnXZb7/wyvQXeOz5h+h8U3tydOcoqMzl4sqEMmSEuEUR4xVPrE8H+3Ot1BZw4PdXSXU1kxfki3R+gJqTXE07vxvoGngTnnUM0JQkicwfn0V3chsylTO+t75MSqg3+3I220szt/Rqx4Dw0Xiqm260tyRJtvED2kLM5QW2n7I8zKV5mMvyMJXmnP93fp3jAOqicPFCHRKHJrIzLq16oInoUGvrh9VkoPLsAcpPbEZ7YguW8r9bDeTObri1uxmPTiNwib6hxnNcWAwqo/wMmVrbYlBlxqpVFi1mK75OQcQGtCfIpEa95w8qj6wHIKPMTPRjs2nRqU+9n58hN4VzXz+A1aDFu/e9BIx6pd7HNoWMjAxiYmKYOnUq06ZNc3Q4QhMRyYBQRYVJxzdH38EiWbg77inC3Ftc8ph169YxfPhwfv75Z8aNGwf83TIwvs3kWqet/dOuzD/Ynb2BVl7tGd3qwRr3KdLnMf/EZ5isRvw1IdwccVu9YpSsFkoPrKRg/ZdYtLaSxy4xvQgc9SpO/lHV9l+5ciV33XUXo0eP5ueff0ahsH2RGMyVZGrP8n+LZqIJleMRfPGcdhkR7i1p59MFzYrZGM8cQOHihc+EjzmrruBIwW6K9fnn95TTxrczPYMH1ThroOzwGrIXv45MqSbskf/DJaozAHpzBX9l/8mhvB1YJStKuYobQ4bTOfDGes3SkCwmzNoiLNoiLJVlWA0624+xEslYidVYidVUidVQ8fc2vfb8nX0pFl1J/dchkMlQuHihcPOx/VfjjszJBblSDXI5SFYkk21wollXdD6JyK22eJDC3R/PrqPw6nk3Ks/A2p+b1Yo+/SjlCRsoT9iAuSzPvk3pEYBH55F4dht9yb76UkMRGeVnSC9PIbngOAZZ1RYihUxBoMIX95NH8U1PR5Zdgv99X9CyS9/6vS5A+YnNZP1kS7aD73oPj8631PvYxvbwww/z+++/k5KSgofH1TMVUvh3RDIgVLMhdSlHC/4i3L0ld8ZOrNd89zvuuIPt27dz8uRJvL29WX76O86UJta7uwFg3dnFHC/cx42hw+kRPLDGfVafWcDJokOEu7fktphHUdVj9oA+4zg5K97DkHkCAJVvBAG3vIRr65uqPTer1cqHH37I1KlTGTt2LAsWLKixmXTixIns3buXLbv/JLnkOEnFR8nUnrVvdzIYiUrL48a+U/AO6wjY7kLTypLYn7uVtLIkwJYUxPt3p3fIUFxV7vbj07+bSEXyX/gOmoTfwOqlYAsqc9iY9isZ2jMABLtGMqLFPXg5/z3VUZIk9OkJ6JJ2UnkuAWP+WcylOTWv1HeZZE4alO5+KN39UXoEoPQMsDXzewah9Ay0Pebue9lN4FaTHmPeGfQZx6lI2Yfu9C6selszvkypxnfg4/j0ffCS4yQkq5XKtEOUHV5LecIGrJV/r+7oGtsHnwGP2hOsuuzdu5dhowexcM0PSF6GGleKVJrMuGYX4u57I4N7jK33SpEF62dRuHkOMicNkZN+Qh3Y6pLHNLa9e/fSs2dPZs6cydNPP+3ocIQmJJIBoZoyQxFzj32IWTIzJOou4v26X/KYrKws2rZty+jRo5k3bx6JhQdZc3YhGqUrj8RPqVeJ4a3pq9ifu4V4vx4Mibqzxn1mH3kHramsXq0WVrORgg2zKN7+E0hW5Go3fAc9gXfPcTUuJpOVlcUTTzzBqlWreP3113nnnXfsLQL/9Oabb/Ldd9+RmZlpf6zUUMTxgv0cOrsKvbMtgVDKVXTy70P34AH2sQUAObp0dmX9wdnSkwA4KZzpEzLUXofh7P9uw5h/lrBHv8G1Zc2vvyRZSSjYy9aMVRgtelRyJwZG3EZb325UnN5N3uqPMeadqX6gXGmbRujigVztavtx0iBXaZCpXWz/dtLYBg06u6HQuCN3dkfh4mm7w3f1Ru5U+xTKhiSZTWhPbado+zz0aUcA8Og8kqA7/1PvokxWsxHdye2U7vsV3eld9mTIo/NIAm+bZlugqRYJCQl06NCBXbt20atXLyRJosRQwLmy06SVnya9LLnaipruKi9aeLYmyjOOCI+YWt/7ktVCxvdPUpGyF5VPOJFPL3BoUSKTyUS3bt1QKpXs2bOnSmVN4donkgGhRnuzN7E9cw1KuYr72jyPr+bSi6788MMPPPTQQ6xYsYKRo0Yy7/jHFBvy6ejfm0GRYy95/IXpiGqFM4/Ev45GWb2s7DdH36XcWMKdsROJ8Kj9TspUkkPmT8/bB3y5dxpBwIgXUbpX76eXJIkffviB559/HrVazXfffcfIkSPrjHX69Ol88803ZGVlVXncatBx6u0byQnxJ7P/MHL1tu1qhYY+oUPp6N+7SnN+RnkKW9J/J7ciA7CNfxgWNY7Kxe+iO7Udn/6P4D/0mTpjKTMUsfbsInsrQUurHzG/LUFpsSJz0uAWdxOaFl1RB8fi5BthG6B3lS25K0kSZQdWkrP8XbCaCXvoK1xje1/2eYwF5yjaNpfS/StAkvDoeivBd7xT6/4FBQX4+/uzdOlSbr/99mrbrZKV9JRNHNv+BfmBvuR5e6JQ/Z1AymVyQt1aEO3Zhmivtvg4V/07MuuKOTdrPKbiLFxj+xA64fNGKz19KdOmTeP9999n7969dOnSxSExCI5zdX0iCE2mW1B/ItxbYbaaWJk8lwpT9fna//TAAw8watQoHnvsMbIysxh4PgE4kr+LxMKDlzw+0iMGP00wBoueTeeWU1OeGuFuSwAO5m2vcTuAMT+Nc19PwJCViMLFi9D7PyPk7hk1JgKJiYkMHDiQhx9+mNGjR5OYmHjJRAAgOTmZsLDqleRkTi6ofcIIycxjwNFsxrS4//xzqmTTuRUsOjmLIv3fg9zC3Fsyvs1kBkXejpPCmRxdOvNPfEpmpy5IYKtzn36szlg81D7cGTeRPiHDkCEjRV7AzgHdkfW+jZZT1hNy74d497obl6jOtqb7qywRAFuZZ89uY3Bvb+s+qkxPuKLzOPlFEDT2LQJutU0J1B6ve5EtX19fvL292bdvX43b5TI5ka0G0ckphl7bDzL8JOycncj2RQcxltrKNqeXp7A1YxVzj33I9wkfsDV9FZnlZ5EkK0pXb0LGf4JM5YwuaSe5v39Q6/u6Mf3666+89957vPvuuyIRuE5dfZ8KQpOQy+SMiB6Pu5MXxYZ8lid/i9FiqPMYmUzGt99+i4uLCyNHjsRHFsQNQbZpV+tSF9ubxGs/Xs7gyNuRIedk0SF2Z62vtk+3oP7IZXJSSo6zL2dLte1mXTHp30/EXJaHU0A0kU8vxK1t/2r7lZeX8+qrr9KhQwfS09NZt24d8+bNu2Qd9pycHL744guWLFnCkCFDsFqt6HR/J0oymYzAW6eAXIk2YQOy76Yw2tiagWFjcFI4k61LY/6JT0kqOlLleXf078WD7V4m0iMWs2Rmh/k4xwfejNlqJnPeMxhyTtcZl1wmp2fIIEY69UBdaaDc040/Qk2c1Z+r87iriT4zEd2pnQBXXMHPaqykeNfPFKz/EgDnsHY17idJEpJkm/740EMP8dlnnzFjxgyOHTtW45e1d6+7bedLP8gvX69gcIvbeX/sd3zz6HJcsoKIcI9BLlNQbMhnf+4WFp2axeyj/+HPtGXkuasIvHsGyGSU7vmFoi3fXtFzu1IbNmxg3LhxjBs3jldeaV4zG4SmI7oJhDoVVuay6OQs9JYKQtyiGBvz6CX7/48fP07v3r3p0qULq1avYlP2ryQVH0EhUzCixb3E+nSs8/hDeTvZdG45AN0C+9M3bESVgkMHc7ezOX0lAD2DB9E7ZIh9e+aCl9Ae+9NW1GXiPJRuVb/cJUli/vz5vPLKK5SUlPD666/z8ssv4+xc/TlJkkRCQgKLFi1i27ZtJCUlkZ+fj0wmw8fHBw8PD7Kzs9Hr9Xh5eREYGEjbtm0ZP348A9sGUbjyHXupXpVPGKret7PTW0tmhW11wr5hI7khqP8/rmmrvrg9Yy0SVnzKjXTbshtnuTOhD8y85KA3beI2Uha/xKGbbqDQ09av3ztkCD2DB9W56FRzJllMFO9eRMEfXyKZDbb5+Y/NuaxiS4acZEr3r6D04O/2wYTq0LaETfgMpUcA6enp/PDDD/z2229kZmaSl5eHxWJBLpejUChQqVTo9XqsVitubm506tSJ4cOHc8cddxATEwNWC6ffuQnJWEnU88tRB7QgOzubF198kZ9//pk+ffow6/++wDlERnLJcc6WJlYpn+yqciey0hmfbavxLC4jaMxUvHrUPG6mIe3cuZOhQ4fSt29fVq5ciUrV/GoeCE1DJAPCJeXozrE06RsMFj1BLuHcFvMwLheNfK/Jzp07GTJkCP369WPpsl/4M2spp4sTABk3hg6je9DNdQ4A25ezhW0Zthr+UR5xDG9xDy6qv8va7sz8g7+yNwAQ6RHL0Ki7UGancu7/HgS5gsinFuAc0rrKORMSEpg0aRI7duzgrrvu4qOPPiIiouq0x/z8fBYsWMDq1avZv38/JSUl9m0ajYbQ0FBiYmIICQnBx8eHsLAwPD09ycnJIScnh927d7Nnzx58fX2ZPOkJHu4ZhP7AMiwVtvNIahdS+g/gpJutlWVA+Gi6BN5U7fmnlZ3m95QfMVgqca8002PTLjRmGcHj/ot7u5ur7X+BpaKUlBmDsFjNpN8zkQSDrUWhpVc7RrS4B6d6DORsLqwmA2WH11C05XtMRemAbSZA8D3v28ouX4KpOJOyo+spP7IWQ3aS/XGVdyg+/R7Es9sYTpxM4o033mDFihW4uLgwevRoYmJiCAwMRKVSYbFYMJlM5Ofnc/bsWQ4ePEhycjIGw9+tZM7OznTu3JkvBzrhai6pNuhzy5YtTJw4kZSUFF566SXeeOMN1M5OnCs/TVJxAsnFCVUGIbqV6QhLy6JL/H0Ed2u8hGDnzp0MGzaMbt26sWrVqhoXGxOuHyIZEOoltyKTpUmz0Zsr8FL7Mjbm0Uuuqvfnn38ycuRIbrzxRpYuW8r+kk0cyd8F2L6chkTehYuq9g+gxMKDrE9dglky46J0Y2DkWGK84u1JxLGCfWxMW4ZZMuMkV9M210jwjj/x6TKGoNvfsp9Hq9Xy9ttv8+mnn9KqVStmzZrFwIFVpy7u27eP5557jt27d9ubgd3d3Rk6dCgPPvgg3bt3x9+/7ud7wYkTJ5g9ezZz5sxBrVbzxpRXmNAnivK9v9hH9ye1bkFSu5YA3BH7BJEeMdXOU1iZw9KkOWhNpbgbJHpu2IbaaCFo7Jt4dhtT6/VzV7xHyZ5fUPlGoB3/Epuy1mCRzPg4B3BrywfrNRjUkYz5aZQeWEHp/hVYdLYCQAo3H/wGP4Vnt9vqHPNgKs6kPOFPyhM2oM+4aKyFQolb3E14dhuDa9yN5BcU8tprrzFv3jwiIyOZMmUK48aNw9390kmGJElkZ2ezbds2Fi5cyJ49e8jLy2PLpDYEeTgxv7g1L77/f3h5edmP0ev1fPTRR7z33nsEBwfz1VdfMXz4cMBWFTG1LInEooMkFx+zl0uWWa1EKQLpGjOWCPdWDbqk9bp16xg7dizdu3dn1apVuLnVvX6EcO0TyYBQb0X6PH5N+pZSYxHOCg0jW06o8UvsYlu3buXWW28lOjqalStXUqLJYtO55VgkC64qdwZH3knLWioNAuRXZLH6zAIK9bbm9hYerekXfqv9C62wMpc/UpeQrbM1vWt0lfQMGUTHlqOQyxQsW7aM5557jsLCQt544w1eeumlKnUDdu/ezSOPPEJiom3WQUxMDC+++CIjR44kNDT0X71e2dnZvPvuu8yePZtWrVrx9Vdf0T3ClZJdP1N+citHO7cmvUUorgYr90c+hGtYfLVzlBoKWXzqa8qNJfgY5HRf+ydKi5XA26bh1b3mmvGWyjJSP78Tc2murSTv2Bf4PXUBWlMZTnI1Q6LuJM6n0796bg3NVJqL9tiflB1Zh/6iwYFKzyC8+9yLV/c7kKurzy4BMBZlUJ6wAe2xP9FnHP97g0yOpkUXPDoOw73dIBSuXkiSxM8//8zkyZMBeOutt3jiiSf+dcndjAN/olv6EkaLRM/PjmFCweTJk3n33XerdEElJyczceJENm7cyJ133slnn31GSEiIfbvBoudU0REOJf1KgfrvMtu+zoF0CexLW98uV7Qy58UWLVrEhAkTGDZsGIsXL0ajaZppokLzJpIB4bLoTGWsSJ5Lji4dGXL6hY+kS0D14j0XS0hIYOTIkRgMBpYsWUJct5asObOAIr2tQlycdyf6h9+Km1PNc6zNVhN7sjeyN2czVsmCDDnt/W6gZ/AgPNTeSJKVfYd/YK/2EAaNraSws8yVhPVnWPDRMgbcOIiZM2cSFRVlP2d+fj4PPPAAa9euBeCmm27iyy+/pEOHSy/OdLku7p6YMmUKM2bMwFiQRu6OH1npm4dBo6bTvuO0C76RgBEvVJvDX6TPZ9HJL6k064jQq4lfvRqZTEbI+E9q7TKoTD9G+pxHkUx63NrdjOft01id9vf0w47+vegXNgqVwjF15yWrFUP2KXRJO9AmbquSACBX4BrTC88bxuLWum+NU+1MJTmUH/2DsqN/2ItJAfYEwD1+CO7tbkbpXrUI08SJE/nmm2+4++67+eKLL+rd2lMXfXYSmT88jbksD/euo1mS4c0bb7yBVqvFw8ODL7/8kvvuu8/+N3IhIXnhhRfQ6XRMmzaN5557DrX673LYktXKyd/f5Lj+NBkRwVhUttfAVeVOt8B+dPTvhUqhrjGe2lgsFmbMmMGbb77J/fffz3fffSfGCAh2IhkQLpvZamJ96i8kFtmmC7b26czgyDtwquPDKS8vj7vuuovt27czbdo0pkx9jT25f3IgdxsSEiq5mh7BA+kaeFOtdz5F+jy2pq/iTKntw18uU9DGpws3BPWj8pf/Upa0ncx+ozik1qJwOZ+cSDJifNrT1rcbLTzikMsUfPzxx0ybNg2j0UjLli1ZsmRJo0+nslqtvP/++0ydOpU9e/bQvbutT3l7yjL2Fu8mJD2HLnuP4RQQTegDX+DkU7VVIlObypJTX2OVLHQt1hC86Xfkaleinl2CyrvmFgxd0i4yf3oOyWxEE92N4Hs/4q/i3ezN2QTYlkYe0eJeAl2rT5FsaFaTAUNOEvpzCVSmHaLizH57F8AFzpEd8YgfinuHIVW+xP8+h57yYxspO7CSijP7/q6kKJPjEt0N9/ghuLUdUOMUUoAvvviCyZMnM2fOHB599NF/9XxspY8TbN0ZB34HqxmngGgiJv6AQuOBwWDgzTff5JNPPsFisdCxY0eWL19OixZ/F8oqKSlh+vTpfPnll0RERDBjxgzuuusu5Oe7QSSLmezFUyhK3ER6TAvOxbdDa7HNXNEoXekZPIiO/r1QyC9dlyA9PZ0HHniALVu28Oabb/LWW281aLeDcPUTyYBwRSRJ4lDeDrak/46EFV/nQG5t9UC1oioXs1gsvPfee7z99tu0a9eO999/ny794tl0bjnZOtsUOHcnL3qHDKWtbxfksppHi2eUn2VX1jrSy1Psj/nnFhKZks7TnxwivdzMKx9NJryHL3n6DPs+TjI1J3acZfvyfZw7ksN/332fSZMmNdmHosViISoqiltvvZVZs2YBkFh4iDVnFxCs9KfH2j8xl+Wj8g4lYtJP1WZCXJhloZApGJhQgNOpA7i1H0To+I9rvabu9G4y57+IZKxA5R1K0F3vkuftwrrUxehMZciQ0y2oH72CB//rVgKrQYe5LN+2RHJxFqaiDIwF5zDmncFYkAZWS5X9ZU4aXFp2x631Tbi17ovSo+b3jqk0l+JdCyndtxxrZZn9cU1UF9w7DsO9/aBqr1VNunXrRmhoKCtXrrzs52UqzsJYmI4xLwV9ZiKVaYfta1wAuLXtT9DY6dWWcs7MzOSuu+5i165dyOVyPvjgA1588cUq77kTJ04wZcoUfvvtN7p27cqMGTMYPHgwMpkMq9lIxtxJVJ7Zj9w7hIrxL7Ov6C9KDYWAbZns/uGjaOlV8xRJvV7P119/zZtvvomHhwcLFiygf//+l/X8heuDSAaEfyWj/AyrzsxHZypDJVczrMXdxHrX3dS+b98+XnrpJbZt20bHjh15ctKT3HBLe/YVbLLXffdW+9MzZBCtfTrVmhRkaVPZemYNWYYUOP/haqmATkG96BZxEz7OAeRXZHG8cD8Jufsw8veIbYVMQZh7SyI9Yohwj8HfJaReC/38Wy+88AKLFy8mIyMDmUzGhrSlHM3/i3a+3RjkezPnZj+MqSgD9w5DCbnngyrHSpLEiuTvOVOaSKAqgG6LFiKTyWj52h+1fpECGHJOk/njs5iKs0Amw73jcDS972Cn8Tinis+X+HXypn/4rbTyal+lOdtq0GIpL8KsLTi/UmGR7b8622JHZm2h7b/lBUgmfa0xAChcvXEObYsmqhOaFt3QhLWvsSz0BRZdCQUb/4+SvUvBYhtUp/QKxrPbGDy7jKy1RaQmR48epWPHjqxYsYLRo0cjWS1YdMWYy/JtyyxrC+0LONmea5F9RcYLayP8k8zJBbc2/fDqedclp3wuX76c8ePHU1lZyZgxY1i8eHG1cQrbt2/n1VdfZffu3dxwww08++yzjB07FidMpM0aj6kwHdc2/Qi67xNOFO5nV9Yf6EzlALTyas/AiNtwc7Itj52amsq3337L7NmzKSws5Mknn+S9996rMqhREC4mkgHhX9May1h9Zr69P/qGoP7cGDqizi9XSZLYsGEDs2bNso9mvv+B+7jx7i4UuqSht9hWivNU+9ItsC/tfG9ApXBCkiROnjzJ2rVrWb58Oe4Fx3h3fGtSo8PIio3BgNF+jUCXMOJ8OmHIkDHwxiGEtQvgyWkP4dlSXW2ZWieFMyGukQS7RRLkEk6ga1iVhYMayu+//86tt97K8ePHqPDJZ+v56ZN3xU4k3KMV+qyTpH0xDmr5ki83lvLD8Y8wWvR0PlNC6KH9hNz7Ie7xQ+q8rkVfTt6qjyg78Jv9MYWbD/mtYjkc4UbF+e9kP62F9qlFeOXmYdEWIpmNtZyxZnK1G0rPAFRewai8Q1D5ReDk3wJ1UAxKj4B6t8JoE7eRs+wte1eCpkVXfG6agGvcjZdVX8Bq0KHPPMGyOf8j88Re7rllAJaSLEyleZe1xLJc44GTbzhOflGog2NxjuiAc1g75Mr6t6ZkZGTQr18/zpw5w/Dhw1l9fuzHxSRJYv369Xz44Yds2rQJT09PRo8ezb3D+hB1fA5YTATd+S6eXUZitBj4K/tPDuRuxSpZcZI7o0zxZfGslWzduhV3d3cefPBBnn76aWJjY+sdp3B9EsmA0CCskoVtGas5kLsNgGjPNtwSPb5e89rT0tL45ptvmDdvHpmZmXj6eDD2maG0HhSOwtn2YWk1SGQdKGXd99s4eeQ0arWa24f14/V2JSitBnxvfhyvgY+TUnKc44X7SC1NQsJqv0bGyVxifeIZ2+9e/DUhFBvySS07xbmy02Roz2K0VL+rdVW546cJxtc5EB9nf7yd/fFU++Lu5Flra0VdJEkityyTB1+8hwH39EBpu4mja2Bf+offat8vdeZdGLKTCLn/U9zbDqh2ngtFl5wsEv3XbCP8lldrnVnwT/rMExRtnYv25Hb7nbxZISc5rgVnYiOwnl+YyT+ngJiTZ/EpLEWudkXh5oPSzReFux9KV2/bssRuvrbH3HzOr2Do1yALGJXuX0HOr2+DJOEU2IqAUa/UulhTTYyF6ZQdXoPu1A7b7ALJWvOOMvnfsZ9/Hrbn6YfSzQeFu69t9UWPABTODTP1rqKigs6dO5OUlMTLL7/Mhx9+WOu+ycnJ/PjjjyxdupTExEQe7xXAC/2CKTcrWakciJOLG0ajkeyydPxvcsIvyjYA98zWPHoEDGLsbWPFlEGh3kQyIDSok0WH+ePsIsySmUCXMG6PfbzGBYdqYrVaOXz4MJs3b2bfvn2cOHWc4M6e3DCmLd4htg86yQoeRn/6xQ7DeeUX6M/sxzmsPRET51ZZLrfCpOVw5m5+/nMuEfFByBV/t1K4qjyI8ogl0iOOCI9WaJSu5Fdmk61NJVt3jhxd+vn1A2r+05Ahw1XlgZvKAxeVGxqlK2qFBpXCCaVMdb7Sn4TZasJoMVBp1lFmLKZQn4veXGE/j5Pcmb5hI+jg36vKHWL6t09QkbKn1nXurZKF+Sc+I78ym/DULIa3ebTOQkQ1vtYmA4bsU5iKMrBUloPVjE4hcViVS5KUg3T+uQe7RNAtuD+tvNpdUQJ0uQy5KaR+cTdYzHh2v4PAUa/W2ZVQ5dicZArWf4k2cUuVx01OHmw5lk6/0eOJaN/DVg3SKxilu59DFgUqLi4mNjaWgoICZs2axaRJky55TFJSEru2b6XdqTl4KIx8sb+SZcfKUCqVRERE0L5De9qPjMQYaBvHEOvdgREt7q3X4EJBAJEMCI0gW3uO5cnfUWnWEegSxt1xT172NKiLWSUrKSXHOZi73d4VAeCirSA8I59eg6bjG1R1AJVer6dNmzakpqby7gfvcOvDQzlTcoK0siRM1qpN336aIMLdWxHmHk2YWwtcVO4YLQYKKnMoqMyhSJ9LsT6fYn0BpcYirFLVgXCXQyFT4q0MYN5HS4hwjuWHb3+sts/Zz+/EmHOasAdn4RrXp8bzpBedYMmZ7wEYGTyGuNAbrzimfyoxFLI3exMnCvdjOf9c3Z286Ojfi/Z+N+Cqarxldi8UTHKNu4nQB2bWu1uheNci8tZ8bBtbIJPh0qon7vFDcI7uTo+bR+Dl5cWWLVuazQj6jIwM2rZtS3l5OV999RVPPvlkvY4r3rmQvFUfog6OJWrykmrbEwsP8UfqIiyShVjvDoyMvu+qLUMtNC2RDAiNorAyh8WnvqbSrKOjfy8GRVZf/vVKFFRmczhnB8dzdmG2LxUrI8K9Fe38utHKqz26MltTbFpaGk8++SRfffWV/Xiz1Uym9gyppUmklSWRX5lV7Rrean9C3KLO/0Ti6xxg/0CVJCs6k5ZyYwk6UxkVZh2VZh1Gix6j1YDFarbfVStlSlQKNRqlK+5Onnir/fHVBKGUK/npp5+YMGECy5cvZ8yYMfZrS1Yrp6f3RjLpafHiSpz8Imt8HbQnt7Ph4EzOxEbiJFdzR+wTBLtF1LjvldIayzicv5Mj+bvtLRpymZyWnu1o79edKM/YBm8tSP3iHgxZiYTc9796t3YUbvmOgj++AMCtTX/8hj2LOsA2hW/27NlMnDiR3bt307NnzwaN9d86d+4c8fHxlJWVcf/99/PDDz/YpxXWxlJRSvJ7N4PVQvSra1F5BVfbJ7X0FMuTv8cqWegdMoReIXWPJxEEEMmA0IjOlZ3ml6TZyGVyJnacXu/ugkspO/oHGUumkBsTS16Pm8jQnrVvk0sKjmw6xd5VCfRpezNzZs+p81wVJi0Z5Smkl6eQoT1LQWV2tX2cFM4Eu0YQ7BpBkGs4wa4Rl1yb4VIkSeK2225j+/btnDhxgsDAQADM5QWkzBgEMjmx/9lTpevjYoWbvyVvwyz2Dx9EnkZCKVcxKGIsbX27Nfjdr9lq4lTRYY7k/2Wv9Ai27pY2Pl1o59cVP031L6UrkfL+UMyluURMmo8mvP0l99ee3E7mvGcA8Bv6DD79HrY//4yMDNq3b8/tt9/Od9991yDxNbTi4mJ69uxJUlISAQEBrF279pI1L9K+vBd95glC7v0I9/jBNe5zvGAf61IXI0PO/W2fx9+lYf7/CNcu0aEkNJpQt2hUcjUmq4EyY3GDJQMVZ/ajsFhp59+dAa2fotRQyPGCA+xM/hNcLcQPbEX8wFY4K1xYn/oLrX06E+YeXePsBheVG7E+He0rKVaaK8jSptp/cirSMVr0pJXZWhIu8HDyJsg1gmDXcIJcIwlyDbusMrEXlnsODw9n3rx59qVjLZW2qWJytWutiQDYZgfIJYmbywPYHehJWlkS61IXk1Cwl14hg4lwj2mQpECSJCx5qYSeO4dftpb8CgMpbmbO+Tmjo4z9uVvYn7sFP4U37YJ609q3a62VJC/FajZi1trmz9dWOOhiFl0JOctsa1B49bwb3/6PVNn+yiuv4Orqyscf116HwdG8vb05deoUb7zxBjNmzKBbt2588cUXPPXUU7Ueo/KLQJ95AlNpTq37tPO7gZSSE5wuSWBPzkZGRt/XGOEL1xCRDAiNotRQxJ9pyzBZDTgrXOosRnS5Lkw3U3nZarp7qn35ZupC5s2bR9serfjPN1PJtaZRYS4noWAPCQV7cFV5EOfdkdY+nQlyDa/1i1KjdKGlV1v7eglWyUJBZQ7ZunNka8+RrUujSJ9PmbGYMmMxSefn6VvMVpR6DR0iutLCJ45Qt2iclXWPrPfz82PMmDH89NNP9mRArrJNVZPMBiSrtdZFeVTnpxxas04zdvj/sS9nM39l/0mm9ixLk77BxzmAdr7diPPphKf60gV5LiZZLVSc2Uf50fVoT27DUl7w93WB1kCsTEZesB/pEcHkBftRQDFbM1ezLWM1Ya6RtAvoSSvv+Esud32x8iNrwWJG6eGP0jPokvvn/v4BFm0RToEt8b/lxSrbSktLWbp0Ke+//z7e3t71ur7FYmHFihWsW7eOI0eO4Ofnx2OPPcbQoUNxcWmYRLY2//nPfxg/fjw9e/bk6aefxtnZmUceeaTmnS8ktdZaZkmc1yN4IKdLEkgpOY7FahaDCYU6iXeH0KDyKjI5mLuDxKKDWCULSpmS4S3GofqXi6tc7EK1uQvL2n722WfMmzePqKgotq3+C19fX6ySlfTyFE4WHSK5OAGdqYyDeds5mLcdL7UfbXy70M63K55q2x2oJEkkJiZisVjw9/cnMDAQmUyGXKYgwCWUAJdQYt06cfDgQZb/9ivbDm/EPURN1/4d8G/picJZjuRm4EjRLo4U7UKGjGC3SKI92xLr3QFv5+rldQH69u3LokWLsFgsKBQKlB6ByFTOSCY9htzTOAfH1Xica5t+sPoTKlL2oju+iR7tB9HWtyv7crZwrGAvRfo8tmeuYXvmGvw1IUR7tSHKI45g10gUtczTNxaco/TACsoO/o65LN/+uEzljCaiI86hbVD5hp8fha8izFhJfHEWpanHSa5MIT3Ik2JfL9Ir0khPTUOZtpSW3vG09elCpEdcrdcFW+nk3N9sRZa8et97yVaN0gO/2ZIHmZygsdOrzffft28fJpPJvjJgXaxWK8uWLWP69OmcOHGCNm3a0LNnT44fP87YsWNxdnZmwIAB3HLLLdxyyy1V1rgA22DVU6dOkZ2djU6nY8CAAfj4XF4CBtC6dWvOnDlDVFQUjz32GLGxsdx0U/XlrU2FtqqaSo+611UIcAlFJXfCZDVSaizG5xKrjArXNzFmQPjXautTjnCPYUDEaPw0l77LuxzlxzaSteBFFG4+eD/yEwGhEbi6unL27Fl8fas3L9uWiD3FyaLDJJccw2w1XRRjK1q5deT9Fz9lyeJf7I+7ubkRHByMl5cXJpOJ8vJy0tLSMJvNBAQEcPfddzNx4kTatm2LJEmUGos4cnYfmw6sw6Apxz+i6t1oqFsLugb2rVLhr7y8nFtvvZXMzEySkv7ugsj86Tm0J7bg1fNuAkdPqfV1yFv1McU754Ncif+wyXj3vheZQmlf+e5k0UEyys/YBzQCOMnV9sqL4e4t8VF6oTuxhdL9K6hI2WvfT67xQB7dmzLvNmRZPMkvKkGSJNzd3fHw8MDDwwNvb28iIiLQaDRIFhPaxK2k71vEGXkhGRFB6Nz/Xp7aWe5Ma9/OtPPrTqBLGDKZDEtlGZVnD1J6YAXaE1sAcGnZg7CHvqyzi6TyXALp3z6GZNLjO2gSfgMfr7bP7t276d27N//973955ZVXahyYZzQa+e2333jnnXdISEhg2LBhvP322/Z1IyRJ4tSpU6xevZrVq1ezfft2zGYzgYGBtGnTBrVaTVZWFidOnMBi+XuGiUqlYt68edxzzz21Poe6nDhxgvbt2xMQEEB2dnaVxMhUks2ZD28ByUr0K2tQeYfUeh6L1cwXh6ZikSw8Fv86HpfZQiRcX0QyIFwxvbmCQ3k7OJS3k0qzbQEVuUxOjFcHugTeSIhbVKNcV7KYOPvJGEzFmWwr9ubx2VtYvHgxd9111yWPNVoMJJcc43jBfs6VJ3OhlkBZgY4gSzTxvj3Jzy4gJSWF3NxcSkpKUKlUuLm50aJFC7p3707Hjh1RKmtvVCsoKGDOT//HzsRNhHTwoVW3CBRK25eRIVciZ4ue1FPp7N27l7KyMlasWMGQIX+P+Nal7CXj28dBriRy0o84h9a8xLNkMZOzbDplh2xVDFV+kXj3God7h6H21pMKk46zpYmcLTtJWllSlToHAE4GE775RbafvGJy8uUsPpjHkt0pGM11N0NfEBwcTGxsLG3btqVTp050i/TAP38/Wdn7yQwLIDM8EKPz31NL3XUGwjPyCTl9BmfD+WmeMjlePe/Cf9izdRYu0mefIn3O41grS23TDyd8VmtFwmeeeYYvv/ySVq1acdNNNxEcHIxSqaS4uJiUlBR2795NcXExgwYNYvr06fTpU3UapyRJWMrzMeSnYi7JRleYTcqp4+TnZFNQWITeAkqNB4FRcYS37kRgqw6gdmPq1KksXLiQuXPn8sADD9TrNfynO+64g2XLljFv3jwmTJhgfzxr0RTKj6zFpWV3wh/9ps5zXBhE6Kpy54kOb4gphkKdRDIgXDaL1cKhvB38lb0Bw/nKfX/PQ+/eKGV8/6n8xGayfnoei1Xi5c2VrN6bdOmD/qGoooD3vpuKW4wcDz/bXayzQkP34IF0CbjxX/exSpLEiRMnWL91HdmyZHw7OqN0UlCeX8Hh7zMID4rk5ZdfJiKi+pTArIUvU56wAZVPOJGTfqq2AM7F1yjd9ysF67+ssgqgU2BLWwlgz0DkKmckkwFjWS55ugyy5FoK/Twp8vPGoqz6RVpRbIBiJ3wUwYRqWhAR1IKgoCD8/PyQy+VotVrKysooKyujsLCQ1NRUkpOTSUpK4tixY5w8eRKr1YqHhwe3Du7HXd3DiHGrJF/KJSPEh5wQf3uVQ5nVSmCRjtaKcNrG34UmqO6SuRVnD5L547NY9eU4h3cg/JH/Q66uuy9/586d/Pjjj+zfv5/CwkLMZjMeHh60atWKzp07M3bsWDp27Gjf31SSjTZxGxUpe6otRlQfCldvnAJasv1EOos27OPeZ99i3GOTL3swZ15eHkFBQbRo0YKUFNuCXMW7fibv9w9AJifiyXlowuNrPT5Hd45fkr7BaNFzY+gIegRfXlEq4fojkgHhspQZivn9zI/k6Gz99X6aIHoEDyTWu0OTVKi72LZ37yRQd5oyJ3+6TV9/WR+4lZWV3H///axcuZKFPy+gbf9o9uZsokifB9ie14gW9+LvUnsz7OUq0Rew9PQcSg2FdAm4iQERo2vd11JRStqX92AqzsI5PJ7wR2bX+cVn0WspO7iK0oO/Ycg8cclY0kuMbDmrJS+0FaE3dSWotTeVqjIsUtV6/X6aIKI84mjh2ZpQtxaXTJAqKys5fPgwGzduZP369ezevRuz2UynTh159J6xDBvUi2JNMadMqeQY8+zHuak8aO/Xgw7+PXB38qp23tIDv5G7/D9IFhOayE6EPvgFCueGSTqtJj3lR9ZRun8FlWmHq26UyW0VC31CUbr6IHd2Q6ZQIlmtSKZKLJVlmMsKMJVkYynPr/H8OklNYMf+uMX0wiWmFyrPwHrF1blzZw4fPszZs2dxT9tMwbrPAfAb9iy+/R6q+blIFg7n7WJ7xmrM/9/efcdHUacPHP/M9pLdTW+E0AIJECA0QRAQUBEROFQsiGIBC2I57O28s52eBcV2FhSVn6LYUERFRJAmvbcAIb3X7XXm98dCJCZAQLwgfN+vV17g7OzMdye488y3PI8SJCWiPZd1uvmo8zUEAUQwIByHGm8Fn+x5A1fAjl5tZEjKxWTG9m2x7sfhA/owY6AfvUZFu+lfoYtre9T9ZVlm//79fPXVV7zyyiuUlpby2WefMWZMuC6ArMjsrFrPL4Xf4gm60Ki0XNx+4hHLw56I/bU7+Grfe0TqY7mx2wNH3ddXtp/8N29A9tRh6tCPVte90qzCOEFnNd78rfgqDhByVuN11bFj915+WbOZDftK8JiTGDdxChMmTCAx8bf5HAE5QLHzAPn2feTZsylzF8Hv5hu0taXTIbIr7W2dMTRjqajdbmfRokXMnTuXb775hkAgwHnnnceNN97IkAsHsse+iR1V6+uHmSRUpEV1pVf8IFpFtAM5SPnCF6ld9TEAEV2Hk3T5kyelBoLs91Czei41yz/4rVdFkjC2ycKcfg6mdr3RJ2eg0jZvRYTs9+CvOICvJBtv0S68hTtwF+5A9bu01rqENCK6nEtE53MxpHQ9YhD75ZdfcsOE8cy5fRhp6nDgFDXoWuJG/r3Re7xBD7urN7GhbBm1B8sbH099EEEQwYDQLEE5wIc7Z1DtLSfWmMi4tBtadEKSLMukxkaw4MaOGDUSbW6fiyE5o8l9XS4Xixcv5rHHHmPLli3o9XrGjx/PP/7xDzp27Nhof3fAycIDH5Fnz0YlqRnf6WZSLO1xOp0Eg8E/VAa2wl3CBztfwKgxMzXrX8fc35O/jYJZN6P43VizRpF4+ZPN7gHZv39//UoLr9dbP+lxwIABzTqGO+Ai35FNbt0eDtTtxh38rZSvSlLR2pJGelQPOkZ1a1ZgUFtby7x58/jggw9YsWIFsbGx3HrrrTz40APkubPZUr6qQbrpeEMS7XfnEL1xFSpFIWbYTcQMv+WIyy2Phyt7FaVfPkGwNpxkShOZRGT/y7H1HHXUctDHS/Z72PjDp/z4wQzaG110TzahOuzaa2yJWLpfgKXb+RhSGpaPtm/5nq2z7iE+QgsqNfGj7iVqwJUHX5ep8pZT6NjPgbrd5Nn31vfqGDQmzmk1ku6x/cQ8AaHZRDAgNMum8pUsyf8Ss9bCNV3+/qfmpz8WRQ6x/INnUG34iLgILbqENNre8UmTE8lqamro0aMHBQUF9OrVi8cee4whQ4Zgs9mOeg5ZCbEgZw57a7ZhUlvY/E4RH743B4/HQ3p6OrNmzWo04aw59tXuYP6+94gzJnNNl79TUlLCpk2byMvLw263U1dXh16v5+yzz2b48OFoNBpc+36l8L3bQA41Wa5YUWQcATvugB1P0E1A9jN37ly++uor9Fo9I4aP5IpLr6JNUnuMGtMJJSNSFJlSVyH763awr2Y7Vd6y+tdUkpr2ts50ielNe1uXZnVJ79y5kzfffJM33niD/v37M3v2bNq3b0+lp4RNZSvZUbW+/uZmcnnpFdmH3t0momlimGL//v0sW7aMgoICnE4nWq2W6OhounXrRo8ePRr0fiiKQtWSt6laHE5RrYlMIvb827D2uPCIRYtCoRDPPfccc+fOpbq6mvj4eCZOnMitt96KXt+8mhuKorBkyRLWr/wZ775fsdr3cUHnGDQctgohKhlr1igkjQ7n3tU4Crfg1+vI9SokjLsdXatW1HgrqPaWU+EpaVRpM9aYSLfYfnSLPesP1QIRzkwiGBCaZd6e/5Lv2MfQ1mPpldB47fP/ghzwYt+8kJrlH+KvCKcgVse0pc2Nr6GNatXke/7+97/z0ksvsXnz5gYTxZojEPLx3rbncARrWTZ7I/2ShtO2bVveeOMNNm3axPz58znvvPOO65gri77n15LF+As0vDX9E3JzcwHQaDRYrVZsNhtOp5OKigoyMjJ46aWXGDFiBJWLXqPq57cxtutN8uQ3ybNnk2vfQ7Ezl2pveYPlkkejljRYdVFEGWKJNsQTa0wi3tSKGGNCkxkaj6TaW8Hemq3sqd5MxWEpnE2aCDJjz6J7XP9mJTtatWoVl19+OVVVVSxdupR+/foBUPjTq2wq/InctFT8+vAyQ4sukrOTzqdrbB9Ukprs7Gxeeukl3n777folf1arlUAgQEVFBS5XeOihT58+TJo0iWuuuYbgps+p/GEmQHj1wsi/H331wsEelQULFjBx4kRSU1uTX7ufUm8evYZ0p2uvznhDbgIhPyHlt7oUElI4TwVqVJIKlaRCLamRDv69sKAIp9NBervWBL0OQn43sgQhtYqQWk1Io0Y5Rg+IRqUlyZxKG2sn2ts6E2tMOmUKMQl/PSIYEJrlnW3/ps5XxZXpt9HK0u5/eu5AXRm1qz+hbt0XhNy1ANR6giwq1vPw/61CpT3yU9B3333HRRddxJIlSxg6dOhxn/ve56eReK4Bk8rCLT3Dy7M8Hg+XXnopS5cu5euvv252QLB27Vq+ynmXmLQIFsxYTrqlJyNGjCArK4u2bds26CJeu3Yt9913H7/88gsdOnTgllF9GRG5j5xumRR2SMEb8jQ4tkpSYdJYIKBix9adxMXF07Fj2m9llEOuRssKD6dV6Ukyp9L6YA6CBHPrZgcHlZ4SdlRuYGfVBtzBcDplCYm0qEzOShxKovnoBZRcLhfDhw8nNzeXV199lREjRlD9wa14C7cTc8nD5KcmsrZkCa6Dx8alYe0nu/n0jfnExcUxffp0br/9dszm3/IayLJMbm4ua9asYe7cuSxcuJDMVjY+uioFFRB30d1ED7rmqO3yer2MGzeOZcuWMW/ePIZecC7fHfiIXPueZl2Xk0EVkgnYPVSUOhkyYARRhliiDHHEGZOINiSIiYHCSSOCAaFZ5ux8iTJ3IaPaTyQjOut/ck5vSTbVv8zGsfUHkMPdqZrIJD7aVM2zX67n5xW/0rdv36MeQ1EUevbsiUajYcmSJVitzR/eWLRoEaPGjOKZZXeBWmFCxu0kRYSrCB4KCBYvXswLL7zA1Vdf3SjrnKIo5OTk8OOPP/Luu++ybt06/vndVCJijYxNvYG0+KbzBxzi9/v55JNP2L1uGX1b5ZA/qBsBXfgp2VXtoWxnHbV5HhzFHsryKiktKauvhLdq1Sqqq6vxeDy0tanx5G3GXbqHOnsB9pALh1bGbtRitxipsxgJahre+A2KhjaaRDrZutI2vhdac/QxnzpDcoicup1sLl9FvmNv/fZ21gwGpowkwdSw96asrIyNGzdiNpvp0KEDN910EwsXLgTg7QmdGZSqY9kBN0+u9FBdV03v0Z0Zfn0/zJHhJ3mt3cKVfW4i3nrsIjwlJSWsfukmuqoKWJrjYn+bcYwePZouXboQHd34szkcDi6//HKWLl3KggULGD58ON8f+IQdVetQS2rSIrux+IulbFu3i/ff+RC9xoBapUHiYECHgqzIKIqMrMjISoiQIqMoIZxuF9dffx3dMjO564ph2Dd8g+KsRpIVDLYkrGkDUHtc+LYuBnt4MqCsKJRoWtH/hscxtustegCEk04EA0KzLC34hg1ly2hny+CSjpP/1HP5yvZRueg1nDt/rt9mbNebqIFX88sBJxePHku/fv349ddfm3W8jRs3MmzYMNLS0li6dCkRERHHfI+iKPTu3RuLxcI9704mu2YLfROHMjhlVP0+gUCAO+64g//+979AuOiMyWRCr9cjSRIVFRXY7XZUKhUjR45kypQpHEhZTUgJMrnbQ8fsRldCAWrXfs6m7R+zKSsNJAmdz4Bju5rqfS4qyivw+/3IsozFYsFgMDBo0CBGjRrF0/fcDPuWcn4nG8m2o69AUACH1Ux1bBSV8dFUxkUR1P2WAVDv8dImv5wOVQEijDForPFoLLFoLLGozVGoTZGoTTbURhsqowW10UKVv5J1pUvZVbUJBRmQyIzty6BWo6itqGPq1KnMnz+//hwff/wxV1xxBatXr2bv3r2U7/qVUdKvqFE4IKWwN2E4XTK7k9K2FUXq3WypWo2shNCqdAxOGUWPuGNPisx7/Rq8BdtYIvfgwTfnU1dXB4DJZCI5OZm4uDgsFguyLLNx40YCgQBffPFFfc/Pu9uepcZXwZgOk+gYFQ64Bg4cyE8//cSwYc1fxz9t2jTWLfyID28bilIZziHQ1NwFOejHtfsXan79FM9h2SENKV2JGXYT5ozBIigQThoRDAjNUu2tYPb251CQGdvhOtKijl1e9niFvA4qf3iV2jXzQJFBkrBknk/0kOswtOpCaWkp7dq1IxAIkJubS0pKSrOPvWXLFgYMGMDkyZN5+eWXj7l/dnY26enpzJ8/n/Rz2rAg50Msukgmd3uoUfd5Xl4eq1evJjc3F4/Hg8/nQ1EUYmJi6NatG2eddVZ9muSZGx8iIPu5IfN+oo6QKz6cM+AbalZ8iN1Txc8XDkBWq+lm68HwDhOO2DWsKAqu3cupWPIO/sKt9du9IdhU4ECX1Jlhl1yDJb41KoMFSa1GkUMoAR+yz0XIVUPQWY3fXkZJoJw8g5eCKD0BXfjmpAqFaJNTRMfdB9D5jz5HQdKZUJtseKJj2dUulvzIcJvVQYmFz/7Itl/LePLJJxk+fDgTJkxAq9WybNmyBsewb/2Bkk8eAjmEqcNZJE98oT63QJWnjMV5n9evPmhv68LIdlcedVXDgZfH4y/dS8r1r6Nvfxbbt29n7969FBQUUFJSQmVlJQ6HA0VRyMzM5Morr6Rz587175+7+zWKnAcYnnoJWfEDUBSFxMREpkyZwpNPPnnU61F/jA9ns/PDR5jQOxYJUOkjiBl+E5H9rzjqcNfsl54k7/v/ckn3WHQHf/2GVl2Iu+jvmNofvXdMEJpDBANCsy0rWMD6sqXo1AauSJ9K/ElMyOPOWUfJp48QrAvPUo/oOozYC6ahj28PQDAYpGvXrmRnZ/POO+8cuaLbUcyYMYO7776b5cuXH3MlwK5du+jSpQvLli1jwDln8+aWJ/CG3PVPhSfq/R0vUOkpaXQc2e/BtXc1jm0/4tz5M0ogPFM8p1tndnZqRZI5lasyph1xqZg7dxMV376At3A7AEFZIVeOY8gNj2Jo35fX33yHBx98EKPBwGPTb+GKi4ag89cRctUi+1woQT9IKiSNFklrRG20ojZHIkVEkivVsMW5jbKDSYL0ipqz6iJIqXQRctUSctcSctchexzIPmeT7auJtrG1V2cctnCvTEZ2MVmq1ujbn03fS26hc/de9UMEh3PuWUHxR/eh+N3oEjvS+vrX6wv0KIrMpvKV/FL4LSElSKQ+hks6Tj5ikFXw7lTce1eRMO4RIs+6rDm/rgbWly5lWeECovRxXJd5DypJzZgxY/D5fPzwww/HfH/JjtVsf3UyqZHhXhdrr9HEjfx7feroYxk1ahS/Ll3Eq7deSG9zJYo/PG/E0n0E8Rffi8bSdDEsQWgOEQwIzRaSg3yW/RaFzhwMGhOXpN1YP4b+R9Ssnkv5N/8BRUYb3ZqESx7F3OGsBvtMnjyZWbNmMWbMmAbdy8fV/lCIwYMHk5uby8aNG0lIOHImuJqaGqKjo+trHqwo/I41pT8RbYjnmi5/R3OCVRiX5H/FpvIVpEVmcqFlEK69q3HvXY07Z134hnyQLq4dwY7DWWJ24rRWcnbS+QxoNaLxZ/I6qVj4AnXrvgTCFQYjz76Ct34p4J/PzWTp0qX0756OY/tiqrYuwZ27Eb0UanScY1GA6jZt2dmlDXWm8GfvobSif2R/dNEpaG2JSBotSiiI7HUS8tQRctvx1ZWzcvFC1i/7jgiVh6TLB1KSFl7q13FnDum7cvAEZIydh9H24tvRJ3RodG5v8W4KZ08j5KhEG5NK6s3v1t/4FEWh3F3E1/vfx+6vwaSJYHz6LU0Wx6r4YSbVS9/F2nsMSZc9ftzXwBfy8s62p/EG3ZyXegk94gcwevRoFEVhwYIFR32vY9uP5M25D61KQRURR/IVT2JO63dc5/f7/aSmplJWVsaKxd+S5txM7ZrPQJFRmyJJvOxxIjoPPu7PJQggggHhOHmDHj7PfotSdwEaScPwNpfSNabPCY9dVv8ym4rvXgLA2vNiEv72cKOlXgsWLGD06NHExcWRm5v7h2rLl5SU0KtXL9LT01m8ePERCw4pikJ0dDT33nsvDz30EN6gm/e2/wd30En3uP6c3+b4nyyVUJDCfT/xqeNHAAYsXUd0VV3965rIJCxdh2HuNoL7n3uT1157nfNu7M+FtwwkRkrmut7TGxzPV7qPog/vIlAdLmlr6zOO2AtuQ2OJJRgMMnnMYM6JrOactkakw/83V2sp86rZkVuOM6QmPTOLvv0HoFGrUIJ+ZL+bkMcRHjZwVBKsK6vvqZAliewu7dmXEV5R0nXzbtrtLwRJQmNNQBvdKvwTk8oPq7fx8gdfsn5PAeMuuYRHHnmEnj17sr54CcuKw70Aqd/+Snfvwd4EScLa8+Imn5b91UUUvD2ZYG0J+uQMvOc+wE233cHGjRsZPnw4r7z5MkurvqDCU0yE1sbELnc2yoXh2rOSwtm3oY1Kpv19jXshmmNj2Qp+LvgKkyaCG7o9QJ+svpx77rm88sorR3xP3aZvKfn0YSSgLqIdvae/j9p4Ynk6tm3bRlZWFlarleLiYqSaPEo/ewxfSXiFQ+yI24kecoOYSyAcNxEMCMfNH/Lxbc4ccup2AZAelcWw1L9h0h57Yt7hnDuXUvThXQDEDL+FmOE3N/oSCwQCJCUlUV1dzbp16+jdu/cfbv/y5csZOnQojz76KI899tgR9xs8eDAJCQnMmxcubXygbjdf7J0FKAxMvpD+yc1bUigHvNSs+pja1XMJ1pWxpXcXCtomY3B7Of9AiNh2/TGnD0QX3wFJkpg8eTLvvfceTz75JH0GZ7FZuxiVSmJQzBjOahd+8nPnbqJo9jRknwtNZBJJlz+JqV342gTtFZR98yzO7Yvr2yAlpBPbaySmDv3QJ6YhqbXs37+fGTNm8NZbbxEbG8uMGTO44oorGrVfURRkj51ATfHBnyK2+Pey0eZBHZI5/4c1aDyuI35+RWvE3DYLc1p/IroOA0sCj314F7E9TEhOHbe2u4Lq5R/g3PETAOqIGJInPIepXa8Gx/FXFZD/xrWEXDV8udPB29th/PjxzJo1i6SkJH76ZTELCmdT7S2njbUTl3ac0uDfk+xzsfdfg8Llfx/4odk1Ag4XkkO8v+M5anyV9IwdxEUZV/Cf//yHO+64o8n93TnrKHjnZlBk1tsjmfDKT0essthcDz/8ME8//TRXXXUVH330EXLQT8XCF6ldPReA6KGTibtg2h86h3DmEcGAcEIURWZNyRJWFS9CQcagNjEo5SIyY89q1vr0kMfOgRfGEnLVEHn2VSSMub/J/WbMmMH06dO59tpref/9909a+x977DGeeuop/u///q/JGyDAvffey6effkpeXl79tkPjxgC9EwYzOOXio35ef3Uhhe9OJVCVD4DKaEPfbRiLUmXqFBfRhngu63QzFl04I+KhuQqvvvoqU6dOxev18nP+1+xyrEMJKVyUNoE0JZa8169B9tgxtutNq6tfqK9q6M7dRPGc6eFc+5IKbefzuPHFL8mrC/HTTz/Rrl3jHBF79uzh4Ycf5vPPP+fVV1/ltttuO+b1UxSFd7c/Q62vinFpN5KqjiNQU4y9aC9PP3gXHRMiGNS9PUZvJUrQ1+C9u2pUvLKmmIvemggS3Nrjn5i0EXjyt1H6xT/xl+1HUmtpde3LmDsNaPDe+vLOgOGyF4nr3J99+/bRv39/7r//fqbddytzdr5IUAnyt7TrG9WVyJ15Bb6SPSRPfBFL1xOr5Le/didf7XsXSVHx+MVvsPSH5WRlZTXaT/a52Puf0eCu5ue8AONfWUZMzB8f15dlmVatWlFWVkZubm591cvqFXOo+PZ5ABIv/Se2Pn/7w+cSzhwicbVwQiRJRf/k85jQ+XbijEl4Q25+zPuMD3a8wL6a7RwrxqxdM4+QqwZdXDviL5re5D4+n4/HHnsMtVrN888/f1Lb/8gjj3DppZdy1VVX8dZbTdeF79+/P/n5+RQUFNRv65N4LoNTLgZgQ9kvfJ79Nq6A/YjnKfv8XwSq8tFY40i89J90eOhHUsc9xmWZdxChtVHtLeejXTMpduYC8MYbb5CYmEibNm3o2bMnZrOZ+y59HPu+AJJa4rsDHzN/w3N4ZA+G1t1Juf61BoFA4axbCLlq0Cd1os3tH9P+mv/w/vyfkCSJHj168NRTT1FaWtqgjXFxcYwbNw6A6urmluxV6n/HkiShscRiTO3Oqws3M3NZIeXp48m45ws6/nMlbW6fi/W826nQJBKSFTpHybx2YSLqg/9EDqXVNaZ2o83UOUR0ORclFKD4o/sI1BQ3OGsgphML94SHFb77zy2YzWauuuoqxo8fz9tvv020IY6s+HMA2FqxplGrdQcnpB4Kzk5Ee1tnUiLao0gywyf1p3v37k3ut/WT/4C7mhKnwphnFpyUQABApVLx/PPPoygK06b91gMQfc5EYobfAkDZN882unaCcDQiGBD+kERza67ufBdDW4/FoDZS5S1j/v7ZfLhzBrurNxGSm56s5tgann0dPXgSkqbpyXivvfYaDoeDG264gbi4pmeInyitVsvHH3/MtGnTuPnmm3nhhRcaBTCDBoXTLq9YsaLB9r6J5zKq/dVoVFryHXt5f8cL7Kne3GQA5D9409EnpYcr1KnDnzVSH8OVGbcRbYjHGahj7u7XWVX0A5u3bOK8885j2rRpSJLEzJkzsdsd/PDyGn56dw0okB9j4OcRA8m/cCzeg7ntQ+46iv/vHpSgD3P6OaTe8j6GpHQAUlNT2bBhAxMnTuSpp54iJSWFbt260a9fP9LT04mJiWHixImMHDmywc3lSBRFYXnRd9T5q9GpDSRHtK1/7Z577mHixIk88cQTxMXFcfGYsVw0cSoZl0xn2LNLeNfeC3OfSylLjiekAm1IIeKwsX2VzkjyVc9hSO2O7HNSuei1Buf+4Ycf+O+KIgAGtjHx1uuvkpOTg6IoFBUVUVRURKeDqzQOldk+nNoYXpoo+46cjfFYJEmib2I4m2Wf0V0blX12uVxMmTKFspWfAtDh0vtITj25WTuvuuoqEhMTWbBgQYOeq5hhN2Fs2wvF76HypzdP6jmF05sIBoQ/TK1S0ythEDd2e5B+icPRqvRUeIr5Nuf/mLX936wp+QlXwFG/v+z34CvJBsCcfk6Tx5Rlmaeffhq1Ws3TTz/9p7RbpVLx8ssvc//993PPPffQq1cvPvnkEwKB8Br62NhYJEmipqam0XszonsysfOdxBmT8ARdLMiZw5f7ZlHjrWywX9Q54ZS3rj0ryH15PPufGkbRB3dRufgN1Ae2c0Wb60iPzkJBZnXJjwy5uysJnW3k5eVx9913M23aNF599VXW/LqG0l9dmL/eha3GTlCrYW31at7e+gTfH5jLztX/JeisQhffnuQJzzWahBkZGcnrr79OcXExb7zxBoMHD6ZHjx5ccMEFfPjhh+zfv59vv/2WqKioo16zWm8lX+17l3Wl4YRQQ1uPRX9YiVybzcaHH37Itm3buPfee1EUhYSEBO644w5ycnJ4/o33MI26hR0DwqtFUvfl4drUcDKfpNGSMDo8bOTYtgjZ/1vq5e+//55ayUqVO4hODdeMHU6fPn0oLAxPonS73WhU4SRL8u9u0gAhVy0AKsPxzW/5vXa2dGpLHeiMGg7Yd4fb6nDw4osvkpGRwbdfzKVtdDhvQHL/sX/oXE1RqVQ88cQTKIrCww8/XL9dUqmIu/DOcHu2fN/g2gnC0TQ9lVoQToBBY+KclJH0ThzM5vKVbC5fhcNfy4qi71hV/APtbV3oEtOHFA7ecFSaI66N/uqrr6iqqmLMmDHExv5566clSeKZZ55h5MiRPPHEE1x55ZUkJCQwevTo+uRBOl3TGfxijIlc3flOfi35ibWlSw6Wkn2OnvED6Zc0HKPGTPQ5E9EnplG7ei6u7FWEXDU4dy3FuWvpoQbQNSmDxJ79WGeugWSITIapsVeg2LwoisLFF1+M1WrFbDajz83l7GAR7r/dwk6LlzJ3ITuq1rPDBvpRg2hr7oDfuYfWlg6YtJZGbY6MjGTKlCnHdY1CcpB8xz62V65jb802FGRUkprhqePIjG064U1mZiaZmY0TU+XWZfPtgTl4FS/RIT0dd+XgZEWj8W19qy6ozVGEXDX4K/MwJGfg8XiYN28eHTt2xHuwF0b2hpMEVVRUEB0dTYcOHVhfHr62scaGaYoVRcGTvyV8/IS047oGvydJKnYs28fAK3oy+8s32f5VAcuXL8fpdDJhwgQevnMKyrxpSBo9Kr352Ac8Addeey133XUXn376Ka+//np9qm1Danc0tgSCdWV4i3bWTywVhKMRwYBw0hk1Zs5OvoC+iUPJrtnK5vJVlLjy2Fe7nX2129Gp9MT37kJicTlt3TXoTY2fRh999FEA/vWvf/1P2jxkyBCGDBnCtm3bmDVrFkuWLEGWZW699VauvPLKI75PrdIwsNUIOsf05Of8+eTa97Ch7Be2Va6ld/wgeiUMxpzWH3Naf+SgH1/RTjwF2/EV78ZbuB1/RS7+4l1YincxWG9gbUY3ylPNtO+VQjm7mbPrJXrFn0PrNinodDp8Xg8SWtoTS8/Ol1LiymNb6Ur2lK/FZ9CzJ1TInpw5QHgoIt7UilhjEtGGOGz6aCy6SIwaMyqp8Yx2RVHwh7zY/bXU+iqp9JRQ7MyjyJlLQP5tEmBbazrnth5NTBNr+Y/EHXCwouh7tlWGx/ETTCkMOuDBG5Lrh05+1xiUUPjJ/tDs++LiYlwuFz6PhxiDEVCodPhZt24dSUlJDBo0iEpfKb+WhFdRdItruI7fc2ADwboyJJ0R4+9WKpyIjJTwcERI70OWZaZMmcIdd9xBSkoKcsDL3s81KEEfgap8dLF/PB/H7+l0OqZOncpzzz3Ha6+9xoMPPgiEA1xtZBLBurLwRFJBaAaxmkD4n6j0lLKjcj27qzfhDBy2th41qbZ02tkyaGvtRKQhlh07dpCZmUnHjh3Jzs5uwVYfv9y6PfxSuKC+rK9ObSArbgC9EgZhbuJJPeioxLlrGXUb5uPND6cQLgipWda2M6buMegM4Rul2+7FsT+IcdVKrkpUEzXgqvqu9JDXQfbjg6mKiyLwt9vIdx+g0lPa6FyH06n0aNU6JFSAQlAJ4g95kRW5yf1NGgudorrRLa4f8aamy0U3xRVwsKlsBRvLV9QHFD2iz6JrdjH2ZbMBaDVpJhEZDZPlOHf/QtH7d6DSm0l7ZCmSRktpaSlJSUncc9X5TG5Tjg8tE752UVpWTlVVFR8ueIe65Fy8Ic/BpYWT6zM2KnKI/LduwJu3BdtZl5E47pFmf4Yj2Vuzna/3zybJ3IYJnW9v9Hrhe7fhyl6JtfdYki77c4LaiooKEhISiI+Pp6SkBEmSUGSZnGdHELRX0PqmWaJnQGgW0TMg/E/EGhMZ0vpiBqdcRJHzAJs3vEeeqhavyUBO3U5y6nYCYNVFUbi9nL6jM7n+0ptRFPmIKXhPRW1t6bSxdiS7Ziu/liym0lPK2tIlbCj7hc4xvegVfw5xh6Vx1lhiiTzrUmx9L8G9fy1l85+mdWUeV+Zt44MVJg4kR9FpSApRSVZMPYGeI/jZ5Sa5Yie9arNpZeuA2mBBH9WKuPJCEipVDO17D96gh1JXAeXuIqq9ZVR7K3D4a3AGHICCX/bhl31NfgaD2oRNH02sMZF4UytaWdoTb0xq9u9BUWQKnQfYVrGG7JothJTwJMdYyULPkiDGb1/B7g3PIYk+98ZGgUCgpoiyL58AwHbWpfUTTBMSEjhv6BCGR5YBEl9sqaS2LkBICjDt5WspS9gFIUgyt2F0+2satLfq51l487Yg6UzEDDu+YZIjORTUGo9QDyF66GRc2Suxb5iPPrEj0edMPCnnPVxcXBwDBw5kxYoVrF+/nr59++LY/iNBewUqvRlDStdjH0QQED0DQgvxlR/gwEuXYrea8I6cRIk+QLErD1lpuPrAoDaSYG5NgimFeFMr4kzJROpjmpXLoKUpisy+2p2sK11Cieu3pWytItrRI24AHaO6oVE1jMdlv4eyL5/EvvlbAJ77uYTVjhikmCC9Lkwn67zOKKrfnt71agOplo7ElFehW/Y5Nr9E6pR3MCRnNNkmWZHxBt34Q178sh/lYE+ARqVBpzZiUBvRqo9R5VAOEawrI1BbStBeTshZhd9dS0momkKtk3xTEI/2t2Q/kdV1pO3JJaG4gkNbtTGpxF14B5bMhombXHtWUvLZo4Sc1eji29Nm6hxUetPB88psfWMqhsJfqXEHueTjA/QY15Nhk/pzcM4g3eP6M7T12Abpou2bv6Pk04dAUUgc/wS2XqOP+vma6/Pst8m172FA8gjOTj6/yX0qf3qLqsWvA2DrO464i6bXF1s6WT744AMmTZrE9OnTefKOayh87zZkn4uY4TcTe96tJ/VcwulLBANCiylf+CI1yz9AZYig9ZR3UCW0I6dyN9Mfn0b6We1om5lMsIkZ4RqVlih9HDHGBKIMcUTpY4nUx2DTR2PURJxyqVgVRaHYmcvG8uXsrdl+sKRveMJll+jedI3t06DrXVEUKhe9SvXSWQAst8fj6HAhl40fT2JyPDs2fcju/J8pT4wloGs43q4JBImsdZIYmUZK+yHEWlKJ1scd8wZ/pHYHa4vxFu/BV7oXX+le/OU5+KsK8Gol6iIt1EbZqImxUR0Tiaz5bR6CJhAkqbCM1ANFRNXYkTR69IlpGNtkYc4YjKl9XyTVoS58GXfOWqp/+QD33lUA6JM60WrSK/VZAmW/h9LPHsOxbRF1kVZ29x5Klc2LfLDOQqwxiaGtx5JqbTgxsG7Tt5R+9g+QQ0T2v5yEsQ8d93VoSqFjP5/seQMJiesz7yfK0PQkV0VRqF72LpWLXgVFQW2OInrIDdj6jkP9B1c0HJKbm0tGx/bcP6oLV2caUUIBjO160/qG/x5x2a4g/J4IBoQWowQDFMy6GU/uRlT6CJKufJr9PhtZWVkMHDiQZb8so9JTQqm7gDJXIeXuIqo8pU0GCIdoVFqsuigsukgsukgitFYitFbMh350VsyaCNSqlhkhc/jr2Fa5hm0VaxrMnYg1JpIR3YuM6B7Y9OFyx1U/v12/zj7y7CuJH3UPklqDoiiUfPIg9i3fUxcbjWfQWCpsBkpceQRkf5PnNasjiDTEYtFHYdZaMWkiMGrN6FV6NKiRPC5CjgqCtaX4a4rx1hbhrSvGTxC/TovPoMdj1OM2G3FFmAjqGt9kDLKKlJCVNqo4UrVJ6EyRqM3RaG3xqCNiG9z8AzVFeIt24s5Zj2v3L/XVKlFpiDr7SmIvuK1+eaRr/1ryvv03eeYgRW2SqYv87ck6zpjEWUnD6BTVo0FvkSKHqFr8X6p+fhsAa++xJF7yWH0b/giHv5aPd7+Kw19Lt9h+XNB2/DHf485ZR9lXT+GvyAVA0hmxdBlGRNdhmNLOOqHeAkVR8Jfto3bTQvZ/9zYx5vC/6Yiuw0m6/MlGy0sF4WhEMCC0qJDXQdH7d+LJ3QiAN6U/Fzwwi0EjxvLZZ5812l9WZGp9VVR7yqj2llPtraDWV0mdr6p+PLw5jBpzfZAQobNh0dqw6CKx6qOJPDjrvqkZ9yeLrMjk1u1hR9U69tfuqB9Xh/BM+45R3ekYlYm08SfKv3kWAFNaP5IufxqNJQY56Kfkk4fq6w8Y2/Um+rxbcMUnkbt7AcWFa6nVSzisZgL64+8VOBZJAZusJzqoIdanJt6rwhaQkJDg4FeKAiAHUYKBcPEjd1248FFtaaMUxSpDBNasi4g65xp0Ma3DvSM5K9mx/VNytU6q4qLgYI+PSlKTFplJVtzZpFg6NK5nUVtKybxH8OSsByBq8CTiRtx5UgKBKk8pX+59lzp/NVGGOK7ufGeDPAtHo4QC1G1cQM2KD/GX5/z2gqRCn5iGPjkDXVw7dNGtUEfEoDZakTTh350S9BPy2AnWlROoLsRXmo0nbzNBe0X9YQpr/fS5+XmsPUaecr1jwqlPBANCi5ODfiq/e4maVR8B4AvK7PBE87d7X8aQ2r3ZX2xBOYjdX4PDX4PDX4fTX4czUIczYMflt+MM2HEHHUecMX84laTCposmyhAejog1JhFnTCLakID6Dxaa+T1v0E12zTb2VG+iwLEf5bCAJkofS6tgBOYVC4guLUdntBF30d1Ysy4CoGbFh1T++Hr9zVWXkIal2wWY0vohexy49q6ktmAztd5y3Do1HpMBn0GPT68joNMS1KoJajTIajWoNaDWoJJUqFChkUEbCKLxuNDa6zC43BjdHsxON2anB7V87Ot4JJJGhy4hDWNqD8ydzsbUoR+SRkdpyWZ25/5Irjefaou+PgAASDS2onNsXzKie2LSNl67r8ghatfMo/KHV5B9LiSdkYSxD2PrdfEJt/MQWZHZUrGKXwq/JSgHiNTHML7TzVj10cd+8+/bqSh487fi2PoDzj0r/lBqZEmjx9SxP7fP+JSF2yvw+gMiEBBOiAgGhFOGJ38r+Z8/BeV76rdpbAmYOw7A2LYnhlZd0MW2Oe5xUEVRUPxugo5KAvZKXM4SHK5ynL4anEEHLsWHWwrg0si4NODSSciqpr9QVYpEtGIkTmUjQRVFojYOq9qKSqMN37gOdVVLUvhLWVIjqbWodAZUejNqc9RRu29dAUc4H0PNdvId+xpMqFSFZKIra4itqCFRsdGh9wRsXYcTdFRQ9fM72DcuaPjErdagi22LLiYFVUQMKpUGRQ6ihAIoofATuxL0I/ucBJ3VBGtL6ksVN0lSobHGobHGo4mIQWWyotKZUGkN4VwBh568FaX+Ji6pNUhqHZLOiNpkQ2OORhOVhDYyCdnjwF6eTW75RvLcByjWevEYGv5uY3xq0hP70zllMJEHh0+a+v26966m/LsZ+Ev3AmBo3Z2k8U+gi/tj6/sVRSGnbhcri76nwhPO9Z9q6cio9lcfd5XOIwnay8O5J0r34q84QLC2lKCrBtljRwkGQCL8b8hgQWONQxuZhC6hA8aUTAyp3VBUWrRaLVarldra2pPSJuHMI4IB4ZTicrkYkpHAtf2TubBLLIr/dznkVerwzcgWj8YUhUpvRtLqQFKDEgp3SQe8yF4nssdO0FVDyFVz9Jvc7yiA16jHFWHCaTHjsJpxWCOwR1oIahvPNdB7fERX1hBTWUtMRQ0RDhdHezZTmyLRxqZiSO6MsU0WprR+aCIaP2H6Ql7y7NkcqNtNbt2eBnMMAFShEFF2D4naBFISe5Gc0A1p32bcu5fjPrAR2VPX6JjHJElobInoYtugjWmNJiIaSWdGUqlQQgFkj52Qx4Hsc6IEfOHEQIocvvmr1EgqNZIq3MNQv7RPUcLvDXhxhVxUaHxUGBQqoyOw2yIaPP2rQiESnArtLB3pkjEWmzXliE1VZBnXnuVULXsXb144s6DKaCX2/KlE9hv/h0oFB0I+dldvZmP5CioP5ozQqw0MbDWSrLizT6nlrsXFxbRq1YrevXuzfv36lm6O8BclggHhlNOuXTtyc3PJ2bub+FAlrv1r8BZsw1eSjexznfBxJZ0RjSUWTURMeEzWHInaaENliEClMyFpdfU3EEWWw0/QAR9KwBse8/a7scsuqtReKrVBqgxQbVKj/K4XQe8PElfrJb7WQ1yVA6PbgxL0IXscKKFAEw2TMLbpiaX7CKzdR9RXITycoihUe8vIs+8jv3YXhXV78akad9PrgjJRIQMx2mii1VasATUWbxCd14sS8KIE/fVj+hy6cavCiYcIBQl5nQTt5QSqiwjay+EIhaaORQHcZiMOqxm7zUJdpIW6KCteU+PxdatXppVio21UFzp0OA+98ej1EYKuGuybvqV2zTwCleEiPZJGR2S/y4kZOrnJ69cc4bTLe9lTvYXsmm31SZK0Kh1Z8QPokzC0yeGJlrZo0SJGjBjBHXfcwcsvv9zSzRH+okQwIJxypkyZwqxZs3jmmWe477776rcrikLIUUGgpiS8vt1dh+x3h2/YihyeIKbSoNIZURksqA2W8A0/IhqNObp+vfrJFJADlLnyKXDkUOjIodiVS1BueMOP0sfRxtqRNtZOJGsTUDmq8Zfl4C3cgTtnbX3RJgDUGixdhmLrMw5TWr8jPt0qikKVq5gDOT9RVLGdSsmJPcKAcoRJcupAEJPLg8ntxeDxYvD4MHh96HwBdH4/Wn8QTSCIJhhEHZLrezYktRaNLRGNLR61NRa1OZqQKYKQ3kBAq8GnVvAQwI0Pp+LFqXix48Uh+QhJjb9aJCBabSPZ2JrW0Z1pHdmZCJ210X6/F/LYce5ejnPbjzizV8DBVMUqQwSRZ11G1MCr0ViPv7KlK2Ant+5g74t9N77Qbz1IkfpYusf1o1tsPwxHSCx0Krj++uuZPXs2q1at4uyzz27p5gh/USIYEE45y5Yt49xzz6VDhw7s27evpZtzXIJykBJXHvn2veTZ91Lqym8wIVBCRXJEG9pYO9HG2olEcwqhunIc2xdj37gAX8nh8yUSsfa8CGvWRccsrKPIMu6ybEqL1lNWu5+qQDW16gAOgxqPUdegK745VKhQSer6yWiKIhNSQg0+y7GoJQ3Rhvj6TIYJ5hQSTK3QNWP2vRzw4i0MLz1071+DJ29zg14KfXJnIs+6BGvWRcdVCMgTdFPkyKHAsZ98x776IYBDzFoLaZHd6Bzdk+SItqf8ZLyamhoSExPRaDQ4HA5UJ2HFhHBmEsGAcMpRFIX27duTm5vL+vXr6d37r5tb3Rv0UODYR549mzx7NrW+qgav69UGks3tMHisxKiSsTmdRJZvxLHlO2SPvX4/XXx7Ijqfi7nTAAyp3VFpmr9cMBDyU+sqoc5Xhd1fizPoxB1y4Qo68QRdeIKucFbCI6Qnbopa0mDQGDGoTZi1lvolmlZdFJH6GCL1MVj10cfMFCkH/QRrSwlUFeCrOIC/bD/e4t34yvbWP/0ffg0sXYdj6TGiUXDk9/vZtm0bW7dupbq6mo4dOzJq1ChcwTqKnLkUOQ9Q5Mw9WLOh4VdevKkV7WwZtLd1JsmcekrNBziWRx55hKeeeorbb7+dmTNntnRzhL8wEQwIp6TPPvuM8ePH1+ddP13U+arIs+8l176HfPs+fKGG9ebtlU7ytpaitRuY1K8/bWtycWevbDDXQNIaMKR0xZjaHX1yBvqEDmhjUo8rQGiKLIfweWrxOyvwOasIuCoJumrDs9q9ThSfG5XPi9ofQCUHfzf3ILxqArUmvIJApQ5P6gRQZBQ5hBL0ofi9hHxOQu46Qo7Ko1bVU1tiwxkL0/ph6jgAXXTjAkkHDhzgscceY968eQSCfpI7xdOpb1uS02PJGtIVRdc4QVW0IZ7Wlg4HfzqekvMAmsPlcpGYmIjb7SYvL4+UlCNPthSEYxHBgHBKUhSF9PR09u7dy8qVKxkwYEBLN+mkkxWZMlch05+4jah2JtJ6t0GRGk4KVAU1tItOI9YZwpqXg2HXehRHVeODSdLBVRYJ4QmSpsjwSgudIby0TyWhyArIwfBqC58b2ecKrw5w1xFy1RB0Vh3XqouTRdIa0EYlo4triz6+A/qkjhhSuqKJTD5qN/33Sxby4L/vpmPvtvQd3gNNpIz8++snqYg3tiI5oi0plva0imiLqYnqkX9Fd955JzNnzuSaa67hgw8+aOnmCH9xIhgQTllr166lX79+REdHk5+fj9n813yCO5a1a9cycOBA7n/wPm6+9wYK7PvIt++joC4HlabhzVAtqYnVxhLjk4isriOiMB99wT6UP7DK4vcknSkcUFiiw3+aow6uujCHV11oDq66kMKrEBQ5BHIonLsgFM5jgBwKb4dwzgW1BkmjC0/u1EegNtnCEzut8ahNkcccmw/IAcrdRZS68ilx5VNQux+37Gi0n0FtonBXObvX7uc/D79E2+iOJ1SX4VS3detWsrKyMJlMFBYWEhkZ2dJNEv7iRDAgnNKmTZvGa6+9xvDhw1m0aNFpO0Hq8ccf5/HHH2fdunX07NkTAH/Qz8RbLsejq2PCreOpDpXiDbobvVer0hGriyNaMhMV0GDzgdXtR+v1Igd8KCE/yDKoVEgqDZJWf/CmbEZttKIy2dCYo1BHxKCxxLZ4Tnt/yEuFp5RydxHl7iLKXIVUekrrCzwdosgKMcYEWlnakRzRhuSItnz/5WKunnA18+fPZ8yYMS30Cf5cLpeLtLQ0SktL+eSTT7j88stbuknCaUAEA8IpLRAIkJmZSXZ2NpMmTeK999475Wd4nwi/30/fvn1RFIW1a9diMIRn3FdUVNC7d2+SkpL45ZdfcCsOSlx5lLoOFm/yFDVayniISWMh2hBHlCGOSH0skYYYbPoYrLpIDGpTi15HRVFwB53Ueiup8VVS7S2jylNOlbeMOl8TwyCEP0+iuTX2Qg9PPfAfnvvHy4wd9bf618vLy+natStDhw7l008//R99kv8tRVEYOXIkP/zwA1deeSUff/xxSzdJOE2IYEA45VVUVNCtWzfKysq47777ePbZZ1u6SX+KrVu30rdvXx544AH+9a9/1W9ft24dAwcOZOrUqbz00ksN3iMrIWq8lZS7i6nwFFHpLqXSW4rDX3vUc2lVuoNVHW2YtRZMWgsmjRmjxoxBY8agMaJXG9Cp9GjVOjSSFrVKg1pSN5ptLx9cdhiSAwTkAAHZhy/oxRfy1K9WcAecOAN2nIE6HP5a7P6aIwYxAGatlXhjMvHmViSYUkgwpWDRRRIKhejRoweJiYksXrz4sKWPCmPGjGHt2rVs3bqVhISE47v4fxF33303L774IhkZGWzevBm9Xt/STRJOEyIYEP4SCgoK6NatG3V1dfz73//mgQceaOkm/SkeeughXnzxRXbt2kW7du3qt8+cOZM777yThQsXMnLkyGMexx/y1ld1rPFW1ld2rPNV4w46/3A7pYNpiY4n70BTR7HobETp4w4WhIon1pBIjDHxiHn/33//fa677jrWrl1L375967d/8MEHTJo06bQeHnjwwQd55plniI2NJTs7m6ioo2dqFITjIYIB4S9jz5499OnTB6fTyfPPP8/dd9/d0k066ZxOJ507dyYrK4tvvvmmfruiKIwYMYLs7Gx27tyJyXTiGfECcgCnvxa7vxZXwI7Tb8cddOINug7+6cEbcuMPefGH/ARkP80tDS2hQqfWoVMbMKiNGDQmjBozJq0Fs8ZChM4aLhWti8Kqi0Ktalzr4UjcbjdpaWkMHDiQefPm1W8vKiqia9euXHzxxcyZM+d4L8dfwqGVAzExMWzdupXk5OSWbpJwulEE4S9k3759SkREhAIozz77bEs350/x2WefKYDy2WefNdi+fPlyBVDWrVv3P22PLMtKIBRQvEGP4vI7Faffrjh8dYrDV6c4/XbFHXAqvqBHCYYCf2o7Pv/8cwVQdu3a1WD7+PHjlYSEBKW6uvpPPX9LkGVZmThxogIoiYmJSnl5eUs3SThNnZ5Ts4XTVocOHdiyZQs2m43777+f22+/vaWbdNJdcskljBs3jltuuYXS0tL67WvXrkWSJOLijj8H/x8hSRIalQa92oBJa8asDT/hR+ismLUWjBozOrXhuJ7yT8RXX30F0KB7/Ouvv2bevHm88MILp123uSzLDBs2jDlz5pCenk52dvb//HcvnDnEMIHwl1RTU0NWVhb5+fnccMMNzJo1q6WbdFKVl5eTlZVFcnIy06dPZ+7cuXzzzTen5WdtrqKiIvr06YNGo+HRRx9FlmXuvfdehg8fzpdffnlarTLx+XxkZWWxe/duzj33XH788Uc0mj832BLOcC3dNSEIJ8rj8SgdO3ZUAGXKlCkt3ZyTbsOGDUrr1q0VQMnIyFDmzJmjhEKhlm5Wi8rNzVVGjx6tEJ7EoIwcOVJxOp0t3ayTyu12K+3bt1cA5brrrmvp5ghnCNEzIPyl+Xw+unbtyv79+7n++uuZNWvWafWEqCgKeXl5pKamnrYJl05EXV0dRUVFZGRknFbXxel0kpmZSV5eHjfffDP//e9/W7pJwhlCBAPCX57b7SYzM5MDBw4wduxYvvjii9PqBiGcGQoKCujZsydVVVXcddddzJgxo6WbJJxBxDem8JdnMpnYvn07mZmZzJ8/n0GDBuF2N07bKwinql27dpGenk5VVRX//ve/RSAg/M+JYEA4LZhMJjZs2MCAAQNYtWoVaWlp7N69u6WbJQjHtGTJEnr06IHX62X27NmnbUIt4dQmggHhtKHT6Vi+fDnXXnstJSUldO/enU8++aSlmyUIR/TKK69w3nnnIcsyX3zxBZMmTWrpJglnKDFnQDgtPf/889x3330oisLkyZN59dVXRR534ZThcrmYMGECX3/9NQaDgSVLlnD22We3dLOEM5gIBoTT1vLly7n44oux2+20a9eOhQsXkpGR0dLNEs5wS5cu5bLLLqOqqorU1FSWLVtG27ZtW7pZwhlODBMIp61BgwaRnZ3NoEGDOHDgAF27dmX69Om4XK6WbppwBsrLy+P8889n6NChVFVVMWnSJHbu3CkCAeGUIIIB4bSWkJDAsmXLeOeddzAYDMyYMYO4uDieeuopgsFgSzdPOANUVlZy3XXX0b59exYvXkzbtm1Zu3Yts2fPxmw2t3TzBAEQwYBwBpAkiRtvvJHy8nIeeOABFEXhkUceITExkTlz5iDLcks3UTgNVVVVMWXKFJKSknj//fexWCy88cYb7N+/v0H5ZUE4FYg5A8IZx+l0cvfdd/POO+8gyzJRUVGMHz+eG2+8kT59+oiERcIfsmnTJv71r3/xzTffIMsykZGR/OMf/+C2225Dp9O1dPMEoUkiGBDOWMXFxUyfPp358+fj9XoBiImJ4dFHH2Xq1KlotdoWbqHwV1FYWMizzz7Lp59+Snl5OQBxcXE88cQT3HjjjaLIkHDKE8GAcMYLBoMsW7aMmTNn8u233xIKhTCZTFx++eU88MADpKent3QThVOQoihs2LCBhx56iMWLF6MoCjqdjgEDBvDAAw9wwQUXnFZ1MoTTmwgGBOEwtbW1PPzww7z77rv1vQWJiYlMmjSJRx55hIiIiBZuodCSFEXh119/ZebMmSxatIjq6moAWrduzQsvvMC4ceNEL4DwlySCAUFoQiAQYPHixcycOZOff/4Zn8+HWq3mggsuYNq0aQwaNAiLxdLSzRT+R0pLS3nppZd46623qKmpAcBsNjNkyBDuu+8+Bg8eLHoBhL80EQwIwjEEg0HeeecdnnjiCYqLi+u3JycnM2jQIG666SaGDBmCWq1uwVYKJ1NFRQVLly7liy++YOXKlRQUFACg0WgYOXIkjzzyCH379hUBgHDaEMGAIByHTZs28d577/HTTz+xb98+/H4/AFqtlszMTM4//3zatGkDUD+TPD4+npiYGJKTk4mPjxdBwylEURSqqqrYsWMHa9asYdmyZaxevbr+6R/CNS86d+7MDTfcwHXXXYfVam3BFgvCn0MEA4JwghRFYfv27bz55pt89dVXFBUVNet9Wq0WtVqNWq1GpVIhSVKjPw/9Haj/7yP9HMmRXvv99mP99x/V1PEkSeLQV8+RXj/a8Q69V1GUo/79UA6JQ3/3+/34/X6CwSB+v59AINDo+Eajkb59+zJy5EjGjh1Lenq6WG4qnPZEMCAIJ0lxcTFbt26luLgYt9tNMBjE7XZTUVFBVVUVpaWlVFdXU1tbi9frxefzHVcWxMNvdIf/ebR9m7u9Oa8ritLgRnwsLfHVcngQ8fugSaVSodPp0Gq16HQ6DAYDJpOJ6OhounbtSp8+fcjKyqJLly7i5i+ccUQwIAiCIAhnOBH+CoIgCMIZTgQDgiAIgnCGE8GAIAiCIJzhRDAgCIIgCGc4EQwIgiAIwhlOBAOCIAiCcIYTwYAgCIIgnOFEMCAIgiAIZzgRDAiCIAjCGU4EA4IgCIJwhhPBgCAIgiCc4UQwIAiCIAhnOBEMCIIgCMIZTgQDgiAIgnCGE8GAIAiCIJzhRDAgCIIgCGc4EQwIgiAIwhlOBAOCIAiCcIYTwYAgCIIgnOFEMCAIgiAIZzgRDAiCIAjCGU4EA4IgCIJwhhPBgCAIgiCc4UQwIAiCIAhnOBEMCIIgCMIZ7v8B133Kt2uXpu8AAAAASUVORK5CYII=",
+      "text/plain": [
+       "\u001b[1m<\u001b[0m\u001b[1;95mFigure\u001b[0m\u001b[39m size 64\u001b[0m\u001b[1;36m0x480\u001b[0m\u001b[39m with \u001b[0m\u001b[1;36m1\u001b[0m\u001b[39m Axes\u001b[0m\u001b[1m>\u001b[0m"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# Top projection\n",
+    "# select objects within the dorso-ventral range\n",
+    "df_top = df[(df[\"Atlas_Y\"] >= dv_lims[0] / 1000) & (df[\"Atlas_Y\"] <= dv_lims[1] / 1000)]\n",
+    "\n",
+    "plt.figure()\n",
+    "\n",
+    "for struct_name, contours in coords_top.items():\n",
+    "    for cont in contours:\n",
+    "        plt.fill(-cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n",
+    "\n",
+    "# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\n",
+    "ax = sns.kdeplot(\n",
+    "    df_top,\n",
+    "    x=\"Atlas_Z\",\n",
+    "    y=\"Atlas_X\",\n",
+    "    hue=\"Classification\",\n",
+    "    levels=nlevels,\n",
+    "    common_norm=False,\n",
+    "    palette=palette,\n",
+    ")\n",
+    "ax.invert_yaxis()\n",
+    "sns.despine(left=True, bottom=True)\n",
+    "plt.axis(\"equal\")\n",
+    "plt.xlabel(None)\n",
+    "plt.ylabel(None)\n",
+    "plt.xticks([])\n",
+    "plt.yticks([])\n",
+    "plt.plot([0.5, 1.5], [0.5, 0.5], \"k\", linewidth=3)\n",
+    "plt.text(0.5, 0.4, \"1 mm\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "hq",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.12.7"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/demo_notebooks/fibers_coverage.html b/demo_notebooks/fibers_coverage.html
new file mode 100644
index 0000000..7add95a
--- /dev/null
+++ b/demo_notebooks/fibers_coverage.html
@@ -0,0 +1,2276 @@
+
+
+
+  
+    
+      
+      
+      
+        
+      
+      
+        
+      
+      
+      
+        
+      
+      
+        
+      
+      
+      
+      
+    
+    
+      
+        Fibers coverage - cuisto
+      
+    
+    
+      
+      
+        
+        
+      
+      
+
+
+    
+    
+      
+        
+      
+    
+    
+      
+        
+        
+        
+        
+        
+      
+    
+    
+      
+    
+      
+    
+      
+    
+    
+    
+      
+
+    
+    
+    
+  
+  
+  
+    
+    
+      
+    
+    
+    
+    
+    
+  
+    
+    
+    
+    
+    
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + +

Fibers coverage

+ + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo_notebooks/fibers_coverage.ipynb b/demo_notebooks/fibers_coverage.ipynb new file mode 100644 index 0000000..f405f81 --- /dev/null +++ b/demo_notebooks/fibers_coverage.ipynb @@ -0,0 +1,511 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot regions coverage percentage in the spinal cord.\n", + "\n", + "This showcases that any brainglobe atlases should be supported.\n", + "\n", + "Here we're going to quantify the percentage of area of each spinal cord regions innervated by axons.\n", + "\n", + "The \"area µm^2\" measurement for each annotations can be created in QuPath with a pixel classifier, using the Measure button.\n", + "\n", + "We're going to consider that the \"area µm^2\" measurement generated by the pixel classifier is an object count. \n", + "`histoquant` computes a density, which is the count in each region divided by its aera. \n", + "Therefore, in this case, it will be actually the fraction of area covered by fibers in a given color.\n", + "\n", + "The data was generated using QuPath with a pixel classifier on toy data." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "import cuisto" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Full path to your configuration file, edited according to your need beforehand\n", + "config_file = \"../../resources/demo_config_fibers.toml\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# - Files\n", + "# not important if only one animal\n", + "animal = \"animalid1-SC\"\n", + "# set the full path to the annotations tsv file from QuPath\n", + "annotations_file = \"../../resources/fibers_measurements_annotations.tsv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# get configuration\n", + "cfg = cuisto.config.Config(config_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ImageObject typeNameClassificationParentROICentroid X µmCentroid Y µmFibers: EGFP area µm^2Fibers: DsRed area µm^2IDSideParent IDArea µm^2Perimeter µm
Object ID
dcfe5196-4e8d-4126-b255-a9ea393c383aanimalid1-SC_s1.ome.tiffAnnotationRootNaNRoot object (Image)Geometry1353.701060.00108993.195315533.3701NaNNaNNaN3172474.09853.3
acc74bc0-3dd0-4b3e-86e3-e6c7b681d544animalid1-SC_s1.ome.tiffAnnotationrootRight: rootRootPolygon864.44989.9539162.89065093.2798250.00.0NaN1603335.74844.2
94571cf9-f22b-453f-860c-eb13d0e72440animalid1-SC_s1.ome.tiffAnnotationWMRight: WMrootGeometry791.001094.6020189.04692582.4824130.00.0250.0884002.07927.8
473d65fb-fda4-4721-ba6f-cc659efc1d5aanimalid1-SC_s1.ome.tiffAnnotationvfRight: vfWMPolygon984.311599.006298.3574940.410070.00.0130.0281816.92719.5
449e2cd1-eca2-4708-83fe-651f378c3a14animalid1-SC_s1.ome.tiffAnnotationdfRight: dfWMPolygon1242.90401.261545.0750241.380074.00.0130.0152952.81694.4
\n", + "
" + ], + "text/plain": [ + " Image Object type \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a animalid1-SC_s1.ome.tiff Annotation \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 animalid1-SC_s1.ome.tiff Annotation \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 animalid1-SC_s1.ome.tiff Annotation \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a animalid1-SC_s1.ome.tiff Annotation \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 animalid1-SC_s1.ome.tiff Annotation \n", + "\n", + " Name Classification \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a Root NaN \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 root Right: root \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 WM Right: WM \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a vf Right: vf \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 df Right: df \n", + "\n", + " Parent ROI \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a Root object (Image) Geometry \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 Root Polygon \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 root Geometry \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a WM Polygon \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 WM Polygon \n", + "\n", + " Centroid X µm Centroid Y µm \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a 1353.70 1060.00 \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 864.44 989.95 \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 791.00 1094.60 \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a 984.31 1599.00 \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 1242.90 401.26 \n", + "\n", + " Fibers: EGFP area µm^2 \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a 108993.1953 \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 39162.8906 \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 20189.0469 \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a 6298.3574 \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 1545.0750 \n", + "\n", + " Fibers: DsRed area µm^2 ID Side \\\n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a 15533.3701 NaN NaN \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 5093.2798 250.0 0.0 \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 2582.4824 130.0 0.0 \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a 940.4100 70.0 0.0 \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 241.3800 74.0 0.0 \n", + "\n", + " Parent ID Area µm^2 Perimeter µm \n", + "Object ID \n", + "dcfe5196-4e8d-4126-b255-a9ea393c383a NaN 3172474.0 9853.3 \n", + "acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 NaN 1603335.7 4844.2 \n", + "94571cf9-f22b-453f-860c-eb13d0e72440 250.0 884002.0 7927.8 \n", + "473d65fb-fda4-4721-ba6f-cc659efc1d5a 130.0 281816.9 2719.5 \n", + "449e2cd1-eca2-4708-83fe-651f378c3a14 130.0 152952.8 1694.4 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# read data\n", + "df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\n", + "df_detections = pd.DataFrame() # empty DataFrame\n", + "\n", + "# remove annotations that are not brain regions\n", + "df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\n", + "df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n", + "\n", + "# have a look\n", + "display(df_annotations.head())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NamehemisphereArea µm^2Area mm^2area µm^2area mm^2density µm^-2density mm^-2coverage indexrelative countrelative densitychannelanimal
010SpContra.1749462.181.74946253117.370153.117373.03621130362.1139731612.7556450.0365350.033062Negativeanimalid1-SC
010SpContra.1749462.181.7494625257.10255.2571030.3004983004.9820815.7974990.0307660.02085Positiveanimalid1-SC
110SpIpsi.1439105.931.43910664182.982364.1829824.45992144599.2063282862.510070.0235240.023265Negativeanimalid1-SC
110SpIpsi.1439105.931.4391068046.33758.0463370.5591215591.20585444.9887290.0289110.022984Positiveanimalid1-SC
210Spboth3188568.113.188568117300.3524117.3003523.67877836787.7832164315.2199350.0280470.025734Negativeanimalid1-SC
\n", + "
" + ], + "text/plain": [ + " Name hemisphere Area µm^2 Area mm^2 area µm^2 area mm^2 \\\n", + "0 10Sp Contra. 1749462.18 1.749462 53117.3701 53.11737 \n", + "0 10Sp Contra. 1749462.18 1.749462 5257.1025 5.257103 \n", + "1 10Sp Ipsi. 1439105.93 1.439106 64182.9823 64.182982 \n", + "1 10Sp Ipsi. 1439105.93 1.439106 8046.3375 8.046337 \n", + "2 10Sp both 3188568.11 3.188568 117300.3524 117.300352 \n", + "\n", + " density µm^-2 density mm^-2 coverage index relative count relative density \\\n", + "0 3.036211 30362.113973 1612.755645 0.036535 0.033062 \n", + "0 0.300498 3004.98208 15.797499 0.030766 0.02085 \n", + "1 4.459921 44599.206328 2862.51007 0.023524 0.023265 \n", + "1 0.559121 5591.205854 44.988729 0.028911 0.022984 \n", + "2 3.678778 36787.783216 4315.219935 0.028047 0.025734 \n", + "\n", + " channel animal \n", + "0 Negative animalid1-SC \n", + "0 Positive animalid1-SC \n", + "1 Negative animalid1-SC \n", + "1 Positive animalid1-SC \n", + "2 Negative animalid1-SC " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# get distributions per regions, spatial distributions and coordinates\n", + "df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n", + " animal, df_annotations, df_detections, cfg, compute_distributions=False\n", + ")\n", + "\n", + "# convert the \"density µm^-2\" column, which is actually the coverage fraction, to a percentage\n", + "df_regions[\"density µm^-2\"] = df_regions[\"density µm^-2\"] * 100\n", + "\n", + "# have a look\n", + "display(df_regions.head())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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iE35o48+alEqlRaDwVAjrks9gKKjoy2AzUP/Yvr162e5+uqrLb/99pu17MCBAxYnJyfLXXfdZS273H8LFovFolKpan1AnavjzjvvrPHZuYfg+datW3dFSa8QrZE8p/+nuTynLZYLJ4qdO3e2Sbo3bNhgASwvvviixWKxWL777jsLYHn33XcvWr8kig1Hup5rMX36dJvtG2+8kd9++w2j0QjA+++/T1VVFePHj+fMmTPWL19fX4KDg/n0009tjm/bti0TJkywbnfv3p327dsTGhpKWFiYtfzc9z///PMFY2vfvj0AH3744SWb+8eOHUvnzp2t29dffz1hYWFs27btsq75/DjeffddPD09GTZsmM01X3vttbRt27bGNQcGBhIZGWlT9u6773LjjTfi5eVlU8fQoUMxm8189tln1n1XrVqFxWIhICDgotd47mfSrl27i+4H1d0k+/fvZ8qUKWg0Gmt5nz59GDZs2GXfl/P/LVyOv9cB2IwDKi0t5cyZMwwYMACAb7/99rLrFqK1kud083lOX8xdd91l8/y+44476Nixo/X6PT09Adi5c2etQwtEw5PJLLXw9/e32fby8gKgqKgItVpNdnY2FouF4ODgWo93dna22e7SpQsKhcKmzNPTEz8/vxpl585zIREREdx+++3MmzePpKQkbr75ZsaOHcvEiRNrDOatLb6QkBA2bNhgU+bm5oaPj49NmZeXl00c2dnZFBcXc/XVV9ca16+//mqzHRgYWGOf7Oxsvv/++xrnulAdl0OtVgPw+++/Wx/OF3Ls2DGg+j+AvwsNDWXnzp01Jptc6t/C5ajtXhQWFjJv3jzWr19f47rPH3cjhKidPKebz3P6Yv5+/QqFAq1Wax3vGRgYyIMPPsgLL7xAamoqN954I7feeitxcXHWn4VoWJIo1uJCs9csFgtQPVhYoVCwffv2Wvf9+8KoF6rvUuepjUKhYOPGjezdu5ctW7awc+dOpk2bxvPPP8/evXvrtCjr5czWq6qq4uqrryY1NbXWz//+UKlt5lxVVRXDhg3j4YcfrrWOkJCQy4jWVo8ePQD44YcfuPHGG6/4+Eupy8/o72q7F+PHj+err75i9uzZ9OvXj7Zt21JVVUVUVFSNAeNCiJrkOV1TU31O19fzzz/PlClT+O9//8tHH33EAw88wKJFi9i7dy9dunRp9HhaG0kU6yAoKAiLxUJgYKBDfmkABgwYwIABA3j66ad55513iI2NZf369dxzzz3WfbKzs2scd+TIkTp1EwQFBfHxxx8zaNCgOi+fEBQUxB9//MHQoUPrdHxtxowZw6JFi1i7du0lE8Vza5wdPny4xmc//fQT3t7edVq65u+tEJdSVFTErl27mDdvHk899ZS1vLaflxCibuQ53XSe0xfz9+u3WCzk5OTQp08fm/LevXvTu3dvnnjiCb766isGDRrEypUrWbhwYaPE2ZrJGMU6+Oc//4lSqWTevHk1/qq0WCwNusRJUVFRjXP269cPgLKyMpvyTZs2ceLECev2vn37yMzMZMSIEVd83vHjx2M2m1mwYEGNzyorKzl79uxl1ZGRkcHOnTtrfHb27FkqKyut25e77EJ4eDhRUVG88cYbtS56XV5ezqxZswDo2LEj/fr1Y/Xq1Tbx/vjjj3z00UeMHDnyktdQG5VKdVnXf865loG//xyXLVtWY9+SkhJ++umnJvW6MiGaA3lO23Lkc/pi1qxZw++//27d3rhxIwUFBdbrNxqNNueE6qTRycmpxr08X0VFBT/99BMFBQV1jk1UkxbFOggKCmLhwoUkJiaSl5fH2LFjadeuHUePHuWDDz7gvvvusyYn9rZ69WpeeeUVoqOjCQoK4vfff+f1119HrVbXSHS0Wi033HAD999/P2VlZSxbtoyrrrrqgl0KFxMREcG//vUvFi1axP79+xk+fDjOzs5kZ2fz7rvv8uKLL3LHHXdctI7Zs2ezefNmRo8ezZQpU7j22msxmUz88MMPbNy4kby8PLy9vQFITExk9erVHD169JJ/Wa9Zs4bhw4fzz3/+kzFjxjBkyBBUKhXZ2dmsX7+egoIC61qKS5cuZcSIEYSHh3P33Xfz559/8vLLL+Pp6cncuXOv+L4AXHvttXz88ce88MILdOrUicDAQJvB73+nVqu56aabWLJkCRUVFXTu3JmPPvqIo0eP1th33759DB48mDlz5tQ5PiFaI3lON63n9IVoNBpuuOEGpk6dyqlTp1i2bBlarZZ7770XqF73dsaMGYwbN46QkBAqKyt5++23USqVta6de86JEycIDQ1l8uTJrFq1qk6xiWqSKNbRo48+SkhICElJScybNw8APz8/hg8fzq233tpg542IiGDfvn2sX7+eU6dO4enpyfXXX09qamqNgcl33XUX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GRkGQIm2CwAq/SFKhg9wZGiN4vbbb6e8vJzVq1fTrVs3Tp06xa5du/jtt99q3b+iooKsrCxGjhzJ448/zpo1azhx4gTTp0/HbDbz3HPPNfIViNbITX+IorCenI6q/h0993ubuiGNxFmzHRmaaCUkURSilcjOy8MY0dOmzKTtgvpIhoMiajxnz57l888/Z/fu3URERADQtWtXrr/+eus+CoWCV155he3bt7Nr1y5mz55NeXk5ffr04amnngJAq9WyZMkSxo8fz5w5c2jXrp1Drke0HsrCYkwDbH9vjUGdObIny0ERidZGup6FaCWCAwJQ556wKVPl5GNuBWMU27ZtS9u2bdm0aRNlZWUX3G/u3LlER0fzww8/MG3aNMrKynBzc7PZx93dndLSUr755puGDlsIzBpPVDn5NmXq3BOEBAY6KCLR2kiiKEQrERczgQ76w/juzMQjJx+fHXvxysyiVBfq6NAaXJs2bVi1ahWrV6+mffv2DBo0iMcee4zvv//eZr+JEycydepUunXrhr+/P5GRkXz11VesW7cOs9nMiRMnmD9/PgAFBQWOuBTRypTqQvHKzMJnx148cvLx3ZlJB/1hYsfHODo00UpIoihEK+Hv709y0jKinTV03JaB6owRY8ywJjfr2Wg02nxdrAXwStx+++388ssvbN68maioKHbv3s0111zDqlWrrPvodDqbY4YPH87SpUuZPn06rq6uhISEMHLkSACcnOz3+CwrK6tx3UIAVGk8McYMQ3XGSPieLKKdNSQnLZNZz6LRKCwWi8XRQQghWocdulEX/MxkruCO/ek1yufMmcPcuXMbJJ577rmH9PR0jh07hkKh4IMPPmDs2LE19rNYLBQUFODl5UVeXh49e/Zk3759XHfddXaJY+7cucybN69G+cZ+w1Apne1yjnOi9FvtWp8QomWTySxCiCbl+PHjqNVq67arq2uDnatnz55s2rTpkvspFAo6deoEwLp16/Dz8+Oaa66xWxyJiYk8+OCD1m2j0Yifn5/d6hdCiLqSRFEI0eAMBgNpa1M52K4SjRl0pUo0VYpa91Wr1TaJoj389ttvjBs3jmnTptGnTx/atWuHXq9nyZIl3HbbbRc9dunSpURFReHk5MT777/Ps88+y4YNG1AqlXaLz9XVtUETYoBCJwt6NzNbpt5NQLCWmLhY6b4UQlySJIpCiAZl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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot distributions per regions\n", + "fig_regions = cuisto.display.plot_regions(df_regions, cfg)\n", + "# specify which regions to plot\n", + "# fig_regions = hq.display.plot_regions(df_regions, cfg, names_list=[\"Rh9\", \"Sr9\", \"8Sp\"])\n", + "\n", + "# save as svg\n", + "# fig_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\nice_figure.svg\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hq", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/demo_notebooks/fibers_length_multi.html b/demo_notebooks/fibers_length_multi.html new file mode 100644 index 0000000..f18e2a7 --- /dev/null +++ b/demo_notebooks/fibers_length_multi.html @@ -0,0 +1,2142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Fibers length in multi animals - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo_notebooks/fibers_length_multi.ipynb b/demo_notebooks/fibers_length_multi.ipynb new file mode 100644 index 0000000..073eea7 --- /dev/null +++ b/demo_notebooks/fibers_length_multi.ipynb @@ -0,0 +1,372 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Fibers length in multi animals\n", + "This example uses synthetic data to showcase how `histoquant` can be used in a [pipeline](../guide-pipeline.html).\n", + "\n", + "Annotations measurements should be exported from QuPath, following the required [directory structure](../guide-pipeline.html#directory-structure).\n", + "\n", + "Alternatively, you can merge all your CSV files yourself, one per animal, adding an animal ID to each table. Those can be processed with the `histoquant.process.process_animal()` function, in a loop, collecting the results at each iteration and finally concatenating the results. Finally, those can be used with `display` module. See the API reference for the [`process` module](../api-process.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import cuisto" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Full path to your configuration file, edited according to your need beforehand\n", + "config_file = \"../../resources/demo_config_multi.toml\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Files\n", + "wdir = \"../../resources/multi\"\n", + "animals = [\"mouse0\", \"mouse1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# get configuration\n", + "cfg = cuisto.Config(config_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Processing mouse1: 100%|██████████| 2/2 [00:00<00:00, 15.66it/s]\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NamehemisphereArea µm^2Area mm^2length µmlength mmdensity µm^-1density mm^-1coverage indexrelative countrelative densitychannelanimal
0ACVIIContra.9099.040.009099468.03810.4680380.05143851438.18468824.075030.000640.022168marker3mouse0
1ACVIIContra.9099.040.0090994260.48444.2604840.468234468234.4950681994.9057620.00190.056502marker2mouse0
2ACVIIContra.9099.040.0090995337.71035.337710.586623586623.456983131.2260690.0101040.242734marker1mouse0
3ACVIIIpsi.4609.900.0046100.00.00.00.00.00.00.0marker3mouse0
4ACVIIIpsi.4609.900.0046100.00.00.00.00.00.00.0marker2mouse0
5ACVIIIpsi.4609.900.0046100.00.00.00.00.00.00.0marker1mouse0
6ACVIIboth13708.940.013709468.03810.4680380.03414134141.08603615.9793290.0002840.011001marker3mouse0
7ACVIIboth13708.940.0137094260.48444.2604840.310781310781.4608571324.0795660.0009340.030688marker2mouse0
8ACVIIboth13708.940.0137095337.71035.337710.38936389359.8119182078.2898780.005340.142623marker1mouse0
9AMBContra.122463.800.12246430482.781530.4827820.248913248912.5888637587.5480590.0417120.107271marker3mouse0
\n", + "
" + ], + "text/plain": [ + " Name hemisphere Area µm^2 Area mm^2 length µm length mm \\\n", + "0 ACVII Contra. 9099.04 0.009099 468.0381 0.468038 \n", + "1 ACVII Contra. 9099.04 0.009099 4260.4844 4.260484 \n", + "2 ACVII Contra. 9099.04 0.009099 5337.7103 5.33771 \n", + "3 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 \n", + "4 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 \n", + "5 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 \n", + "6 ACVII both 13708.94 0.013709 468.0381 0.468038 \n", + "7 ACVII both 13708.94 0.013709 4260.4844 4.260484 \n", + "8 ACVII both 13708.94 0.013709 5337.7103 5.33771 \n", + "9 AMB Contra. 122463.80 0.122464 30482.7815 30.482782 \n", + "\n", + " density µm^-1 density mm^-1 coverage index relative count relative density \\\n", + "0 0.051438 51438.184688 24.07503 0.00064 0.022168 \n", + "1 0.468234 468234.495068 1994.905762 0.0019 0.056502 \n", + "2 0.586623 586623.45698 3131.226069 0.010104 0.242734 \n", + "3 0.0 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 0.0 \n", + "5 0.0 0.0 0.0 0.0 0.0 \n", + "6 0.034141 34141.086036 15.979329 0.000284 0.011001 \n", + "7 0.310781 310781.460857 1324.079566 0.000934 0.030688 \n", + "8 0.38936 389359.811918 2078.289878 0.00534 0.142623 \n", + "9 0.248913 248912.588863 7587.548059 0.041712 0.107271 \n", + "\n", + " channel animal \n", + "0 marker3 mouse0 \n", + "1 marker2 mouse0 \n", + "2 marker1 mouse0 \n", + "3 marker3 mouse0 \n", + "4 marker2 mouse0 \n", + "5 marker1 mouse0 \n", + "6 marker3 mouse0 \n", + "7 marker2 mouse0 \n", + "8 marker1 mouse0 \n", + "9 marker3 mouse0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# get distributions per regions\n", + "df_regions, _, _ = cuisto.process.process_animals(\n", + " wdir, animals, cfg, compute_distributions=False\n", + ")\n", + "\n", + "# have a look\n", + "display(df_regions.head(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAApQAAAH0CAYAAACD0737AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3wT9f/A8ddlNOlM9y5toS177z1ki4jyFQVRpigKisgWWTIUVHAByhZEBBVQEUERBNnI3qtQRvdKZ9ok9/ujP4KhLaNNaaGf5+PRB9zl7nPvS9vrO58pybIsIwiCIAiCIAhFpCjtAARBEARBEIRHm0goBUEQBEEQhGIRCaUgCIIgCIJQLCKhFARBEARBEIpFJJSCIAiCIAhCsYiEUhAEQRAEQSgWkVAKgiAIgiAIxSISSkEQBEEQBKFYREIpCIIgCIIgFItIKO9iypQpSJJEQkJCaYdisXz5ciRJ4sqVKyVSfv/+/XFyciqRsgVBEEqCeFYLBQkJCaF///6lHUa5IRJK4bGUnZ3N3Llzady4MTqdDq1WS0REBMOGDeP8+fMleu2ZM2eyYcOGEr2GIAjCo06SJIYNG1baYQg2IhLKR8xLL71EVlYWwcHBpR1KmZWQkECLFi0YOXIk3t7eTJs2jS+//JIePXrw888/U6NGjRK9vkgoBUEQz+rSd+7cORYtWlTaYZQbqtIOQHgwSqUSpVJZ2mEUiyzLZGdnY29vXyLl9+/fnyNHjvDDDz/Qs2dPq9fef/993n333RK5blFkZGTg6OhY2mEIgmBj4lld+jQaTWmHUK6IGsr7kJKSQv/+/XF1dUWn0zFgwAAyMzPzHbdq1Srq16+Pvb097u7uvPDCC1y7ds3qmDZt2lCjRg2OHz9O69atcXBwICwsjB9++AGAv//+m8aNG2Nvb0/lypX5888/rc4vqF/OoUOH6NSpE56entjb2xMaGsrAgQMtr1+5cgVJkvjoo4+YO3cuwcHB2Nvb07p1a06ePFngPd+4cYMePXrg5OSEl5cXo0aNwmQyWR1jNpuZN28e1atXR6vV4uPjw6uvvkpycrLVcSEhIXTr1o0tW7bQoEED7O3t+eqrryzv7YgRIwgKCkKj0RAWFsaHH36I2Wy2KiM6OpqzZ8+Sm5tbYLy37N+/n02bNjFo0KB8ySTkPWA++ugjq31//fUXLVu2xNHREVdXV55++mnOnDljdcytPloXL16868+CJElkZGSwYsUKJElCkiRLH55bZZw+fZo+ffrg5uZGixYtADh+/Dj9+/enYsWKaLVafH19GThwIImJiXe9X0EQbhPP6kfnWV2QHTt2IEkS33//PRMmTMDX1xdHR0e6d++e7/tz4cIFevbsia+vL1qtlsDAQF544QVSU1Ot7kf0oXyIZKFQkydPlgG5bt268rPPPivPnz9fHjx4sAzIY8aMsTp2+vTpsiRJ8vPPPy/Pnz9fnjp1quzp6SmHhITIycnJluNat24t+/v7y0FBQfLo0aPlzz//XK5WrZqsVCrlNWvWyL6+vvKUKVPkefPmyQEBAbJOp5P1er3l/GXLlsmAHBkZKcuyLMfGxspubm5yRESEPGfOHHnRokXyu+++K1etWtVyTmRkpAzINWvWlENCQuQPP/xQnjp1quzu7i57eXnJMTExlmP79esna7VauXr16vLAgQPlBQsWyD179pQBef78+Vb3PHjwYFmlUsmvvPKKvHDhQnns2LGyo6Oj3LBhQzknJ8dyXHBwsBwWFia7ubnJ48aNkxcuXChv375dzsjIkGvVqiV7eHjIEyZMkBcuXCi//PLLsiRJ8ltvvWV1rX79+lndd2EmTJggA/LOnTvvetwtf/zxh6xSqeSIiAh59uzZlu+bm5ub1bXu92dh5cqVskajkVu2bCmvXLlSXrlypbxnzx6rMqpVqyY//fTT8vz58+Uvv/xSlmVZ/uijj+SWLVvK06ZNk7/++mv5rbfeku3t7eVGjRrJZrP5vu5FEMor8ax+9J7VsizLgPzGG29Ytrdv3265/1q1asmffPKJPG7cOFmr1coRERFyZmamLMuybDAY5NDQUNnf31+ePn26vHjxYnnq1Klyw4YN5StXrljdT79+/e4Zh2AbIqG8i1sPqYEDB1rtf+aZZ2QPDw/L9pUrV2SlUinPmDHD6rgTJ07IKpXKan/r1q1lQF69erVl39mzZ2VAVigU8r59+yz7t2zZIgPysmXLLPvufEitX79eBuSDBw8Weh+3HlL29vby9evXLfv3798vA/Lbb79t2XfrYTBt2jSrMurWrSvXr1/fsr1r1y4ZkL/99lur437//fd8+4ODg2VA/v33362Off/992VHR0f5/PnzVvvHjRsnK5VKOSoqKl9c93pIPfPMMzJg9YfhburUqSN7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3qyqau4HmkajUS9evOg6Z8aMGaqvr69qsVhKPfaykJiYqALq+vXrVVVV5bnlw9//8XM6nWp4eLj67rvvuo6lpqaqRqNR/fbbb1VVVdVDhw6pgLp9+3bXOb/88ouqKIqakJBQarGXN61bt1aff/5512uHw6FWrVpVjYuLK8OoSkZluteCkt+pwpHP78KRPKFgKkWX9185HA7mz59PZmYm7dq1Y+fOndhsNu666y7XOXXr1iUqKorNmzcDsHnzZho1akRYWJjrnB49emA2mzl48GCp30NZuLqX+9U9huW5FdypU6e4ePGi2zPz8/OjTZs2bs/M39+fli1bus6566670Gg0bN26tdRjLg+sVis7d+50e24ajYa77rrL9dwqisp0r8VBfqfyRz6/C0byhMLJ117eFcH+/ftp164dOTk5mEwmFi1aRP369dmzZw8GgwF/f3+388PCwrh48SIAFy9edPshufr+1fcqOqfTyejRo7njjjto2LAhkHvf8twK5uo95/VM/vrMQkND3d7X6XQEBgZWymcGcPnyZRwOR57P7fDhw2UUVcmoTPdaHOR36tbk8zv/JE8omkqTUNapU4c9e/aQlpbG999/z5NPPsn69evLOqzbwvPPP8+BAwf4448/yjoUIYQQBSCf3/kneULRVJoub4PBQM2aNWnRogVxcXE0adKE//znP4SHh2O1WklNTXU7/9KlS4SHhwMQHh5+3Wyuq6+vnlNRjRw5kqVLl7J27VoiIiJcx+W5FdzVe87rmfz1mSUmJrq9b7fbuXLlSqV8ZgDBwcFotdqbPreKojLda3GQ36mbk8/vgpE8oWgqTUL5d06nE4vFQosWLdDr9axevdr13pEjR4iPj6ddu3YAtGvXjv3797t9KK1atQpfX1/q169f6rGXBlVVGTlyJIsWLWLNmjXExsa6vS/PreBiY2MJDw93e2Zms5mtW7e6PbPU1FR27tzpOmfNmjU4nU7atGlT6jGXBwaDgRYtWrg9N6fTyerVq13PraKoTPdaHOR3Km/y+V08JE8ooLKeFVQaXn75ZXX9+vXqqVOn1H379qkvv/yyqiiKunLlSlVVc5cDiIqKUtesWaPu2LFDbdeundquXTvX9VeXA+jevbu6Z88e9ddff1VDQkIq9HIAw4cPV/38/NR169apFy5ccH1lZWW5zpHndr309HR19+7d6u7d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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAApMAAAH0CAYAAABhD6aCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC7bklEQVR4nOzdd3hURdvA4d+WZFM2jSSQQhqE0LtIkaoIUboIiKI0G9hQAQ1SpEYRBAvFQrVTpBhAioAiHSEU6TUhJLRAlrRNsnu+P/Kxuia0ZJNd3jz3dZ3rdc/OmXkm0fM+mXNmRqUoioIQQgghhBBFoLZ3AEIIIYQQ4v4lyaQQQgghhCgySSaFEEIIIUSRSTIphBBCCCGKTJJJIYQQQghRZJJMCiGEEEKIIpNkUgghhBBCFJkkk0IIIYQQosgkmRRCCCGEEEUmyeRtvP/++6hUKq5cuWLvUCzmz5+PSqXi7NmzJVJ/v3790Ov1JVK3EEKUBLlXi8KEh4fTr18/e4dRJkgyKf4nZWdnM23aNBo3boyXlxcuLi5ERUXx6quvcvz48RJte9KkSSxfvrxE2xBCiPudSqXi1VdftXcYwgYkmbzPPPvss2RlZREWFmbvUBzWlStXaN68OW+99Rbly5dn3LhxzJgxg65du7Jy5Upq1apVou1LMimEkHu1/R07doyvvvrK3mGUCVp7ByDujUajQaPR2DuMYlEUhezsbFxdXUuk/n79+rFv3z6WLFlC9+7drb4bP3487733Xom0WxQZGRm4u7vbOwwhhI3Jvdr+dDqdvUMoM2Rk8i5cv36dfv364e3tjZeXF/379yczM7NAuW+//ZaGDRvi6upKuXLleOqpp0hMTLQq07p1a2rVqsWBAwdo1aoVbm5uREZGsmTJEgB+//13GjdujKurK1WrVmXDhg1W1xf2Hs6ePXto3749fn5+uLq6EhERwYABAyzfnz17FpVKxZQpU5g2bRphYWG4urrSqlUrDh06VGifk5KS6Nq1K3q9Hn9/f4YOHYrJZLIqYzabmT59OjVr1sTFxYUKFSrw0ksvce3aNaty4eHhdOzYkbVr1/LAAw/g6urKF198YfnZDhkyhJCQEHQ6HZGRkXz44YeYzWarOpKTkzl69Ci5ubmFxnvTzp07WbVqFQMHDiyQSEL+zWXKlClW5zZu3EiLFi1wd3fH29ubLl26cOTIEasyN9/JOnny5G3/XVCpVGRkZLBgwQJUKhUqlcryzs7NOg4fPszTTz+Nj48PzZs3B+DAgQP069ePSpUq4eLiQkBAAAMGDODq1au37a8Q4h9yr75/7tWF2bx5MyqVip9++okRI0YQEBCAu7s7nTt3LvD7OXHiBN27dycgIAAXFxcqVqzIU089RVpamlV/5J3JUqKIWxozZowCKPXr11eeeOIJZebMmcrzzz+vAMrw4cOtyk6YMEFRqVRKr169lJkzZypjx45V/Pz8lPDwcOXatWuWcq1atVKCgoKUkJAQZdiwYcpnn32m1KhRQ9FoNMqPP/6oBAQEKO+//74yffp0JTg4WPHy8lIMBoPl+nnz5imAcubMGUVRFOXixYuKj4+PEhUVpXz00UfKV199pbz33ntK9erVLdecOXNGAZTatWsr4eHhyocffqiMHTtWKVeunOLv76+kpKRYyvbt21dxcXFRatasqQwYMECZNWuW0r17dwVQZs6cadXn559/XtFqtcoLL7ygzJ49W3nnnXcUd3d3pVGjRkpOTo6lXFhYmBIZGan4+Pgo7777rjJ79mxl06ZNSkZGhlKnTh3F19dXGTFihDJ79mzlueeeU1QqlfLGG29YtdW3b1+rft/KiBEjFED5448/blvupvXr1ytarVaJiopSJk+ebPm9+fj4WLV1t/8ufPPNN4pOp1NatGihfPPNN8o333yjbNu2zaqOGjVqKF26dFFmzpypzJgxQ1EURZkyZYrSokULZdy4ccqXX36pvPHGG4qrq6vy4IMPKmaz+a76IkRZJffq++9erSiKAiivvPKK5fOmTZss/a9Tp47y8ccfK++++67i4uKiREVFKZmZmYqiKIrRaFQiIiKUoKAgZcKECcrXX3+tjB07VmnUqJFy9uxZq/707dv3jnGI4pNk8jZu3qAGDBhgdb5bt26Kr6+v5fPZs2cVjUajTJw40arcwYMHFa1Wa3W+VatWCqB8//33lnNHjx5VAEWtVis7duywnF+7dq0CKPPmzbOc++8NatmyZQqg7N69+5b9uHmDcnV1Vc6fP285v3PnTgVQ3nzzTcu5mzeCcePGWdVRv359pWHDhpbPW7ZsUQDlu+++syr366+/FjgfFhamAMqvv/5qVXb8+PGKu7u7cvz4cavz7777rqLRaJSEhIQCcd3pBtWtWzcFsPo/hdupV6+eUr58eeXq1auWc/v371fUarXy3HPPWc7d7b8LiqIo7u7uhd7AbtbRu3fvAt/dvEn+2w8//HBPibEQZZXcq/9xv9yrFeXWyWRwcLBVYr5o0SIFUD755BNFURRl3759CqAsXrz4tvVLMll65DH3XXj55ZetPrdo0YKrV69iMBgA+PnnnzGbzfTs2ZMrV65YjoCAAKpUqcKmTZusrtfr9Tz11FOWz1WrVsXb25vq1avTuHFjy/mb/3z69Olbxubt7Q1AXFzcHR8rdO3aleDgYMvnBx98kMaNG7N69eq76vO/41i8eDFeXl48+uijVn1u2LAher2+QJ8jIiJo37691bnFixfTokULfHx8rOpo27YtJpOJP/74w1J2/vz5KIpCeHj4bft483fi4eFx23KQ/zgmPj6efv36Ua5cOcv5OnXq8Oijj971z+Xf/y7cjf/WAVi9k5Sdnc2VK1do0qQJAHv37r3ruoUoy+Reff/cq2/nueees7qHP/nkkwQGBlr67+XlBcDatWsLfY1BlD6ZgHMXQkNDrT77+PgAcO3aNTw9PTlx4gSKolClSpVCr3dycrL6XLFiRVQqldU5Ly8vQkJCCpy72c6ttGrViu7duzN27FimTZtG69at6dq1K08//XSBl48Liy8qKopFixZZnXNxccHf39/qnI+Pj1UcJ06cIC0tjfLlyxca16VLl6w+R0REFChz4sQJDhw4UKCtW9VxNzw9PQG4ceOG5eZ9K+fOnQPy/w/iv6pXr87atWsLTJC5078Ld6Own0Vqaipjx47lxx9/LNDvf78DJIS4NblX3z/36tv5b/9VKhWRkZGW908jIiJ46623+Pjjj/nuu+9o0aIFnTt3pk+fPpbfhShdkkzehVvNyFMUBch/uVmlUrFmzZpCy/53Ydlb1XendgqjUqlYsmQJO3bs4JdffmHt2rUMGDCAqVOnsmPHjiItans3MxDNZjPly5fnu+++K/T7/950CpsNaDabefTRRxk+fHihdURFRd1FtNaqVasGwMGDB2nRosU9X38nRfkd/VdhP4uePXuybds2hg0bRr169dDr9ZjNZqKjowu84C6EKJzcqwty1Ht1cU2dOpV+/fqxYsUK1q1bx+uvv05sbCw7duygYsWKpR5PWSfJpA1UrlwZRVGIiIiwy39UAE2aNKFJkyZMnDiR77//nmeeeYYff/yR559/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "figs_regions = cuisto.display.plot_regions(df_regions, cfg)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hq", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/guide-create-pyramids.html b/guide-create-pyramids.html new file mode 100644 index 0000000..4b9fb88 --- /dev/null +++ b/guide-create-pyramids.html @@ -0,0 +1,1416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Create pyramidal OME-TIFF - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Create pyramidal OME-TIFF#

+

This page will guide you to use the pyramid-creator package, in the event the CZI file does not work directly in QuPath. The script will generate pyramids from OME-TIFF files exported from ZEN.

+
+

Tip

+

pyramid-creator can also pyramidalize images using Python only with the --no-use-qupath option.

+
+

This Python script uses QuPath under the hood, via a companion script called createPyramids.groovy. It will find the OME-TIFF files and make QuPath run the groovy script on it, in console mode (without graphical user interface).

+

This script is standalone, eg. it does not rely on the cuisto package. But installing the later makes sure all dependencies are installed (namely typer and tqdm with the QuPath backend and quite a few more for the Python backend).

+

pyramid-creator moved to a standalone package that you can find here with installation and usage instructions.

+

Installation#

+

You will find instructions on the dedicated project page over at Github.

+

For reference :

+

You will need conda, follow those instructions to install it.

+

Then, create a virtual environment if you didn't already (pyramid-creator can be installed in the environment for cuisto) and install the pyramid-creator package. +

conda create -c conda-forge -n cuisto-env python=3.12  # not required if you already create an environment
+conda activate cuisto-env
+pip install pyramid-creator
+
+To use the Python backend (with tifffile), replace the last line with : +
pip install pyramid-creator[python-backend]
+
+To use the QuPath backend, a working QuPath installation is required, and the pyramid-creator command needs to be aware of its location.

+

To do so, first, install QuPath. By default, it will install in ~\AppData\QuPath-0.X.Y. In any case, note down the installation location.

+

Then, you have several options : +- Create a file in your user directory called "QUPATH_PATH" (without extension), containing the full path to the QuPath console executable. In my case, it reads : C:\Users\glegoc\AppData\Local\QuPath-0.5.1\QuPath-0.5.1 (console).exe. Then, the pyramid-creator script will read this file to find the QuPath executable. +- Specify the QuPath path as an option when calling the command line interface (see the Usage section) : +

pyramid-creator /path/to/your/images --qupath-path "C:\Users\glegoc\AppData\Local\QuPath-0.5.1\QuPath-0.5.1 (console).exe"
+
+- Specify the QuPath path as an option when using the package in a Python script (see the Usage section) : +
from pyramid_creator import pyramidalize_directory
+pyramidalize_directory("/path/to/your/images/", qupath_path="C:\Users\glegoc\AppData\Local\QuPath-0.5.1\QuPath-0.5.1 (console).exe")
+
+- If you're using Windows, using QuPath v0.6.0, v0.5.1 or v0.5.0 and chose the default installation location, pyramid-creator should find it automatically and write it down in the "QUPATH_PATH" file by itself.

+

Export CZI to OME-TIFF#

+

OME-TIFF is a specification of the TIFF image format. It specifies how the metadata should be written to the file to be interoperable between softwares. ZEN can export to OME-TIFF so you don't need to pay attention to metadata. Therefore, you won't need to specify pixel size and channels names and colors as it will be read directly from the OME-TIFF files.

+
+
    +
  1. Open your CZI file in ZEN.
  2. +
  3. Open the "Processing tab" on the left panel.
  4. +
  5. Under method, choose Export/Import > OME TIFF-Export.
  6. +
  7. In Parameters, make sure to tick the "Show all" tiny box on the right.
  8. +
  9. The following parameters should be used (checked), the other should be unchecked :
      +
    • Use Tiles
    • +
    • Original data ⚠ "Convert to 8 Bit" should be UNCHECKED ⚠
    • +
    • OME-XML Scheme : 2016-06
    • +
    • Use full set of dimensions (unless you want to select slices and/or channels)
    • +
    +
  10. +
  11. In Input, choose your file
  12. +
  13. Go back to Parameters to choose the output directory and file prefix. "_s1", "_s2"... will be appended to the prefix.
  14. +
  15. Back on the top, click the "Apply" button.
  16. +
+
+

The OME-TIFF files should be ready to be pyramidalized with the create_pyramids.py script.

+

Usage#

+

See the instructions on the dedicated project page over at Github.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide-install-abba.html b/guide-install-abba.html new file mode 100644 index 0000000..01f425c --- /dev/null +++ b/guide-install-abba.html @@ -0,0 +1,1629 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Install ABBA - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

Install ABBA#

+

You can head to the ABBA documentation for installation instructions. You'll see that a Windows installer is available. While it might be working great, I prefer to do it manually step-by-step to make sure everything is going well.

+

You will find below installation instructions for the regular ABBA Fiji plugin, which proposes only the mouse and rat brain atlases. To be able to use the Brainglobe atlases, you will need the Python version. The two can be installed alongside each other.

+

ABBA Fiji#

+

Install Fiji#

+

Install the "batteries-included" distribution of ImageJ, Fiji, from the official website.

+
+

Warning

+

Extract Fiji somewhere you have write access, otherwise Fiji will not be able to download and install plugins. In other words, put the folder in your User directory and not in C:\, C:\Program Files and the like.

+
+
    +
  1. Download the zip archive and extract it somewhere relevant.
  2. +
  3. Launch ImageJ.exe.
  4. +
+

Install the ABBA plugin#

+

We need to add the PTBIOP update site, managed by the bio-imaging and optics facility at EPFL, that contains the ABBA plugin.

+
    +
  1. In Fiji, head to Help > Update...
  2. +
  3. In the ImageJ updater window, click on Manage Update Sites. Look up PTBIOP, and click on the check box. Apply and Close, and Apply Changes. +This will download and install the required plugins. Restart ImageJ as suggested.
  4. +
  5. In Fiji, head to Plugins > BIOP > Atlas > ABBA - ABBA start, or simply type abba start in the search box.
    +Choose the "Adult Mouse Brain - Allen Brain Atlas V3p1". It will download this atlas and might take a while, depending on your Internet connection.
  6. +
+

Install the automatic registration tools#

+

ABBA can leverage the elastix toolbox for automatic 2D in-plane registration.

+
    +
  1. You need to download it here, which will redirect you to the Github releases page (5.2.0 should work).
  2. +
  3. Download the zip archive and extract it somewhere relevant.
  4. +
  5. In Fiji, in the search box, type "set and check" and launch the "Set and Check Wrappers" command. Set the paths to "elastix.exe" and "transformix.exe" you just downloaded.
  6. +
+

ABBA should be installed and functional ! You can check the official documentation for usage instructions and some tips here.

+

ABBA Python#

+

Brainglobe is an initiative aiming at providing interoperable, model-agnostic Python-based tools for neuroanatomy. They package various published volumetric anatomical atlases of different species (check the list), including the Allen Mouse brain atlas (CCFv3, ref.) and a 3D version of the Allen mouse spinal cord atlas (ref).

+

To be able to leverage those atlases, we need to make ImageJ and Python be able to talk to each other. This is the purpose of abba_python, that will install ImageJ and its ABBA plugins inside a python environment, with bindings between the two worlds.

+

Install conda#

+

If not done already, follow those instructions to install conda.

+

Install abba_python in a virtual environment#

+
    +
  1. Open a terminal (PowerShell).
  2. +
  3. Create a virtual environment with Python 3.10, OpenJDK and PyImageJ : +
    conda create -c conda-forge -n abba_python python=3.10 openjdk=11 maven pyimagej notebook
    +
  4. +
  5. Install the latest functional version of abba_python with pip : +
    pip install abba-python==0.9.6.dev0
    +
  6. +
  7. Restart the terminal and activate the new environment : +
    conda activate abba_python
    +
  8. +
  9. Download the Brainglobe atlas you want (eg. Allen mouse spinal cord) : +
    brainglobe install -a allen_cord_20um
    +
  10. +
  11. Launch an interactive Python shell : +
    ipython
    +
    +You should see the IPython prompt, that looks like this : +
    In [1]:
    +
  12. +
  13. Import abba_python and launch ImageJ from Python : +
    from abba_python import abba
    +abba.start_imagej()
    +
    +The first launch needs to initialize ImageJ and install all required plugins, which takes a while (>5min).
  14. +
  15. Use ABBA as the regular Fiji version ! The main difference is that the dropdown menu to select which atlas to use is populated with the Brainglobe atlases.
  16. +
+
+

Tip

+

Afterwards, to launch ImageJ from Python and do some registration work, you just need to launch a terminal (PowerShell), and do steps 4., 6., and 7.

+
+

Install the automatic registration tools#

+

You can follow the same instructions as the regular Fiji version. You can do it from either the "normal" Fiji or the ImageJ instance launched from Python, they share the same configuration files. Therefore, if you already did it in regular Fiji, elastix should already be set up and ready to use in ImageJ from Python.

+

Troubleshooting#

+

JAVA_HOME errors#

+

Unfortunately on some computers, Python does not find the Java virtual machine even though it should have been installed when installing OpenJDK with conda. This will result in an error mentionning "java.dll" and suggesting to check the JAVA_HOME environment variable.

+

The only fix I could find is to install Java system-wide. You can grab a (free) installer on Adoptium, choosing JRE 17.X for your platform.
+During the installation :

+
    +
  • choose to install "just for you",
  • +
  • enable "Modify PATH variable" as well as "Set or override JAVA_HOME" variable.
  • +
+

Restart the terminal and try again. Now, ImageJ should use the system-wide Java and it should work.

+

ABBA QuPath extension#

+

To import registered regions in your QuPath project and be able to convert objects' coordinates in atlas space, the ABBA QuPath extension is required.

+
    +
  1. In QuPath, head to Edit > Preferences. In the Extension tab, set your QuPath user directory to a local directory (usually C:\Users\USERNAME\QuPath\v0.X.Y).
  2. +
  3. Create a folder named extensions in your QuPath user directory.
  4. +
  5. Download the latest ABBA extension for QuPath from GitHub (choose the file qupath-extension-abba-x.y.z.zip).
  6. +
  7. Uncompress the archive and copy all .jar files into the extensions folder in your QuPath user directory.
  8. +
  9. Restart QuPath. Now, in Extensions, you should have an ABBA entry.
  10. +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide-pipeline.html b/guide-pipeline.html new file mode 100644 index 0000000..b5009be --- /dev/null +++ b/guide-pipeline.html @@ -0,0 +1,1491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Pipeline - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Pipeline#

+

While you can use QuPath and cuisto functionalities as you see fit, there exists a pipeline version of those. It requires a specific structure to store files (so that the different scripts know where to look for data). It also requires that you have detections stored as geojson files, which can be achieved using a pixel classifier and further segmentation (see here) for example.

+

Purpose#

+

This is especially useful to perform quantification for several animals at once, where you'll only need to specify the root directory and the animals identifiers that should be pooled together, instead of having to manually specify each detections and annotations files.

+

Three main scripts and function are used within the pipeline :

+
    +
  • exportPixelClassifierProbabilities.groovy to create prediction maps of objects of interest
  • +
  • segment_image.py to segment those maps and create geojson files to be imported back to QuPath as detections
  • +
  • pipelineImportExport.groovy to :
      +
    • clear all objects
    • +
    • import ABBA regions
    • +
    • mirror regions names
    • +
    • import geojson detections (from $folderPrefix$segmentation/$segTag$/geojson)
    • +
    • add measurements to detections
    • +
    • add atlas coordinates to detections
    • +
    • add hemisphere to detections' parents
    • +
    • add regions measurements
        +
      • count for punctal objects
      • +
      • cumulated length for lines objects
      • +
      +
    • +
    • export detections measurements
        +
      • as CSV for punctual objects
      • +
      • as JSON for lines
      • +
      +
    • +
    • export annotations as CSV
    • +
    +
  • +
+

Directory structure#

+

Following a specific directory structure ensures subsequent scripts and functions can find required files. The good news is that this structure will mostly be created automatically using the segmentation scripts (from QuPath and Python), as long as you stay consistent filling the parameters of each script. +The structure expected by the groovy all-in-one script and cuisto batch-process function is the following :

+
some_directory/
+    ├──AnimalID0/  
+    │   ├── animalid0_qupath/
+    │   └── animalid0_segmentation/  
+    │       └── segtag/  
+    │           ├── annotations/  
+    │           ├── detections/  
+    │           ├── geojson/  
+    │           └── probabilities/  
+    ├──AnimalID1/  
+    │   ├── animalid1_qupath/
+    │   └── animalid1_segmentation/  
+    │       └── segtag/  
+    │           ├── annotations/  
+    │           ├── detections/  
+    │           ├── geojson/  
+    │           └── probabilities/  
+
+
+

Info

+

Except the root directory and the QuPath project, the rest is automatically created based on the parameters provided in the different scripts. Here's the description of the structure and the requirements :

+
+
    +
  • animalid0 should be a convenient animal identifier.
  • +
  • The hierarchy must be followed.
  • +
  • The experiment root directory, AnimalID0, can be anything but should correspond to one and only one animal.
  • +
  • Subsequent animalid0 should be lower case.
  • +
  • animalid0_qupath can be named as you wish in practice, but should be the QuPath project.
  • +
  • animalid0_segmentation should be called exactly like this -- replacing animalid0 with the actual animal ID. It will be created automatically with the exportPixelClassifierProbabilities.groovy script.
  • +
  • segtag corresponds to the type of segmentation (cells, fibers...). It is specified in the exportPixelClassifierProbabilities script. It could be anything, but to recognize if the objects are polygons (and should be counted per regions) or polylines (and the cumulated length should be measured), there are some hardcoded keywords in the segment_images.py and pipelineImportExport.groovy scripts :
      +
    • Cells-like when you need measurements related to its shape (area, circularity...) : cells, cell, polygons, polygon
    • +
    • Cells-like when you consider them as punctual : synapto, synaptophysin, syngfp, boutons, points
    • +
    • Fibers-like (polylines) : fibers, fiber, axons, axon
    • +
    +
  • +
  • annotations contains the atlas regions measurements as TSV files.
  • +
  • detections contains the objects atlas coordinates and measurements as CSV files (for punctal objects) or JSON (for polylines objects).
  • +
  • geojson contains objects stored as geojson files. They could be generated with the pixel classifier prediction map segmentation.
  • +
  • probabilities contains the prediction maps to be segmented by the segment_images.py script.
  • +
+
+

Tip

+

You can see an example minimal directory structure with only annotations stored in resources/multi.

+
+

Usage#

+
+

Tip

+

Remember that this is merely an example pipeline, you can shortcut it at any points, as long as you end up with TSV files following the requirements for cuisto.

+
+
    +
  1. Create a QuPath project.
  2. +
  3. Register your images on an atlas with ABBA and export the registration back to QuPath.
  4. +
  5. Use a pixel classifier and export the prediction maps with the exportPixelClassifierProbabilities.groovy script. You need to get a pixel classifier or create one.
  6. +
  7. Segment those maps with the segment_images.py script to generate the geojson files containing the objects of interest.
  8. +
  9. Run the pipelineImportExport.groovy script on your QuPath project.
  10. +
  11. Set up your configuration files.
  12. +
  13. Then, analysing your data with any number of animals should be as easy as executing those lines in Python (either from IPython directly or in a script to easily run it later) :
  14. +
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
import cuisto
+
+# Parameters
+wdir = "/path/to/some_directory"
+animals = ["AnimalID0", "AnimalID1"]
+config_file = "/path/to/your/config.toml"
+output_format = "h5"  # to save the quantification values as hdf5 file
+
+# Processing
+cfg = cuisto.Config(config_file)
+df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animals(
+    wdir, animals, cfg, out_fmt=output_format
+)
+
+# Display
+cuisto.display.plot_regions(df_regions, cfg)
+cuisto.display.plot_1D_distributions(dfs_distributions, cfg, df_coordinates=df_coordinates)
+cuisto.display.plot_2D_distributions(df_coordinates, cfg)
+
+
+

Tip

+

You can see a live example in this demo notebook.

+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide-prepare-qupath.html b/guide-prepare-qupath.html new file mode 100644 index 0000000..cadab50 --- /dev/null +++ b/guide-prepare-qupath.html @@ -0,0 +1,1584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Prepare QuPath data - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

Prepare QuPath data#

+

cuisto uses some QuPath classifications concepts, make sure to be familiar with them with the official documentation. Notably, we use the concept of primary classification and derived classification : an object classfied as First: second is of classification First and of derived classification second.

+

QuPath requirements#

+

cuisto assumes a specific way of storing regions and objects information in the TSV files exported from QuPath. Note that only one primary classification is supported, but you can have any number of derived classifications.

+

Detections#

+

Detections are the objects of interest. Their information must respect the following :

+
    +
  • Atlas coordinates should be in millimetres (mm) and stored as Atlas_X, Atlas_Y, Atlas_Z. They correspond, respectively, to the anterio-posterior (rostro-caudal) axis, the inferio-superior (dorso-ventral) axis and the left-right (medio-lateral) axis.
  • +
  • They must have a derived classification, in the form Primary: second. Primary would be an object type (cells, fibers, ...), the second one would be a biological marker or a detection channel (fluorescence channel name), for instance : Cells: some marker, or Fibers: EGFP.
  • +
  • The classification must match exactly the corresponding measurement in the annotations (see below).
  • +
+

Annotations#

+

Annotations correspond to the atlas regions. Their information must respect the following :

+
    +
  • They should be imported with the ABBA extension as acronyms and splitting left/right. Therefore, the annotation name should be the region acronym and its classification should be formatted as Hemisphere: acronym (for ex. Left: PAG).
  • +
  • Measurements names should be formatted as :
    +Primary classification: derived classification measurement name.
    +For instance :
      +
    • if one has cells with some marker and count them in each atlas regions, the measurement name would be :
      +Cells: some marker Count.
    • +
    • if one segments fibers revealed in the EGFP channel and measures the cumulated length in µm in each atlas regions, the measurement name would be :
      +Fibers: EGFP Length µm.
    • +
    +
  • +
  • Any number of markers or channels are supported.
  • +
+

Measurements#

+

Metrics supported by cuisto#

+

While you're free to add any measurements as long as they follow the requirements, keep in mind that for atlas regions quantification, cuisto will only compute, pool and average the following metrics :

+
    +
  • the base measurement itself
      +
    • if "µm" is contained in the measurement name, it will also be converted to mm (\(\div\)1000)
    • +
    +
  • +
  • the base measurement divided by the region area in µm² (density in something/µm²)
  • +
  • the base measurement divided by the region area in mm² (density in something/mm²)
  • +
  • the squared base measurement divided by the region area in µm² (could be an index, in weird units...)
  • +
  • the relative base measurement : the base measurement divided by the total base measurement across all regions in each hemisphere
  • +
  • the relative density : density divided by total density across all regions in each hemisphere
  • +
+

It is then up to you to select which metrics among those to compute and display and name them, via the configuration file.

+

For punctal detections (eg. objects whose only the centroid is considered), only the atlas coordinates are used, to compute and display spatial distributions of objects across the brain (using their classifications to give each distributions different hues).
+For fibers-like objects, it requires to export the lines detections atlas coordinates as JSON files, with the exportFibersAtlasCoordinates.groovy script (this is done automatically when using the pipeline).

+

Adding measurements#

+

Count for cell-like objects#

+

The groovy script under scripts/qupath-utils/measurements/addRegionsCount.groovy will add a properly formatted count of objects of selected classifications in all atlas regions. This is used for punctual objects (polygons or points), for example objects created in QuPath or with the segmentation script.

+

Cumulated length for fibers-like objects#

+

The groovy script under scripts/qupath-utils/measurements/addRegionsLength.groovy will add the properly formatted cumulated lenghth in microns of fibers-like objects in all atlas regions. This is used for polylines objects, for example generated with the segmentation script.

+

Custom measurements#

+

Keeping in mind cuisto limitations, you can add any measurements you'd like.

+

For example, you can run a pixel classifier in all annotations (eg. atlas regions). Using the Measure button, it will add a measurement of the area covered by classified pixels. Then, you can use the script located under scripts/qupath-utils/measurements/renameMeasurements.groovy to rename the generated measurements with a properly-formatted name. Finally, you can export regions measurements.

+

Since cuisto will compute a "density", eg. the measurement divided by the region area, in this case, it will correspond to the fraction of surface occupied by classified pixels. This is showcased in the Examples.

+

QuPath export#

+

Once you imported atlas regions registered with ABBA, detected objects in your images and added properly formatted measurements to detections and annotations, you can :

+
    +
  • Head to Measure > Export measurements
  • +
  • Select relevant images
  • +
  • Choose the Output file (specify in the file name if it is a detections or annotations file)
  • +
  • Chose either Detections or Annoations in Export type
  • +
  • Click Export
  • +
+

Do this for both Detections and Annotations, you can then use those files with cuisto (see the Examples).

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide-qupath-objects.html b/guide-qupath-objects.html new file mode 100644 index 0000000..4237693 --- /dev/null +++ b/guide-qupath-objects.html @@ -0,0 +1,1693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Detect objects with QuPath - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Detect objects with QuPath#

+

The QuPath documentation is quite extensive, detailed, very well explained and contains full guides on how to create a QuPath project and how to find objects of interests. It is therefore a highly recommended read, nevertheless, you will find below some quick reminders.

+

QuPath project#

+

QuPath works with projects. It is basically a folder with a main project.qproj file, which is a JSON file that contains all the data about your images except the images themselves. Algonside, there is a data folder with an entry for each image, that stores the thumbnails, metadata about the image and detections and annotations but, again, not the image itself. The actual images can be stored anywhere (including a remote server), the QuPath project merely contains the information needed to fetch them and display them. QuPath will never modify your image data.

+

This design makes the QuPath project itself lightweight (should never exceed 500MB even with millions of detections), and portable : upon opening, if QuPath is not able to find the images where they should be, it will ask for their new locations.

+
+

Tip

+

It is recommended to create the QuPath project locally on your computer, to avoid any risk of conflicts if two people open it at the same time. Nevertheless, you should backup the project regularly on a remote server.

+
+

To create a new project, simply drag & drop an empty folder into QuPath window and accept to create a new empty project. Then, add images :

+
    +
  • If you have a single file, just drag & drop it in the main window.
  • +
  • If you have several images, in the left panel, click Add images, then Choose files on the bottom. Drag & drop does not really work as the images will not be sorted properly.
  • +
+

Then, choose the following options :

+
+
Image server
+
+

Default (let QuPath decide)

+
+
Set image type
+
+

Most likely, fluorescence

+
+
Rotate image
+
+

No rotation (unless all your images should be rotated)

+
+
Optional args
+
+

Leave empty

+
+
Auto-generate pyramids
+
+

Uncheck

+
+
Import objects
+
+

Uncheck

+
+
Show image selector
+
+

Might be useful to check if the images are read correctly (mostly for CZI files).

+
+
+

Detect objects#

+

Built-in cell detection#

+

QuPath has a built-in cell detection feature, available in Analyze > Cell detection. You hava a full tutorial in the official documentation.

+

Briefly, this uses a watershed algorithm to find bright spots and can perform a cell expansion to estimate the full cell shape based on the detected nuclei. Therefore, this works best to segment nuclei but one can expect good performance for cells as well, depending on the imaging and staining conditions.

+
+

Tip

+

In scripts/qupath-utils/segmentation, there is watershedDetectionFilters.groovy which uses this feature from a script. It further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

+
+

Pixel classifier#

+

Another very powerful and versatile way to segment cells if through machine learning. Note the term "machine" and not "deep" as it relies on statistics theory from the 1980s. QuPath provides an user-friendly interface to that, similar to what ilastik provides.

+

The general idea is to train a model to classify every pixel as a signal or as background. You can find good resources on how to procede in the official documentation and some additionnal tips and tutorials on Michael Neslon's blog (here and here).

+

Specifically, you will manually annotate some pixels of objects of interest and background. Then, you will apply some image processing filters (gaussian blur, laplacian...) to reveal specific features in your images (shapes, textures...). Finally, the pixel classifier will fit a model on those pixel values, so that it will be able to predict if a pixel, given the values with the different filters you applied, belongs to an object of interest or to the background.

+

This is done in an intuitive GUI with live predictions to get an instant feedback on the effects of the filters and manual annotations.

+

Train a model#

+

First and foremost, you should use a QuPath project dedicated to the training of a pixel classifier, as it is the only way to be able to edit it later on.

+
    +
  1. You should choose some images from different animals, with different imaging conditions (staining efficiency and LED intensity) in different regions (eg. with different objects' shape, size, sparsity...). The goal is to get the most diversity of objects you could encounter in your experiments. 10 images is more than enough !
  2. +
  3. Import those images to the new, dedicated QuPath project.
  4. +
  5. Create the classifications you'll need, "Cells: marker+" for example. The "Ignore*" classification is used for the background.
  6. +
  7. Head to Classify > Pixel classification > Train pixel classifier, and turn on Live prediction.
  8. +
  9. Load all your images in Load training.
  10. +
  11. In Advanced settings, check Reweight samples to help make sure a classification is not over-represented.
  12. +
  13. Modify the different parameters :
      +
    • Classifier : typically, RTrees or ANN_MLP. This can be changed dynamically afterwards to see which works best for you.
    • +
    • Resolution : this is the pixel size used. This is a trade-off between accuracy and speed. If your objects are only composed of a few pixels, you'll the full resolution, for big objects reducing the resolution will be faster.
    • +
    • Features : this is the core of the process -- where you choose the filters. In Edit, you'll need to choose :
        +
      • The fluorescence channels
      • +
      • The scales, eg. the size of the filters applied to the image. The bigger, the coarser the filter is. Again, this will depend on the size of the objects you want to segment.
      • +
      • The features themselves, eg. the filters applied to your images before feeding the pixel values to the model. For starters, you can select them all to see what they look like.
      • +
      +
    • +
    • Output : +
    • +
    +
  14. +
  15. In the bottom-right corner of the pixel classifier window, you can select to display each filters individually. Then in the QuPath main window, hitting C will switch the view to appreciate what the filter looks like. Identify the ones that makes your objects the most distinct from the background as possible. Switch back to Show classification once you begin to make annotations.
  16. +
  17. +

    Begin to annotate ! Use the Polyline annotation tool (V) to classify some pixels belonging to an object and some pixels belonging to the background across your images.

    +
    +

    Tip

    +

    You can select the RTrees Classifier, then Edit : check the Calculate variable importance checkbox. Then in the log (Ctrl+Shift+L), you can inspect the weight each features have. This can help discard some filters to keep only the ones most efficient to distinguish the objects of interest.

    +
    +
  18. +
  19. +

    See in live the effect of your annotations on the classification using C and continue until you're satisfied.

    +
    +

    Important

    +

    This is machine learning. The lesser annotations, the better, as this will make your model more general and adapt to new images. The goal is to find the minimal number of annotations to make it work.

    +
    +
  20. +
  21. +

    Once you're done, give your classifier a name in the text box in the bottom and save it. It will be stored as a JSON file in the classifiers folder of the QuPath project. This file can be imported in your other QuPath projects.

    +
  22. +
+

Built-in create objects#

+

Once you imported your model JSON file (Classify > Pixel classification > Load pixel classifier, three-dotted menu and Import from file), you can create objects out of it, measure the surface occupied by classified pixels in each annotation or classify existing detections based on the prediction at their centroid.

+

In scripts/qupath-utils/segmentation, there is a createDetectionsFromPixelClassifier.groovy script to batch-process your project.

+

Probability map segmentation#

+

Alternatively, a Python script provided with cuisto can be used to segment the probability map generated by the pixel classifier (the script is located in scripts/segmentation).

+

You will first need to export those with the exportPixelClassifierProbabilities.groovy script (located in scripts/qupath-utils).

+

Then the segmentation script can :

+
    +
  • find punctal objects as polygons (with a shape) or points (punctal) than can be counted.
  • +
  • trace fibers with skeletonization to create lines whose lengths can be measured.
  • +
+

Several parameters have to be specified by the user, see the segmentation script API reference. This script will generate GeoJson files that can be imported back to QuPath with the importGeojsonFiles.groovy script.

+

Third-party extensions#

+

QuPath being open-source and extensible, there are third-party extensions that implement popular deep learning segmentation algorithms directly in QuPath. They can be used to find objects of interest as detections in the QuPath project and thus integrate nicely with cuisto to quantify them afterwards.

+

InstanSeg#

+

QuPath extension : https://github.com/qupath/qupath-extension-instanseg
+Original repository : https://github.com/instanseg/instanseg
+Reference papers : doi:10.48550/arXiv.2408.15954, doi:10.1101/2024.09.04.611150

+

Stardist#

+

QuPath extension : https://github.com/qupath/qupath-extension-stardist
+Original repository : https://github.com/stardist/stardist
+Reference paper : doi:10.48550/arXiv.1806.03535

+

There is a stardistDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

+

Cellpose#

+

QuPath extension : https://github.com/BIOP/qupath-extension-cellpose
+Original repository : https://github.com/MouseLand/cellpose
+Reference papers : doi:10.1038/s41592-020-01018-x, doi:10.1038/s41592-022-01663-4, doi:10.1101/2024.02.10.579780

+

There is a cellposeDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

+

SAM#

+

QuPath extension : https://github.com/ksugar/qupath-extension-sam
+Original repositories : samapi, SAM
+Reference papers : doi:10.1101/2023.06.13.544786, doi:10.48550/arXiv.2304.02643

+

This is more an interactive annotation tool than a fully automatic segmentation algorithm.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guide-register-abba.html b/guide-register-abba.html new file mode 100644 index 0000000..39e55f0 --- /dev/null +++ b/guide-register-abba.html @@ -0,0 +1,1761 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Registration with ABBA - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + +

Registration with ABBA#

+

The ABBA documentation is quite extensive and contains guided tutorials and a video tutorial. You should therefore check it out ! Nevertheless, you will find below some quick reminders.

+

Import a QuPath project#

+

Always use ABBA with a QuPath project, if you import the images directly it will not be possible to export the results back to QuPath. In the toolbar, head to Import > Import QuPath Project.

+
    +
  • Select the .qproj file corresponding to the QuPath project to be aligned.
  • +
  • Initial axis position : this is the initial position where to put your stack. It will be modified afterwards.
  • +
  • Axis increment between slices : this is the spatial spacing, in mm, between two slices. This would correspond to the slice thickness multiplied by the number of set. If your images are ordered from rostral to caudal, set it negative.
  • +
+
+

Warning

+

ABBA is not the most stable software, it is highly recommended to save in a different file each time you do anything.

+
+ +

Interface#

+
    +
  • Left Button + drag to select slices
  • +
  • Right Button for display options
  • +
  • Right Button + drag to browse the view
  • +
  • Middle Button to zoom in and or out
  • +
+

Right panel#

+

In the right panel, there is everything related to the images, both yours and the atlas.

+

In the Atlas Display section, you can turn on and off different channels (the first is the reference image, the last is the regions outlines). +The Displayed slicing [atlas steps] slider can increase or decrease the number of displayed 2D slices extracted from the 3D volume. It is comfortable to set to to the same spacing as your slices. Remember it is in "altas steps", so for an atlas imaged at 10µm, a 120µm spacing corresponds to 12 atlas steps.

+

The Slices Display section lists all your slices. Ctrl+A to select all, and click on the Vis. header to make them visible. Then, you can turn on and off each channels (generally the NISSL channel and the ChAT channel will be used) by clicking on the corresponding header. Finally, set the display limits clicking on the empty header containing the colors.

+

Right Button in the main view to Change overlap mode twice to get the slices right under the atlas slices.

+
+

Tip

+

Every action in ABBA are stored and are cancellable with Right Button+Z, except the Interactive transform.

+
+

Find position and angle#

+

This is the hardest task. You need to drag the slices along the rostro-caudal axis and modify the virtual slicing angle (X Rotation [deg] and Y Rotation [deg] sliders at the bottom of the right panel) until you match the brain structures observed in both your images and the atlas.

+
+

Tip

+

With a high number of slices, most likely, it will be impossible to find a position and slicing angle that works for all your slices. In that case, you should procede in batch, eg. sub-stack of images with a unique position and slicing angle that works for all images in the sub-stack. Then, remove the remaining slices (select them, Right Button > Remove Selected Slices), but do not remove them from the QuPath project.

+

Procede as usual, including saving (note the slices range it corresponds to) and exporting the registration back to QuPath. Then, reimport the project in a fresh ABBA instance, remove the slices that were already registered and redo the whole process with the next sub-stack and so on.

+
+

Once you found the correct position and slicing angle, it must not change anymore, otherwise the registration operations you perform will not make any sense anymore.

+

In-plane registration#

+

The next step is to deform your slices to match the corresponding atlas image, extracted from the 3D volume given the position and virtual slicing angle defined at the previous step.

+
+

Info

+

ABBA makes the choice to deform your slices to the atlas, but the transformations are invertible. This means that you will still be able to work on your raw data and deform the altas onto it instead.

+
+

In image processing, there are two kinds of deformation one can apply on an image :

+
    +
  • Affine (or linear) : simple, image-wide, linear operations - translation, rotation, scaling, shearing.
  • +
  • Spline (or non-linear) : complex non-linear operations that can allow for local deformation.
  • +
+

Both can be applied manually or automatically (if the imaging quality allows it). +You have different tools to achieve this, all of which can be combined in any order, except the Interactive transform tool (coarse, linear manual deformation).

+

Change the overlap mode (Right Button) to overlay the slice onto the atlas regions borders. Select the slice you want to align.

+

Coarse, linear manual deformation#

+

While not mandatory, if this tool shall be used, it must be before any operation as it is not cancellable. +Head to Register > Affine > Interactive transform.
+This will open a box where you can rotate, translate and resize the image to make a first, coarse alignment.

+

Close the box. Again, this is not cancellable. Afterwards, you're free to apply any numbers of transformations in any order.

+

Automatic registration#

+

This uses the elastix toolbox to compute the transformations needed to best match two images. It is available in both affine and spline mode, in the Register > Affine and Register > Spline menus respectively.

+

In both cases, it will open a dialog where you need to choose :

+
    +
  • Atlas channels : the reference image of the atlas, usually channel number 0
  • +
  • Slices channels : the fluorescence channel that looks like the most to the reference image, usually channel number 0
  • +
  • Registration re-sampling (micrometers) : the pixel size to resize the images before registration, as it is a computationally intensive task. Going below 20µm won't help much.
  • +
+

For the Spline mode, there an additional parameter :

+
    +
  • Number of control points along X : the algorithm will set points as a grid in the image and perform the transformations from those. The higher number of points, the more local transformations will be.
  • +
+

Manual registration#

+

This uses BigWarp to manually deform the images with the mouse. It can be done from scratch (eg. you place the points yourself) or from a previous registration (either a previous BigWarp session or elastix in Spline mode).

+

From scratch#

+

Register > Spline > BigWarp registration to launch the tool. Choose the atlas that allows you to best see the brain structures (usually the regions outlines channels, the last one), and the reference fluorescence channel.

+

It will open two viewers, called "BigWarp moving image" and "BigWarp fixed image". Briefly, they correspond to the two spaces you're working in, the "Atlas space" and the "Slice space".

+
+

Tip

+

Do not panick yet, while the explanations might be confusing (at least they were to me), in practice, it is easy, intuitive and can even be fun (sometimes, at small dose).

+
+

To browse the viewer, use Right Button + drag (Left Button is used to rotate the viewer), Middle Button zooms in and out.

+

The idea is to place points, called landmarks, that always go in pairs : one in the moving image and one where it corresponds to in the fixed image (or vice-versa). In practice, we will only work in the BigWarp fixed image viewer to place landmarks in both space in one click, then drag it to the corresponding location, with a live feedback of the transformation needed to go from one to another.

+

To do so :

+
    +
  1. +

    Press Space to switch to the "Landmark mode".

    +
    +

    Warning

    +

    In "Landmark mode", Right Button can't be used to browse the view anymore. To do so, turn off the "Landmark mode" hitting Space again.

    +
    +
  2. +
  3. +

    Use Ctrl+Left Button to place a landmark.

    +
    +

    Info

    +

    At least 4 landmarks are needed before activating the live-transform view.

    +
    +
  4. +
  5. +

    When there are at least 4 landmarks, hit T to activate the "Transformed" view. Transformed will be written at the bottom.

    +
  6. +
  7. Hold Left Button on a landmark to drag it to deform the image onto the atlas.
  8. +
  9. Add as many landmarks as needed, when you're done, find the Fiji window called "Big Warp registration" that opened at the beginning and click OK.
  10. +
+
+

Important remarks and tips

+
    +
  • A landmark is a location where you said "this location correspond to this one". Therefore, BigWarp is not allowed to move this particular location. Everywhere else, it is free to transform the image without any restrictions, including the borders. Thus, it is a good idea to delimit the coarse contour of the brain with landmarks to constrain the registration.
  • +
  • Left Button without holding Ctrl will place a landmark in the fixed image only, without pair, and BigWarp won't like it. To delete landmarks, head to the "Landmarks" window that lists all of them. They highlight in the viewer upon selection. Hit Del to delete one. Alternatively, click on it on the viewer and hit Del.
  • +
+
+

From a previous registration#

+

Head to Register > Edit last Registration to work on a previous registration.

+

If the previous registration was done with elastix (Spline) or BigWarp, it will launch the BigWarp interface exactly like above, but with landmarks already placed, either on a grid (elastix) or the one you manually placed (BigWarp).

+
+

Tip

+

It will ask which channels to use, you can modify the channel for your slices to work on two channels successively. For instance, one could make a first registration using the NISSL staining, then refine the motoneurons with the ChAT staining, if available.

+
+

ABBA state file#

+

ABBA can save the state you're in, from the File > Save State menu. It will be saved as a .abba file, which is actually a zip archive containing a bunch of JSON, listing every actions you made and in which order, meaning you will stil be able to cancel actions after quitting ABBA.

+

To load a state, quit ABBA, launch it again, then choose File > Load State and select the .abba file to carry on with the registration.

+
+

Save, save, save !

+

Those state files are cheap, eg. they are lightweight (less than 200KB). You should save the state each time you finish a slice, and you can keep all your files, without overwritting the previous ones, appending a number to its file name. This will allow to roll back to the previous slice in the event of any problem you might face.

+
+

Export registration back to QuPath#

+

Export the registration from ABBA#

+

Once you are satisfied with your registration, select the registered slices and head to Export > QuPath > Export Registrations To QuPath Project. Check the box to make sure to get the latest registered regions.

+

It will export several files in the QuPath projects, including the transformed atlas regions ready to be imported in QuPath and the transformations parameters to be able to convert coordinates from the extension.

+

Import the registration in QuPath#

+

Make sure you installed the ABBA extension in QuPath.

+

From your project with an image open, the basic usage is to head to Extensions > ABBA > Load Atlas Annotations into Open Image. +Choose to Split Left and Right Regions to make the two hemispheres independent, and choose the "acronym" to name the regions. The registered regions should be imported as Annotations in the image.

+
+

Tip

+

With ABBA in regular Fiji using the CCFv3 Allen mouse brain atlas, the left and right regions are flipped, because ABBA considers the slices as backward facing. The importAbba.groovy script located in scripts/qupath-utils-atlas allows you to flip left/right regions names. This is OK because the Allen brain is symmetrical by construction.

+
+

For more complex use, check the Groovy scripts in scripts/qupath-utils/atlas. ABBA registration is used throughout the guides, to either work with brain regions (and count objects for instance) or to get the detections' coordinates in the atlas space.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/images/anaconda-licences.png b/images/anaconda-licences.png new file mode 100644 index 0000000..3ce4a23 Binary files /dev/null and b/images/anaconda-licences.png differ diff --git a/images/cuisto-pipeline.svg b/images/cuisto-pipeline.svg new file mode 100644 index 0000000..ea07169 --- /dev/null +++ b/images/cuisto-pipeline.svg @@ -0,0 +1,4 @@ + + + +
Images
(CZI, LIF, ...)
Images...
Pre-processing
(find brain contours)
Pre-processing...
Pyramidalize
Pyramidalize
Compute & Export
Compute & Expo...
Pool & compute
Pool & compu...
Display
Display
Pixel classification
Pixel classif...
Probability map
Probability m...
Segmentation
Segmentation
Create objects
Create objects
Measure
Measure
Cell detection
Cell detection
Cellpose
Cellpose
Manual counting
Manual counting
Stardist
Stardist
Objects
Objects
Classification
Classification
cuisto
cuisto
QuPath
built in
QuPath...
ABBA
ABBA
???
???
Registration
Registration
Manual drawing
Manual drawing
Annotations
Annotations
Detections
Detections
Measure intensity
Measure intensit...
Measure aera
Measure aera
Measure length
Measure length
QuPath
custom scripts
QuPath...
Configuration files
Configuration f...
Count objects
Count objects
???
???
Measurement
Measurement
Optional
Optional
Text is not SVG - cannot display
\ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..e465db5 --- /dev/null +++ b/index.html @@ -0,0 +1,1372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Introduction#

+
+

Info

+

The documentation is under construction.

+
+

cuisto is a Python package aiming at quantifying histological data.

+

After ABBA registration of 2D histological slices and QuPath objects' detection, cuisto is used to :

+
    +
  • compute metrics, such as objects density in each brain regions,
  • +
  • compute objects distributions in three three axes (rostro-caudal, dorso-ventral and medio-lateral),
  • +
  • compute averages and sem across animals,
  • +
  • displaying all the above.
  • +
+

This documentation contains cuisto installation instructions, ABBA installation instructions, guides to prepare images for the pipeline, detect objects with QuPath, register 2D slices on a 3D atlas with ABBA, along with examples.

+

In theory, cuisto should work with any measurements table with the required columns, but has been designed with ABBA and QuPath in mind.

+

Due to the IT environment of the laboratory, this documentation is very Windows-oriented but most of it should be applicable to Linux and MacOS as well by slightly adapting terminal commands.

+

Histological slices analysis pipeline

+

Documentation navigation#

+

The documentation outline is on the left panel, you can click on items to browse it. In each page, you'll get the table of contents on the right panel.

+

Useful external resources#

+ +

Credits#

+

cuisto has been primarly developed by Guillaume Le Goc in Julien Bouvier's lab at NeuroPSI. The clever name was found by Aurélie Bodeau.

+

The documentation itself is built with MkDocs using the Material theme.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/javascripts/katex.js b/javascripts/katex.js new file mode 100644 index 0000000..941c360 --- /dev/null +++ b/javascripts/katex.js @@ -0,0 +1,10 @@ +document$.subscribe(({ body }) => { + + + renderMathInElement(body, { + delimiters: [ + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true } + ], + }) + }) \ No newline at end of file diff --git a/main-citing.html b/main-citing.html new file mode 100644 index 0000000..2bba38b --- /dev/null +++ b/main-citing.html @@ -0,0 +1,1264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Citing - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Citing#

+

While cuisto does not have a reference paper as of now, you can reference the GitHub repository.

+

Please make sure to cite all the softwares used in your research. Citations are usually the only metric used by funding agencies, so citing properly the tools used in your research ensures the continuation of those projects.

+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main-configuration-files.html b/main-configuration-files.html new file mode 100644 index 0000000..db96b45 --- /dev/null +++ b/main-configuration-files.html @@ -0,0 +1,1682 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + The configuration files - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

The configuration files#

+

There are three configuration files : altas_blacklist, atlas_fusion and a modality-specific file, that we'll call config in this document. The former two are related to the atlas you're using, the latter is what is used by cuisto to know what and how to compute and display things. There is a fourth, optional, file, used to provide some information on a specific experiment, info.

+

The configuration files are in the TOML file format, that are basically text files formatted in a way that is easy to parse in Python. See here for a basic explanation of the syntax.

+

Most lines of each template file are commented to explain what each parameter do.

+

atlas_blacklist.toml#

+
+Click to see an example file +
atlas_blacklist.toml
# TOML file to list Allen brain regions to ignore during analysis.
+# 
+# It is used to blacklist regions and all descendants regions ("WITH_CHILD").
+# Objects belonging to those regions and their descendants will be discarded.
+# And you can specify an exact region where to remove objects ("EXACT"),
+# descendants won't be affected.
+# Use it to remove noise in CBX, ventricual systems and fiber tracts.
+# Regions are referenced by their exact acronym.
+#
+# Syntax :
+#   [WITH_CHILDS]
+#   members = ["CBX", "fiber tracts", "VS"]
+#
+#   [EXACT]
+#   members = ["CB"]
+
+
+[WITH_CHILDS]
+members = ["CBX", "fiber tracts", "VS"]
+
+[EXACT]
+members = ["CB"]
+
+
+

This file is used to filter out specified regions and objects belonging to them.

+
    +
  • The atlas regions present in the members keys will be ignored. Objects whose parents are in here will be ignored as well.
  • +
  • In the [WITH_CHILDS] section, regions and objects belonging to those regions and all descending regions (child regions, as per the altas hierarchy) will be removed.
  • +
  • In the [EXACT] section, only regions and objects belonging to those exact regions are removed. Descendants regions are not taken into account.
  • +
+

atlas_fusion.toml#

+
+Click to see an example file +
atlas_blacklist.toml
# TOML file to determine which brain regions should be merged together.
+# Regions are referenced by their exact acronym.
+# The syntax should be the following :
+# 
+#   [MY]
+#   name = "Medulla"  # new or existing full name
+#   acronym = "MY"  # new or existing acronym
+#   members = ["MY-mot", "MY-sat"]  # existing Allen Brain acronyms that should belong to the new region
+#
+# Then, regions labelled "MY-mot" and "MY-sat" will be labelled "MY" and will join regions already labelled "MY".
+# What's in [] does not matter but must be unique and is used to group.
+# The new "name" and "acronym" can be existing Allen Brain regions or a new (meaningful) one.
+# Note that it is case sensitive.
+
+[PHY]
+name = "Perihypoglossal nuclei"
+acronym = "PHY"
+members = ["NR", "PRP"]
+
+[NTS]
+name = "Nucleus of the solitary tract"
+acronym = "NTS"
+members = ["ts", "NTSce", "NTSco", "NTSge", "NTSl", "NTSm"]
+
+[AMB]
+name = "Nucleus ambiguus"
+acronym = "AMB"
+members = ["AMBd", "AMBv"]
+
+[MY]
+name = "Medulla undertermined"
+acronym = "MYu"
+members = ["MY-mot", "MY-sat"]
+
+[IRN]
+name = "Intermediate reticular nucleus"
+acronym = "IRN"
+members = ["IRN", "LIN"]
+
+
+

This file is used to group regions together, to customize the atlas' hierarchy. It is particularly useful to group smalls brain regions that are impossible to register precisely. +Keys name, acronym and members should belong to a [section].

+
    +
  • [section] is just for organizing, the name does not matter but should be unique.
  • +
  • name should be a human-readable name for your new region.
  • +
  • acronym is how the region will be refered to. It can be a new acronym, or an existing one.
  • +
  • members is a list of acronyms of atlas regions that should be part of the new one.
  • +
+

config.toml#

+
+Click to see an example file +
config_template.toml
########################################################################################
+# Configuration file for cuisto package
+# -----------------------------------------
+# This is a TOML file. It maps a key to a value : `key = value`.
+# Each key must exist and be filled. The keys' names can't be modified, except:
+#   - entries in the [channels.names] section and its corresponding [channels.colors] section,
+#   - entries in the [regions.metrics] section.                                                                                   
+#
+# It is strongly advised to NOT modify this template but rather copy it and modify the copy.
+# Useful resources :
+#   - the TOML specification : https://toml.io/en/
+#   - matplotlib colors : https://matplotlib.org/stable/gallery/color/color_demo.html
+#
+# Configuration file part of the python cuisto package.
+# version : 2.1
+########################################################################################
+
+object_type = "Cells"  # name of QuPath base classification (eg. without the ": subclass" part)
+segmentation_tag = "cells"  # type of segmentation, matches directory name, used only in the full pipeline
+
+[atlas]  # information related to the atlas used
+name = "allen_mouse_10um"  # brainglobe-atlasapi atlas name
+type = "brain"  # brain or cord (eg. registration done in ABBA or abba_python)
+midline = 5700  # midline Z coordinates (left/right limit) in microns
+outline_structures = ["root", "CB", "MY", "P"]  # structures to show an outline of in heatmaps
+
+[channels]  # information related to imaging channels
+[channels.names]  # must contain all classifications derived from "object_type"
+"marker+" = "Positive"  # classification name = name to display
+"marker-" = "Negative"
+[channels.colors]  # must have same keys as names' keys
+"marker+" = "#96c896"  # classification name = matplotlib color (either #hex, color name or RGB list)
+"marker-" = "#688ba6"
+
+[hemispheres]  # information related to hemispheres
+[hemispheres.names]
+Left = "Left"  # Left = name to display
+Right = "Right"  # Right = name to display
+[hemispheres.colors]  # must have same keys as names' keys
+Left = "#ff516e"  # Left = matplotlib color (either #hex, color name or RGB list)
+Right = "#960010"  # Right = matplotlib color
+
+[distributions]  # spatial distributions parameters
+stereo = true  # use stereotaxic coordinates (Paxinos, only for brain)
+ap_lim = [-8.0, 0.0]  # bins limits for anterio-posterior
+ap_nbins = 75  # number of bins for anterio-posterior
+dv_lim = [-1.0, 7.0]  # bins limits for dorso-ventral
+dv_nbins = 50  # number of bins for dorso-ventral
+ml_lim = [-5.0, 5.0]  # bins limits for medio-lateral
+ml_nbins = 50  # number of bins for medio-lateral
+hue = "channel"  # color curves with this parameter, must be "hemisphere" or "channel"
+hue_filter = "Left"  # use only a subset of data. If hue=hemisphere : channel name, list of such or "all". If hue=channel : hemisphere name or "both".
+common_norm = true  # use a global normalization for each hue (eg. the sum of areas under all curves is 1)
+[distributions.display]
+show_injection = false  # add a patch showing the extent of injection sites. Uses corresponding channel colors
+cmap = "OrRd"  # matplotlib color map for heatmaps
+cmap_nbins = 50  # number of bins for heatmaps
+cmap_lim = [1, 50]  # color limits for heatmaps
+
+[regions]  # distributions per regions parameters
+base_measurement = "Count"  # the name of the measurement in QuPath to derive others from
+hue = "channel"  # color bars with this parameter, must be "hemisphere" or "channel"
+hue_filter = "Left"  # use only a subset of data. If hue=hemisphere : channel name, list of such or "all". If hue=channel : hemisphere name or "both".
+hue_mirror = false  # plot two hue_filter in mirror instead of discarding the other
+normalize_starter_cells = false  # normalize non-relative metrics by the number of starter cells
+[regions.metrics]  # names of metrics. Do not change the keys !
+"density µm^-2" = "density µm^-2"
+"density mm^-2" = "density mm^-2"
+"coverage index" = "coverage index"
+"relative measurement" = "relative count"
+"relative density" = "relative density"
+[regions.display]
+nregions = 18  # number of regions to display (sorted by max.)
+orientation = "h"  # orientation of the bars ("h" or "v")
+order = "max"  # order the regions by "ontology" or by "max". Set to "max" to provide a custom order
+dodge = true  # enforce the bar not being stacked
+log_scale = false  # use log. scale for metrics
+[regions.display.metrics]  # name of metrics to display
+"count" = "count"  # real_name = display_name, with real_name the "values" in [regions.metrics]
+"density mm^-2" = "density (mm^-2)"
+
+[files]  # full path to information TOML files
+blacklist = "../../atlas/atlas_blacklist.toml"
+fusion = "../../atlas/atlas_fusion.toml"
+outlines = "/data/atlases/allen_mouse_10um_outlines.h5"
+infos = "../../configs/infos_template.toml"
+
+
+

This file is used to configure cuisto behavior. It specifies what to compute, how, and display parameters such as colors associated to each classifications, hemisphere names, distributions bins limits...

+
+

Warning

+

When editing your config.toml file, you're allowed to modify the keys only in the [channels] section.

+
+
+Click for a more readable parameters explanation +

object_type : name of QuPath base classification (eg. without the ": subclass" part) +segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

+

atlas

+Information related to the atlas used

+

name : brainglobe-atlasapi atlas name
+type : "brain" or "cord" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps.
+midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates.
+outline_structures : structures to show an outline of in heatmaps

+

channels

+Information related to imaging channels

+

names

+Must contain all classifications derived from "object_type" you want to process. In the form subclassification name = name to display on the plots

+

"marker+" : classification name = name to display
+"marker-" : add any number of sub-classification

+

colors

+Must have same keys as "names" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

+

"marker+" : classification name = matplotlib color
+"marker-" : must have the same entries as "names".

+

hemispheres

+Information related to hemispheres, same structure as channels

+

names

+

Left : Left = name to display
+Right : Right = name to display

+

colors

+Must have same keys as names' keys

+

Left : ff516e" # Left = matplotlib color (either #hex, color name or RGB list)
+Right : 960010" # Right = matplotlib color

+

distributions

+Spatial distributions parameters

+

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3)
+ap_lim : bins limits for anterio-posterior in mm
+ap_nbins : number of bins for anterio-posterior
+dv_lim : bins limits for dorso-ventral in mm
+dv_nbins : number of bins for dorso-ventral
+ml_lim : bins limits for medio-lateral in mm
+ml_nbins : number of bins for medio-lateral
+hue : color curves with this parameter, must be "hemisphere" or "channel"
+hue_filter : use only a subset of data

+
    +
  • If hue=hemisphere : it should be a channel name, a list of such or "all"
  • +
  • If hue=channel : it should be a hemisphere name or "both"
  • +
+

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

+

display

+Display parameters

+

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up +cmap : matplotlib color map for 2D heatmaps +cmap_nbins : number of bins for 2D heatmaps +cmap_lim : color limits for 2D heatmaps

+

regions

+Distributions per regions parameters

+

base_measurement : the name of the measurement in QuPath to derive others from. Usually "Count" or "Length µm"
+hue : color bars with this parameter, must be "hemisphere" or "channel"
+hue_filter : use only a subset of data

+
    +
  • If hue=hemisphere : it should be a channel name, a list of such or "all"
  • +
  • If hue=channel : it should be a hemisphere name or "both"
  • +
+

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter="both", plots the two hemisphere in mirror.
+normalize_starter_cells : normalize non-relative metrics by the number of starter cells

+

metrics

+Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

+

"density µm^-2" : relevant name
+"density mm^-2" : relevant name
+"coverage index" : relevant name
+"relative measurement" : relevant name
+"relative density" : relevant name

+

display

+

nregions : number of regions to display (sorted by max.)
+orientation : orientation of the bars ("h" or "v")
+order : order the regions by "ontology" or by "max". Set to "max" to provide a custom order
+dodge : enforce the bar not being stacked
+log_scale : use log. scale for metrics

+

metrics
+name of metrics to display

+

"count" : real_name = display_name, with real_name the "values" in [regions.metrics] +"density mm^-2"

+

files

+Full path to information TOML files and atlas outlines for 2D heatmaps.

+

blacklist
+fusion
+outlines
+infos

+
+

info.toml#

+
+Click to see an example file +
info_template.toml
# TOML file to specify experimental settings of each animals.
+# Syntax should be :
+#   [animalid0]  # animal ID
+#   slice_thickness = 30  # slice thickness in microns
+#   slice_spacing = 60  # spacing between two slices in microns
+#   [animalid0.marker-name]  # [{Animal id}.{segmented channel name}]
+#   starter_cells = 190  # number of starter cells
+#   injection_site = [x, y, z]  # approx. injection site in CCFv3 coordinates
+#
+# --------------------------------------------------------------------------
+[animalid0]
+slice_thickness = 30
+slice_spacing = 60
+[animalid0."marker+"]
+starter_cells = 150
+injection_site = [ 10.8937328, 6.18522070, 6.841855301 ]
+[animalid0."marker-"]
+starter_cells = 175
+injection_site = [ 10.7498512, 6.21545461, 6.815487203 ]
+# --------------------------------------------------------------------------
+[animalid1-SC]
+slice_thickness = 30
+slice_spacing = 120
+[animalid1-SC.EGFP]
+starter_cells = 250
+injection_site = [ 10.9468211, 6.3479642, 6.0061113 ]
+[animalid1-SC.DsRed]
+starter_cells = 275
+injection_site = [ 10.9154874, 6.2954872, 8.1587125 ]
+# --------------------------------------------------------------------------
+
+
+

This file is used to specify injection sites for each animal and each channel, to display it in distributions.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main-getting-help.html b/main-getting-help.html new file mode 100644 index 0000000..ca7255e --- /dev/null +++ b/main-getting-help.html @@ -0,0 +1,1269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Getting help - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Getting help#

+

For help in QuPath, ABBA, Fiji or any image processing-related questions, your one stop is the image.sc forum. There, you can search with specific tags (#qupath, #abba, ...). You can also ask questions or even answer to some by creating an account !

+

For help with cuisto in particular, you can open an issue in Github (which requires an account as well), or send an email to me or Antoine Lesage.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main-getting-started.html b/main-getting-started.html new file mode 100644 index 0000000..a14a354 --- /dev/null +++ b/main-getting-started.html @@ -0,0 +1,1517 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Getting started - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Getting started#

+

Quick start#

+
    +
  1. Install QuPath, ABBA and conda.
  2. +
  3. Create an environment : +
    conda create -c conda-forge -n cuisto-env python=3.12
    +
  4. +
  5. Activate it : +
    conda activate cuisto-env
    +
  6. +
  7. Download the latest release .zip, unzip it and install it with pip, from inside the cuisto-xxx folder : +
    pip install .
    +
    +If you want to build the doc : +
    pip install .[doc]
    +
  8. +
+

Slow start#

+
+

Tip

+

If all goes well, you shouldn't need any admin rights to install the various pieces of software used before cuisto.

+
+
+

Important

+

Remember to cite all softwares you use ! See Citing.

+
+

QuPath#

+

QuPath is an "open source software for bioimage analysis". You can install it from the official website : https://qupath.github.io/.
+The documentation is quite clear and comprehensive : https://qupath.readthedocs.io/en/stable/index.html.

+

This is where you'll create QuPath projects, in which you'll be able to browse your images, annotate them, import registered brain regions and find objects of interests (via automatic segmentation, thresholding, pixel classification, ...). Then, those annotations and detections can be exported to be processed by cuisto.

+

Aligning Big Brain and Atlases (ABBA)#

+

This is the tool you'll use to register 2D histological sections to 3D atlases. See the dedicated page.

+

Python virtual environment manager (conda)#

+

The cuisto package is written in Python. It depends on scientific libraries (such as NumPy, pandas and many more). Those libraries need to be installed in versions that are compatible with each other and with cuisto. To make sure those versions do not conflict with other Python tools you might be using (deeplabcut, abba_python, ...), we will install cuisto and its dependencies in a dedicated virtual environment.

+

conda is a software that takes care of this. It comes with a "base" environment, from which we will create and manage other, project-specific environments. It is also used to download and install python in each of those environments, as well as third-party libraries. conda in itself is free and open-source and can be used freely by anyone.

+

It is included with the Anaconda distribution, which is subject to specific terms of service, which state that unless you're an individual, a member of a company with less than 200 employees or a member of an university (but not a national research lab) it's free to use, otherwise, you need to pay a licence. conda, while being free, is by default configured to use the "defaults" channel to fetch the packages (including Python itself), a repository operated by Anaconda, which is, itself, subject to the Anaconda terms of service.

+

In contrast, conda-forge is a community-run repository that contains more numerous and more update-to-date packages. This is free to use for anyone. The idea is to use conda directly (instead of Anaconda graphical interface) and download packages from conda-forge (instead of the Anaconda-run defaults). To try to decipher this mess, Anaconda provides this figure :

+

Anaconda terms of service

+

Furthermore, the "base" conda environment installed with the Anaconda distribution is bloated and already contains tons of libraries, and tends to self-destruct at some point (eg. becomes unable to resolve the inter-dependencies), which makes you unable to install new libraries nor create new environments.

+

This is why it is highly recommended to install Miniconda instead, a minimal installer for conda, and configure it to use the free, community-run channel conda-forge, or, even better, use Miniforge which is basically the same but pre-configured to use conda-forge. The only downside is that will not get the Anaonda graphical user interface and you'll need to use the terminal instead, but worry not ! We got you covered.

+
+
    +
  1. Download and install Miniforge (choose the latest release for your system). During the installation, choose to install for the current user, add conda to PATH and make python the default interpreter.
  2. +
  3. Open a terminal (PowerShell in Windows). Run : +
    conda init
    +
    +This will activate conda and its base environment whenever you open a new PowerShell window. Now, when opening a new PowerShell (or terminal), you should see a prompt like this : +
    (base) PS C:\Users\myname>
    +
  4. +
+
+
+

Tip

+

If Anaconda is already installed and you don't have the rights to uninstall it, you'll have to use it instead. You can launch the "Anaconda Prompt (PowerShell)", run conda init. Open a regular PowerShell window and run conda config --add channels conda-forge, so that subsequent installations and environments creation will fetch required dependencies from conda-forge.

+
+

Installation#

+

This section explains how to actually install the cuisto package. +The following commands should be run from a terminal (PowerShell). Remember that the -c conda-forge bits are not necessary if you installed conda with the miniforge distribution.

+
+
    +
  1. Create a virtual environment with python 3.12 : +
    conda create -c conda-forge -n cuisto-env python=3.12
    +
  2. +
  3. Get a copy of the cuisto Source code .zip package, from the Releases page.
  4. +
  5. We need to install it inside the cuisto-env environment we just created. First, you need to activate the cuisto-env environment : +
    conda activate cuisto-env
    +
    +Now, the prompt should look like this : +
    (cuisto-env) PS C:\Users\myname>
    +
    +This means that Python packages will now be installed in the cuisto-env environment and won't conflict with other toolboxes you might be using. +Then, we use pip to install cuisto. pip was installed with Python, and will scan the cuisto folder, specifically the "pyproject.toml" file that lists all the required dependencies. To do so, you can either :
      +
    • pip install /path/to/cuisto
      +
    • +
    • Change directory from the terminal : +
      cd /path/to/cuisto
      +
      +Then install the package, "." denotes "here" : +
      pip install .
      +
    • +
    • Use the file explorer to get to the cuisto folder, use Shift+Right Button to "Open PowerShell window here" and run : +
      pip install .
      +
    • +
    +
  6. +
+
+

cuisto is now installed inside the cuisto-env environment and will be available in Python from that environment !

+
+

Tip

+

You will need to perform step 3. each time you want to update the package.

+
+

If you already have registered data and cells in QuPath, you can export Annotations and Detections as TSV files and head to the Example section.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main-using-notebooks.html b/main-using-notebooks.html new file mode 100644 index 0000000..f5e0211 --- /dev/null +++ b/main-using-notebooks.html @@ -0,0 +1,1301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Using notebooks - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Using notebooks#

+

A Jupyter notebook is a way to use Python in an interactive manner. It uses cells that contain Python code, and that are to be executed to immediately see the output, including figures.

+

You can see some rendered notebooks in the examples here, but you can also download them (downward arrow button on the top right corner of each notebook) and run them locally with your own data.

+

To do so, you can either use an integrated development environment (basically a supercharged text editor) that supports Jupyter notebooks, or directly the Jupyter web interface.

+
+
+
+

You can use for instance Visual Studio Code, also known as vscode.

+
    +
  1. Download it and install it.
  2. +
  3. Launch vscode.
  4. +
  5. Follow or skip tutorials.
  6. +
  7. In the left panel, open Extension (squared pieces).
  8. +
  9. Install the "Python" and "Jupyter" extensions (by Microsoft).
  10. +
  11. You now should be able to open .ipynb (notebooks) files with vscode. On the top right, you should be able to Select kernel : choose "cuisto-env".
  12. +
+
+
+
    +
  1. Create a folder dedicated to working with notebooks, for example "Documents\notebooks".
  2. +
  3. Copy the notebooks you're interested in in this folder.
  4. +
  5. Open a terminal inside this folder (by either using cd Documents\notebooks or, in the file explorer in your "notebooks" folder, Shift+Right Button to "Open PowerShell window here")
  6. +
  7. Activate the conda environment : +
    conda activate cuisto-env
    +
  8. +
  9. Launch the Jupyter Lab web interface : +
    jupyter lab
    +
    +This should open a web page where you can open the ipynb files.
  10. +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/overrides/main.html b/overrides/main.html new file mode 100644 index 0000000..f223d92 --- /dev/null +++ b/overrides/main.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +{% if page.nb_url %} + + {% include ".icons/material/download.svg" %} + +{% endif %} + +{{ super() }} +{% endblock content %} \ No newline at end of file diff --git a/search/search_index.js b/search/search_index.js new file mode 100644 index 0000000..16b9579 --- /dev/null +++ b/search/search_index.js @@ -0,0 +1 @@ +var __index = {"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"index.html","title":"Introduction","text":"

Info

The documentation is under construction.

cuisto is a Python package aiming at quantifying histological data.

After ABBA registration of 2D histological slices and QuPath objects' detection, cuisto is used to :

  • compute metrics, such as objects density in each brain regions,
  • compute objects distributions in three three axes (rostro-caudal, dorso-ventral and medio-lateral),
  • compute averages and sem across animals,
  • displaying all the above.

This documentation contains cuisto installation instructions, ABBA installation instructions, guides to prepare images for the pipeline, detect objects with QuPath, register 2D slices on a 3D atlas with ABBA, along with examples.

In theory, cuisto should work with any measurements table with the required columns, but has been designed with ABBA and QuPath in mind.

Due to the IT environment of the laboratory, this documentation is very Windows-oriented but most of it should be applicable to Linux and MacOS as well by slightly adapting terminal commands.

"},{"location":"index.html#documentation-navigation","title":"Documentation navigation","text":"

The documentation outline is on the left panel, you can click on items to browse it. In each page, you'll get the table of contents on the right panel.

"},{"location":"index.html#useful-external-resources","title":"Useful external resources","text":"
  • Project repository : https://github.com/TeamNCMC/cuisto
  • QuPath documentation : https://qupath.readthedocs.io/en/stable/
  • Aligning Big Brain and Atlases (ABBA) documentation : https://abba-documentation.readthedocs.io/en/latest/
  • Brainglobe : https://brainglobe.info/
  • BraiAn, a similar but published and way more feature-packed project : https://silvalab.codeberg.page/BraiAn/
  • Image.sc community forum : https://forum.image.sc/
  • Introduction to Bioimage Analysis, an interactive book written by QuPath's creator : https://bioimagebook.github.io/index.html
"},{"location":"index.html#credits","title":"Credits","text":"

cuisto has been primarly developed by Guillaume Le Goc in Julien Bouvier's lab at NeuroPSI. The clever name was found by Aur\u00e9lie Bodeau.

The documentation itself is built with MkDocs using the Material theme.

"},{"location":"api-compute.html","title":"cuisto.compute","text":"

compute module, part of cuisto.

Contains actual computation functions.

"},{"location":"api-compute.html#cuisto.compute.get_distribution","title":"get_distribution(df, col, hue, hue_filter, per_commonnorm, binlim, nbins=100)","text":"

Computes distribution of objects.

A global distribution using only col is computed, then it computes a distribution distinguishing values in the hue column. For the latter, it is possible to use a subset of the data ony, based on another column using hue_filter. This another column is determined with hue, if the latter is \"hemisphere\", then hue_filter is used in the \"channel\" color and vice-versa. per_commonnorm controls how they are normalized, either as a whole (True) or independantly (False).

Use cases : (1) single-channel, two hemispheres : col=x, hue=hemisphere, hue_filter=\"\", per_commonorm=True. Computes a distribution for each hemisphere, the sum of the area of both is equal to 1. (2) three-channels, one hemisphere : col=x, hue=channel, hue_filter=\"Ipsi.\", per_commonnorm=False. Computes a distribution for each channel only for points in the ipsilateral hemisphere. Each curve will have an area of 1.

Parameters:

Name Type Description Default df DataFrame required col str

Key in df, used to compute the distributions.

required hue str

Key in df. Criterion for additional distributions.

required hue_filter str

Further filtering for \"per\" distribution. - hue = channel : value is the name of one of the hemisphere - hue = hemisphere : value can be the name of a channel, a list of such or \"all\"

required per_commonnorm bool

Use common normalization for all hues (per argument).

required binlim list or tuple

First bin left edge and last bin right edge.

required nbins int

Number of bins. Default is 100.

100

Returns:

Name Type Description df_distribution DataFrame

DataFrame with bins, distribution, count and their per-hemisphere or per-channel variants.

Source code in cuisto/compute.py
def get_distribution(\n    df: pd.DataFrame,\n    col: str,\n    hue: str,\n    hue_filter: dict,\n    per_commonnorm: bool,\n    binlim: tuple | list,\n    nbins=100,\n) -> pd.DataFrame:\n    \"\"\"\n    Computes distribution of objects.\n\n    A global distribution using only `col` is computed, then it computes a distribution\n    distinguishing values in the `hue` column. For the latter, it is possible to use a\n    subset of the data ony, based on another column using `hue_filter`. This another\n    column is determined with `hue`, if the latter is \"hemisphere\", then `hue_filter` is\n    used in the \"channel\" color and vice-versa.\n    `per_commonnorm` controls how they are normalized, either as a whole (True) or\n    independantly (False).\n\n    Use cases :\n    (1) single-channel, two hemispheres : `col=x`, `hue=hemisphere`, `hue_filter=\"\"`,\n    `per_commonorm=True`. Computes a distribution for each hemisphere, the sum of the\n    area of both is equal to 1.\n    (2) three-channels, one hemisphere : `col=x`, hue=`channel`,\n    `hue_filter=\"Ipsi.\", per_commonnorm=False`. Computes a distribution for each channel\n    only for points in the ipsilateral hemisphere. Each curve will have an area of 1.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    col : str\n        Key in `df`, used to compute the distributions.\n    hue : str\n        Key in `df`. Criterion for additional distributions.\n    hue_filter : str\n        Further filtering for \"per\" distribution.\n        - hue = channel : value is the name of one of the hemisphere\n        - hue = hemisphere : value can be the name of a channel, a list of such or \"all\"\n    per_commonnorm : bool\n        Use common normalization for all hues (per argument).\n    binlim : list or tuple\n        First bin left edge and last bin right edge.\n    nbins : int, optional\n        Number of bins. Default is 100.\n\n    Returns\n    -------\n    df_distribution : pandas.DataFrame\n        DataFrame with `bins`, `distribution`, `count` and their per-hemisphere or\n        per-channel variants.\n\n    \"\"\"\n\n    # - Preparation\n    bin_edges = np.linspace(*binlim, nbins + 1)  # create bins\n    df_distribution = []  # prepare list of distributions\n\n    # - Both hemispheres, all channels\n    # get raw count per bins (histogram)\n    count, bin_edges = np.histogram(df[col], bin_edges)\n    # get normalized count (pdf)\n    distribution, _ = np.histogram(df[col], bin_edges, density=True)\n    # get bin centers rather than edges to plot them\n    bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2\n\n    # make a DataFrame out of that\n    df_distribution.append(\n        pd.DataFrame(\n            {\n                \"bins\": bin_centers,\n                \"distribution\": distribution,\n                \"count\": count,\n                \"hemisphere\": \"both\",\n                \"channel\": \"all\",\n                \"axis\": col,  # keep track of what col. was used\n            }\n        )\n    )\n\n    # - Per additional criterion\n    # select data\n    df_sub = select_hemisphere_channel(df, hue, hue_filter, False)\n    hue_values = df[hue].unique()  # get grouping values\n    # total number of datapoints in the subset used for additional distribution\n    length_total = len(df_sub)\n\n    for value in hue_values:\n        # select part and coordinates\n        df_part = df_sub.loc[df_sub[hue] == value, col]\n\n        # get raw count per bins (histogram)\n        count, bin_edges = np.histogram(df_part, bin_edges)\n        # get normalized count (pdf)\n        distribution, _ = np.histogram(df_part, bin_edges, density=True)\n\n        if per_commonnorm:\n            # re-normalize so that the sum of areas of all sub-parts is 1\n            length_part = len(df_part)  # number of datapoints in that hemisphere\n            distribution *= length_part / length_total\n\n        # get bin centers rather than edges to plot them\n        bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2\n\n        # make a DataFrame out of that\n        df_distribution.append(\n            pd.DataFrame(\n                {\n                    \"bins\": bin_centers,\n                    \"distribution\": distribution,\n                    \"count\": count,\n                    hue: value,\n                    \"channel\" if hue == \"hemisphere\" else \"hemisphere\": hue_filter,\n                    \"axis\": col,  # keep track of what col. was used\n                }\n            )\n        )\n\n    return pd.concat(df_distribution)\n
"},{"location":"api-compute.html#cuisto.compute.get_regions_metrics","title":"get_regions_metrics(df_annotations, object_type, channel_names, meas_base_name, metrics_names)","text":"

Get a new DataFrame with cumulated axons segments length in each brain regions.

This is the quantification per brain regions for fibers-like objects, eg. axons. The returned DataFrame has columns \"cum. length \u00b5m\", \"cum. length mm\", \"density \u00b5m^-1\", \"density mm^-1\", \"coverage index\".

Parameters:

Name Type Description Default df_annotations DataFrame

DataFrame with an entry for each brain regions, with columns \"Area \u00b5m^2\", \"Name\", \"hemisphere\", and \"{object_type: channel} Length \u00b5m\".

required object_type str

Object type (primary classification).

required channel_names dict

Map between original channel names to something else.

required meas_base_name str required metrics_names dict required

Returns:

Name Type Description df_regions DataFrame

DataFrame with brain regions name, area and metrics.

Source code in cuisto/compute.py
def get_regions_metrics(\n    df_annotations: pd.DataFrame,\n    object_type: str,\n    channel_names: dict,\n    meas_base_name: str,\n    metrics_names: dict,\n) -> pd.DataFrame:\n    \"\"\"\n    Get a new DataFrame with cumulated axons segments length in each brain regions.\n\n    This is the quantification per brain regions for fibers-like objects, eg. axons. The\n    returned DataFrame has columns \"cum. length \u00b5m\", \"cum. length mm\", \"density \u00b5m^-1\",\n    \"density mm^-1\", \"coverage index\".\n\n    Parameters\n    ----------\n    df_annotations : pandas.DataFrame\n        DataFrame with an entry for each brain regions, with columns \"Area \u00b5m^2\",\n        \"Name\", \"hemisphere\", and \"{object_type: channel} Length \u00b5m\".\n    object_type : str\n        Object type (primary classification).\n    channel_names : dict\n        Map between original channel names to something else.\n    meas_base_name : str\n    metrics_names : dict\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        DataFrame with brain regions name, area and metrics.\n\n    \"\"\"\n    # get columns names\n    cols = df_annotations.columns\n    # get columns with fibers lengths\n    cols_colors = cols[\n        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)\n    ]\n    # select relevant data\n    cols_to_select = pd.Index([\"Name\", \"hemisphere\", \"Area \u00b5m^2\"]).append(cols_colors)\n    # sum lengths and areas of each brain regions\n    df_regions = (\n        df_annotations[cols_to_select]\n        .groupby([\"Name\", \"hemisphere\"])\n        .sum()\n        .reset_index()\n    )\n\n    # get measurement for both hemispheres (sum)\n    df_both = df_annotations[cols_to_select].groupby([\"Name\"]).sum().reset_index()\n    df_both[\"hemisphere\"] = \"both\"\n    df_regions = (\n        pd.concat([df_regions, df_both], ignore_index=True)\n        .sort_values(by=\"Name\")\n        .reset_index()\n        .drop(columns=\"index\")\n    )\n\n    # rename measurement columns to lower case\n    df_regions = df_regions.rename(\n        columns={\n            k: k.replace(meas_base_name, meas_base_name.lower()) for k in cols_colors\n        }\n    )\n\n    # update names\n    meas_base_name = meas_base_name.lower()\n    cols = df_regions.columns\n    cols_colors = cols[\n        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)\n    ]\n\n    # convert area in mm^2\n    df_regions[\"Area mm^2\"] = df_regions[\"Area \u00b5m^2\"] / 1e6\n\n    # prepare metrics\n    if \"\u00b5m\" in meas_base_name:\n        # fibers : convert to mm\n        cols_to_convert = pd.Index([col for col in cols_colors if \"\u00b5m\" in col])\n        df_regions[cols_to_convert.str.replace(\"\u00b5m\", \"mm\")] = (\n            df_regions[cols_to_convert] / 1000\n        )\n        metrics = [meas_base_name, meas_base_name.replace(\"\u00b5m\", \"mm\")]\n    else:\n        # objects : count\n        metrics = [meas_base_name]\n\n    # density = measurement / area\n    metric = metrics_names[\"density \u00b5m^-2\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[\n        cols_colors\n    ].divide(df_regions[\"Area \u00b5m^2\"], axis=0)\n    metrics.append(metric)\n    metric = metrics_names[\"density mm^-2\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[\n        cols_colors\n    ].divide(df_regions[\"Area mm^2\"], axis=0)\n    metrics.append(metric)\n\n    # coverage index = measurement\u00b2 / area\n    metric = metrics_names[\"coverage index\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = (\n        df_regions[cols_colors].pow(2).divide(df_regions[\"Area \u00b5m^2\"], axis=0)\n    )\n    metrics.append(metric)\n\n    # prepare relative metrics columns\n    metric = metrics_names[\"relative measurement\"]\n    cols_rel_meas = cols_colors.str.replace(meas_base_name, metric)\n    df_regions[cols_rel_meas] = np.nan\n    metrics.append(metric)\n    metric = metrics_names[\"relative density\"]\n    cols_dens = cols_colors.str.replace(meas_base_name, metrics_names[\"density mm^-2\"])\n    cols_rel_dens = cols_colors.str.replace(meas_base_name, metric)\n    df_regions[cols_rel_dens] = np.nan\n    metrics.append(metric)\n    # relative metrics should be defined within each hemispheres (left, right, both)\n    for hemisphere in df_regions[\"hemisphere\"].unique():\n        row_indexer = df_regions[\"hemisphere\"] == hemisphere\n\n        # relative measurement = measurement / total measurement\n        df_regions.loc[row_indexer, cols_rel_meas] = (\n            df_regions.loc[row_indexer, cols_colors]\n            .divide(df_regions.loc[row_indexer, cols_colors].sum())\n            .to_numpy()\n        )\n\n        # relative density = density / total density\n        df_regions.loc[row_indexer, cols_rel_dens] = (\n            df_regions.loc[\n                row_indexer,\n                cols_dens,\n            ]\n            .divide(df_regions.loc[row_indexer, cols_dens].sum())\n            .to_numpy()\n        )\n\n    # collect channel names\n    channels = (\n        cols_colors.str.replace(object_type + \": \", \"\")\n        .str.replace(\" \" + meas_base_name, \"\")\n        .values.tolist()\n    )\n    # collect measurements columns names\n    cols_metrics = df_regions.columns.difference(\n        pd.Index([\"Name\", \"hemisphere\", \"Area \u00b5m^2\", \"Area mm^2\"])\n    )\n    for metric in metrics:\n        cols_to_cat = [f\"{object_type}: {cn} {metric}\" for cn in channels]\n        # make sure it's part of available metrics\n        if not set(cols_to_cat) <= set(cols_metrics):\n            raise ValueError(f\"{cols_to_cat} not in DataFrame.\")\n        # group all colors in the same colors\n        df_regions[metric] = df_regions[cols_to_cat].values.tolist()\n        # remove original data\n        df_regions = df_regions.drop(columns=cols_to_cat)\n\n    # add a color tag, given their names in the configuration file\n    df_regions[\"channel\"] = len(df_regions) * [[channel_names[k] for k in channels]]\n    metrics.append(\"channel\")\n\n    # explode the dataframe so that each color has an entry\n    df_regions = df_regions.explode(metrics)\n\n    return df_regions\n
"},{"location":"api-compute.html#cuisto.compute.normalize_starter_cells","title":"normalize_starter_cells(df, cols, animal, info_file, channel_names)","text":"

Normalize data by the number of starter cells.

Parameters:

Name Type Description Default df DataFrame

Contains the data to be normalized.

required cols list - like

Columns to divide by the number of starter cells.

required animal str

Animal ID to parse the number of starter cells.

required info_file str

Full path to the TOML file with informations.

required channel_names dict

Map between original channel names to something else.

required

Returns:

Type Description DataFrame

Same df with normalized count.

Source code in cuisto/compute.py
def normalize_starter_cells(\n    df: pd.DataFrame, cols: list[str], animal: str, info_file: str, channel_names: dict\n) -> pd.DataFrame:\n    \"\"\"\n    Normalize data by the number of starter cells.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        Contains the data to be normalized.\n    cols : list-like\n        Columns to divide by the number of starter cells.\n    animal : str\n        Animal ID to parse the number of starter cells.\n    info_file : str\n        Full path to the TOML file with informations.\n    channel_names : dict\n        Map between original channel names to something else.\n\n    Returns\n    -------\n    pd.DataFrame\n        Same `df` with normalized count.\n\n    \"\"\"\n    for channel in df[\"channel\"].unique():\n        # inverse mapping channel colors : names\n        reverse_channels = {v: k for k, v in channel_names.items()}\n        nstarters = get_starter_cells(animal, reverse_channels[channel], info_file)\n\n        for col in cols:\n            df.loc[df[\"channel\"] == channel, col] = (\n                df.loc[df[\"channel\"] == channel, col] / nstarters\n            )\n\n    return df\n
"},{"location":"api-config-config.html","title":"Api config config","text":"

object_type : name of QuPath base classification (eg. without the \": subclass\" part) segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

atlas

Information related to the atlas used

name : brainglobe-atlasapi atlas name type : \"brain\" or \"cord\" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps. midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates. outline_structures : structures to show an outline of in heatmaps

channels

Information related to imaging channels

names

Must contain all classifications derived from \"object_type\" you want to process. In the form subclassification name = name to display on the plots

\"marker+\" : classification name = name to display \"marker-\" : add any number of sub-classification

colors

Must have same keys as \"names\" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

\"marker+\" : classification name = matplotlib color \"marker-\" : must have the same entries as \"names\".

hemispheres

Information related to hemispheres, same structure as channels

names

Left : Left = name to display Right : Right = name to display

colors

Must have same keys as names' keys

Left : ff516e\" # Left = matplotlib color (either #hex, color name or RGB list) Right : 960010\" # Right = matplotlib color

distributions

Spatial distributions parameters

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3) ap_lim : bins limits for anterio-posterior in mm ap_nbins : number of bins for anterio-posterior dv_lim : bins limits for dorso-ventral in mm dv_nbins : number of bins for dorso-ventral ml_lim : bins limits for medio-lateral in mm ml_nbins : number of bins for medio-lateral hue : color curves with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

display

Display parameters

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up cmap : matplotlib color map for 2D heatmaps cmap_nbins : number of bins for 2D heatmaps cmap_lim : color limits for 2D heatmaps

regions

Distributions per regions parameters

base_measurement : the name of the measurement in QuPath to derive others from. Usually \"Count\" or \"Length \u00b5m\" hue : color bars with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter=\"both\", plots the two hemisphere in mirror. normalize_starter_cells : normalize non-relative metrics by the number of starter cells

metrics

Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

\"density \u00b5m^-2\" : relevant name \"density mm^-2\" : relevant name \"coverage index\" : relevant name \"relative measurement\" : relevant name \"relative density\" : relevant name

display

nregions : number of regions to display (sorted by max.) orientation : orientation of the bars (\"h\" or \"v\") order : order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order dodge : enforce the bar not being stacked log_scale : use log. scale for metrics

metrics

name of metrics to display

\"count\" : real_name = display_name, with real_name the \"values\" in [regions.metrics] \"density mm^-2\"

files

Full path to information TOML files and atlas outlines for 2D heatmaps.

blacklist fusion outlines infos

"},{"location":"api-config.html","title":"cuisto.config","text":"

config module, part of cuisto.

Contains the Config class.

"},{"location":"api-config.html#cuisto.config.Config","title":"Config(config_file)","text":"

The configuration class.

Reads input configuration file and provides its constant.

Parameters:

Name Type Description Default config_file str

Full path to the configuration file to load.

required

Returns:

Name Type Description cfg Config object.

Constructor.

Source code in cuisto/config.py
def __init__(self, config_file):\n    \"\"\"Constructor.\"\"\"\n    with open(config_file, \"rb\") as fid:\n        cfg = tomllib.load(fid)\n\n        for key in cfg:\n            setattr(self, key, cfg[key])\n\n    self.config_file = config_file\n    self.bg_atlas = BrainGlobeAtlas(self.atlas[\"name\"], check_latest=False)\n    self.get_blacklist()\n    self.get_leaves_list()\n
"},{"location":"api-config.html#cuisto.config.Config.get_blacklist","title":"get_blacklist()","text":"

Wraps cuisto.utils.get_blacklist.

Source code in cuisto/config.py
def get_blacklist(self):\n    \"\"\"Wraps cuisto.utils.get_blacklist.\"\"\"\n\n    self.atlas[\"blacklist\"] = utils.get_blacklist(\n        self.files[\"blacklist\"], self.bg_atlas\n    )\n
"},{"location":"api-config.html#cuisto.config.Config.get_hue_palette","title":"get_hue_palette(mode)","text":"

Get color palette given hue.

Maps hue to colors in channels or hemispheres.

Parameters:

Name Type Description Default mode (hemisphere, channel) \"hemisphere\"

Returns:

Name Type Description palette dict

Maps a hue level to a color, usable in seaborn.

Source code in cuisto/config.py
def get_hue_palette(self, mode: str) -> dict:\n    \"\"\"\n    Get color palette given hue.\n\n    Maps hue to colors in channels or hemispheres.\n\n    Parameters\n    ----------\n    mode : {\"hemisphere\", \"channel\"}\n\n    Returns\n    -------\n    palette : dict\n        Maps a hue level to a color, usable in seaborn.\n\n    \"\"\"\n    params = getattr(self, mode)\n\n    if params[\"hue\"] == \"channel\":\n        # replace channels by their new names\n        palette = {\n            self.channels[\"names\"][k]: v for k, v in self.channels[\"colors\"].items()\n        }\n    elif params[\"hue\"] == \"hemisphere\":\n        # replace hemispheres by their new names\n        palette = {\n            self.hemispheres[\"names\"][k]: v\n            for k, v in self.hemispheres[\"colors\"].items()\n        }\n    else:\n        palette = None\n        warnings.warn(f\"hue={self.regions[\"display\"][\"hue\"]} not supported.\")\n\n    return palette\n
"},{"location":"api-config.html#cuisto.config.Config.get_injection_sites","title":"get_injection_sites(animals)","text":"

Get list of injection sites coordinates for each animals, for each channels.

Parameters:

Name Type Description Default animals list of str

List of animals.

required

Returns:

Name Type Description injection_sites dict

{\"x\": {channel0: [x]}, \"y\": {channel1: [y]}}

Source code in cuisto/config.py
def get_injection_sites(self, animals: list[str]) -> dict:\n    \"\"\"\n    Get list of injection sites coordinates for each animals, for each channels.\n\n    Parameters\n    ----------\n    animals : list of str\n        List of animals.\n\n    Returns\n    -------\n    injection_sites : dict\n        {\"x\": {channel0: [x]}, \"y\": {channel1: [y]}}\n\n    \"\"\"\n    injection_sites = {\n        axis: {channel: [] for channel in self.channels[\"names\"].keys()}\n        for axis in [\"x\", \"y\", \"z\"]\n    }\n\n    for animal in animals:\n        for channel in self.channels[\"names\"].keys():\n            injx, injy, injz = utils.get_injection_site(\n                animal,\n                self.files[\"infos\"],\n                channel,\n                stereo=self.distributions[\"stereo\"],\n            )\n            if injx is not None:\n                injection_sites[\"x\"][channel].append(injx)\n            if injy is not None:\n                injection_sites[\"y\"][channel].append(injy)\n            if injz is not None:\n                injection_sites[\"z\"][channel].append(injz)\n\n    return injection_sites\n
"},{"location":"api-config.html#cuisto.config.Config.get_leaves_list","title":"get_leaves_list()","text":"

Wraps utils.get_leaves_list.

Source code in cuisto/config.py
def get_leaves_list(self):\n    \"\"\"Wraps utils.get_leaves_list.\"\"\"\n\n    self.atlas[\"leaveslist\"] = utils.get_leaves_list(self.bg_atlas)\n
"},{"location":"api-display.html","title":"cuisto.display","text":"

display module, part of cuisto.

Contains display functions, essentially wrapping matplotlib and seaborn functions.

"},{"location":"api-display.html#cuisto.display.add_data_coverage","title":"add_data_coverage(df, ax, colors=None, **kwargs)","text":"

Add lines below the plot to represent data coverage.

Parameters:

Name Type Description Default df DataFrame

DataFrame with X_min and X_max on rows for each animals (on columns).

required ax Axes

Handle to axes where to add the patch.

required colors list or str or None

Colors for the patches, as a RGB list or hex list. Should be the same size as the number of patches to plot, eg. the number of columns in df. If None, default seaborn colors are used. If only one element, used for each animal.

None **kwargs passed to patches.Rectangle() {}

Returns:

Name Type Description ax Axes

Handle to updated axes.

Source code in cuisto/display.py
def add_data_coverage(\n    df: pd.DataFrame, ax: plt.Axes, colors: list | str | None = None, **kwargs\n) -> plt.Axes:\n    \"\"\"\n    Add lines below the plot to represent data coverage.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n        DataFrame with `X_min` and `X_max` on rows for each animals (on columns).\n    ax : Axes\n        Handle to axes where to add the patch.\n    colors : list or str or None, optional\n        Colors for the patches, as a RGB list or hex list. Should be the same size as\n        the number of patches to plot, eg. the number of columns in `df`. If None,\n        default seaborn colors are used. If only one element, used for each animal.\n    **kwargs : passed to patches.Rectangle()\n\n    Returns\n    -------\n    ax : Axes\n        Handle to updated axes.\n\n    \"\"\"\n    # get colors\n    ncolumns = len(df.columns)\n    if not colors:\n        colors = sns.color_palette(n_colors=ncolumns)\n    elif isinstance(colors, str) or (isinstance(colors, list) & (len(colors) == 3)):\n        colors = [colors] * ncolumns\n    elif len(colors) != ncolumns:\n        warnings.warn(f\"Wrong number of colors ({len(colors)}), using default colors.\")\n        colors = sns.color_palette(n_colors=ncolumns)\n\n    # get patch height depending on current axis limits\n    ymin, ymax = ax.get_ylim()\n    height = (ymax - ymin) * 0.02\n\n    for animal, color in zip(df.columns, colors):\n        # get patch coordinates\n        ymin, ymax = ax.get_ylim()\n        ylength = ymax - ymin\n        ybottom = ymin - 0.02 * ylength\n        xleft = df.loc[\"X_min\", animal]\n        xright = df.loc[\"X_max\", animal]\n\n        # plot patch\n        ax.add_patch(\n            patches.Rectangle(\n                (xleft, ybottom),\n                xright - xleft,\n                height,\n                label=animal,\n                color=color,\n                **kwargs,\n            )\n        )\n\n        ax.autoscale(tight=True)  # set new axes limits\n\n    ax.autoscale()  # reset scale\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.add_injection_patch","title":"add_injection_patch(X, ax, **kwargs)","text":"

Add a patch representing the injection sites.

The patch will span from the minimal coordinate to the maximal. If plotted in stereotaxic coordinates, coordinates should be converted beforehand.

Parameters:

Name Type Description Default X list

Coordinates in mm for each animals. Can be empty to not plot anything.

required ax Axes

Handle to axes where to add the patch.

required **kwargs passed to Axes.axvspan {}

Returns:

Name Type Description ax Axes

Handle to updated Axes.

Source code in cuisto/display.py
def add_injection_patch(X: list, ax: plt.Axes, **kwargs) -> plt.Axes:\n    \"\"\"\n    Add a patch representing the injection sites.\n\n    The patch will span from the minimal coordinate to the maximal.\n    If plotted in stereotaxic coordinates, coordinates should be converted beforehand.\n\n    Parameters\n    ----------\n    X : list\n        Coordinates in mm for each animals. Can be empty to not plot anything.\n    ax : Axes\n        Handle to axes where to add the patch.\n    **kwargs : passed to Axes.axvspan\n\n    Returns\n    -------\n    ax : Axes\n        Handle to updated Axes.\n\n    \"\"\"\n    # plot patch\n    if len(X) > 0:\n        ax.axvspan(min(X), max(X), **kwargs)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.draw_structure_outline","title":"draw_structure_outline(view='sagittal', structures=['root'], outline_file='', ax=None, microns=False, **kwargs)","text":"

Plot brain regions outlines in given projection.

This requires a file containing the structures outlines.

Parameters:

Name Type Description Default view str

Projection, \"sagittal\", \"coronal\" or \"top\". Default is \"sagittal\".

'sagittal' structures list[str]

List of structures acronyms whose outlines will be drawn. Default is [\"root\"].

['root'] outline_file str

Full path the outlines HDF5 file.

'' ax Axes or None

Axes where to plot the outlines. If None, get current axes (the default).

None microns bool

If False (default), converts the coordinates in mm.

False **kwargs passed to pyplot.plot() {}

Returns:

Name Type Description ax Axes Source code in cuisto/display.py
def draw_structure_outline(\n    view: str = \"sagittal\",\n    structures: list[str] = [\"root\"],\n    outline_file: str = \"\",\n    ax: plt.Axes | None = None,\n    microns: bool = False,\n    **kwargs,\n) -> plt.Axes:\n    \"\"\"\n    Plot brain regions outlines in given projection.\n\n    This requires a file containing the structures outlines.\n\n    Parameters\n    ----------\n    view : str\n        Projection, \"sagittal\", \"coronal\" or \"top\". Default is \"sagittal\".\n    structures : list[str]\n        List of structures acronyms whose outlines will be drawn. Default is [\"root\"].\n    outline_file : str\n        Full path the outlines HDF5 file.\n    ax : plt.Axes or None, optional\n        Axes where to plot the outlines. If None, get current axes (the default).\n    microns : bool, optional\n        If False (default), converts the coordinates in mm.\n    **kwargs : passed to pyplot.plot()\n\n    Returns\n    -------\n    ax : plt.Axes\n\n    \"\"\"\n    # get axes\n    if not ax:\n        ax = plt.gca()\n\n    # get units\n    if microns:\n        conv = 1\n    else:\n        conv = 1 / 1000\n\n    with h5py.File(outline_file) as f:\n        if view == \"sagittal\":\n            for structure in structures:\n                dsets = f[\"sagittal\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n        if view == \"coronal\":\n            for structure in structures:\n                dsets = f[\"coronal\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n        if view == \"top\":\n            for structure in structures:\n                dsets = f[\"top\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.nice_bar_plot","title":"nice_bar_plot(df, x='', y=[''], hue='', ylabel=[''], orient='h', nx=None, ordering=None, names_list=None, hue_mirror=False, log_scale=False, bar_kws={}, pts_kws={})","text":"

Nice bar plot of per-region objects distribution.

This is used for objects distribution across brain regions. Shows the y metric (count, aeral density, cumulated length...) in each x categories (brain regions). orient controls wether the bars are shown horizontally (default) or vertically. Input df must have an additional \"hemisphere\" column. All y are plotted in the same figure as different subplots. nx controls the number of displayed regions.

Parameters:

Name Type Description Default df DataFrame required x str

Key in df.

'' y str

Key in df.

'' hue str

Key in df.

'' ylabel list of str

Y axis labels.

[''] orient h or v

\"h\" for horizontal bars (default) or \"v\" for vertical bars.

'h' nx None or int

Number of x to show in the plot. Default is None (no limit).

None ordering None or list[str] or max

Sorted list of acronyms. Data will be sorted follwowing this order, if \"max\", sorted by descending values, if None, not sorted (default).

None names_list list or None

List of names to display. If None (default), takes the most prominent overall ones.

None hue_mirror bool

If there are 2 groups, plot in mirror. Default is False.

False log_scale bool

Set the metrics in log scale. Default is False.

False bar_kws dict

Passed to seaborn.barplot().

{} pts_kws dict

Passed to seaborn.stripplot().

{}

Returns:

Name Type Description figs list

List of figures.

Source code in cuisto/display.py
def nice_bar_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: list[str] = [\"\"],\n    hue: str = \"\",\n    ylabel: list[str] = [\"\"],\n    orient=\"h\",\n    nx: None | int = None,\n    ordering: None | list[str] | str = None,\n    names_list: None | list = None,\n    hue_mirror: bool = False,\n    log_scale: bool = False,\n    bar_kws: dict = {},\n    pts_kws: dict = {},\n) -> list[plt.Axes]:\n    \"\"\"\n    Nice bar plot of per-region objects distribution.\n\n    This is used for objects distribution across brain regions. Shows the `y` metric\n    (count, aeral density, cumulated length...) in each `x` categories (brain regions).\n    `orient` controls wether the bars are shown horizontally (default) or vertically.\n    Input `df` must have an additional \"hemisphere\" column. All `y` are plotted in the\n    same figure as different subplots. `nx` controls the number of displayed regions.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y, hue : str\n        Key in `df`.\n    ylabel : list of str\n        Y axis labels.\n    orient : \"h\" or \"v\", optional\n        \"h\" for horizontal bars (default) or \"v\" for vertical bars.\n    nx : None or int, optional\n        Number of `x` to show in the plot. Default is None (no limit).\n    ordering : None or list[str] or \"max\", optional\n        Sorted list of acronyms. Data will be sorted follwowing this order, if \"max\",\n        sorted by descending values, if None, not sorted (default).\n    names_list : list or None, optional\n        List of names to display. If None (default), takes the most prominent overall\n        ones.\n    hue_mirror : bool, optional\n        If there are 2 groups, plot in mirror. Default is False.\n    log_scale : bool, optional\n        Set the metrics in log scale. Default is False.\n    bar_kws : dict\n        Passed to seaborn.barplot().\n    pts_kws : dict\n        Passed to seaborn.stripplot().\n\n    Returns\n    -------\n    figs : list\n        List of figures.\n\n    \"\"\"\n    figs = []\n    # loop for each features\n    for yi, ylabeli in zip(y, ylabel):\n        # prepare data\n        # get nx first most prominent regions\n        if not names_list:\n            names_list_plt = (\n                df.groupby([\"Name\"])[yi].mean().sort_values(ascending=False).index[0:nx]\n            )\n        else:\n            names_list_plt = names_list\n        dfplt = df[df[\"Name\"].isin(names_list_plt)]  # limit to those regions\n        # limit hierarchy list if provided\n        if isinstance(ordering, list):\n            order = [el for el in ordering if el in names_list_plt]\n        elif ordering == \"max\":\n            order = names_list_plt\n        else:\n            order = None\n\n        # reorder keys depending on orientation and create axes\n        if orient == \"h\":\n            xp = yi\n            yp = x\n            if hue_mirror:\n                nrows = 1\n                ncols = 2\n                sharex = None\n                sharey = \"all\"\n            else:\n                nrows = 1\n                ncols = 1\n                sharex = None\n                sharey = None\n        elif orient == \"v\":\n            xp = x\n            yp = yi\n            if hue_mirror:\n                nrows = 2\n                ncols = 1\n                sharex = \"all\"\n                sharey = None\n            else:\n                nrows = 1\n                ncols = 1\n                sharex = None\n                sharey = None\n        fig, axs = plt.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey)\n\n        if hue_mirror:\n            # two graphs\n            ax1, ax2 = axs\n            # determine what will be mirrored\n            if hue == \"channel\":\n                hue_filter = \"hemisphere\"\n            elif hue == \"hemisphere\":\n                hue_filter = \"channel\"\n            # select the two types (should be left/right or two channels)\n            hue_filters = dfplt[hue_filter].unique()[0:2]\n            hue_filters.sort()  # make sure it will be always in the same order\n\n            # plot\n            for filt, ax in zip(hue_filters, [ax1, ax2]):\n                dfplt2 = dfplt[dfplt[hue_filter] == filt]\n                ax = sns.barplot(\n                    dfplt2,\n                    x=xp,\n                    y=yp,\n                    hue=hue,\n                    estimator=\"mean\",\n                    errorbar=\"se\",\n                    orient=orient,\n                    order=order,\n                    ax=ax,\n                    **bar_kws,\n                )\n                # add points\n                ax = sns.stripplot(\n                    dfplt2, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws\n                )\n\n                # cosmetics\n                if orient == \"h\":\n                    ax.set_title(f\"{hue_filter}: {filt}\")\n                    ax.set_ylabel(None)\n                    ax.set_ylim((nx + 0.5, -0.5))\n                    if log_scale:\n                        ax.set_xscale(\"log\")\n\n                elif orient == \"v\":\n                    if ax == ax1:\n                        # top title\n                        ax1.set_title(f\"{hue_filter}: {filt}\")\n                        ax.set_xlabel(None)\n                    elif ax == ax2:\n                        # use xlabel as bottom title\n                        ax2.set_xlabel(\n                            f\"{hue_filter}: {filt}\", fontsize=ax1.title.get_fontsize()\n                        )\n                    ax.set_xlim((-0.5, nx + 0.5))\n                    if log_scale:\n                        ax.set_yscale(\"log\")\n\n                    for label in ax.get_xticklabels():\n                        label.set_verticalalignment(\"center\")\n                        label.set_horizontalalignment(\"center\")\n\n            # tune axes cosmetics\n            if orient == \"h\":\n                ax1.set_xlabel(ylabeli)\n                ax2.set_xlabel(ylabeli)\n                ax1.set_xlim(\n                    ax1.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))\n                )\n                ax2.set_xlim(\n                    ax2.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))\n                )\n                ax1.invert_xaxis()\n                sns.despine(ax=ax1, left=True, top=True, right=False, bottom=False)\n                sns.despine(ax=ax2, left=False, top=True, right=True, bottom=False)\n                ax1.yaxis.tick_right()\n                ax1.tick_params(axis=\"y\", pad=20)\n                for label in ax1.get_yticklabels():\n                    label.set_verticalalignment(\"center\")\n                    label.set_horizontalalignment(\"center\")\n            elif orient == \"v\":\n                ax2.set_ylabel(ylabeli)\n                ax1.set_ylim(\n                    ax1.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))\n                )\n                ax2.set_ylim(\n                    ax2.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))\n                )\n                ax2.invert_yaxis()\n                sns.despine(ax=ax1, left=False, top=True, right=True, bottom=False)\n                sns.despine(ax=ax2, left=False, top=False, right=True, bottom=True)\n                for label in ax2.get_xticklabels():\n                    label.set_verticalalignment(\"center\")\n                    label.set_horizontalalignment(\"center\")\n                ax2.tick_params(axis=\"x\", labelrotation=90, pad=20)\n\n        else:\n            # one graph\n            ax = axs\n            # plot\n            ax = sns.barplot(\n                dfplt,\n                x=xp,\n                y=yp,\n                hue=hue,\n                estimator=\"mean\",\n                errorbar=\"se\",\n                orient=orient,\n                order=order,\n                ax=ax,\n                **bar_kws,\n            )\n            # add points\n            ax = sns.stripplot(\n                dfplt, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws\n            )\n\n            # cosmetics\n            if orient == \"h\":\n                ax.set_xlabel(ylabeli)\n                ax.set_ylabel(None)\n                ax.set_ylim((nx + 0.5, -0.5))\n                if log_scale:\n                    ax.set_xscale(\"log\")\n            elif orient == \"v\":\n                ax.set_xlabel(None)\n                ax.set_ylabel(ylabeli)\n                ax.set_xlim((-0.5, nx + 0.5))\n                if log_scale:\n                    ax.set_yscale(\"log\")\n\n        fig.tight_layout(pad=0)\n        figs.append(fig)\n\n    return figs\n
"},{"location":"api-display.html#cuisto.display.nice_distribution_plot","title":"nice_distribution_plot(df, x='', y='', hue=None, xlabel='', ylabel='', injections_sites={}, channel_colors={}, channel_names={}, ax=None, **kwargs)","text":"

Nice plot of 1D distribution of objects.

Parameters:

Name Type Description Default df DataFrame required x str

Keys in df.

'' y str

Keys in df.

'' hue str or None

Key in df. If None, no hue is used.

None xlabel str

X and Y axes labels.

'' ylabel str

X and Y axes labels.

'' injections_sites dict

List of injection sites 1D coordinates in a dict with the channel name as key. If empty, injection site is not plotted (default).

{} channel_colors dict

Required if injections_sites is not empty, dict mapping channel names to a color.

{} channel_names dict

Required if injections_sites is not empty, dict mapping channel names to a display name.

{} ax Axes or None

Axes in which to plot the figure, if None, a new figure is created (default).

None **kwargs passed to seaborn.lineplot() {}

Returns:

Name Type Description ax matplotlib axes

Handle to axes.

Source code in cuisto/display.py
def nice_distribution_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: str = \"\",\n    hue: str | None = None,\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    injections_sites: dict = {},\n    channel_colors: dict = {},\n    channel_names: dict = {},\n    ax: plt.Axes | None = None,\n    **kwargs,\n) -> plt.Axes:\n    \"\"\"\n    Nice plot of 1D distribution of objects.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y : str\n        Keys in `df`.\n    hue : str or None, optional\n        Key in `df`. If None, no hue is used.\n    xlabel, ylabel : str\n        X and Y axes labels.\n    injections_sites : dict, optional\n        List of injection sites 1D coordinates in a dict with the channel name as key.\n        If empty, injection site is not plotted (default).\n    channel_colors : dict, optional\n        Required if injections_sites is not empty, dict mapping channel names to a\n        color.\n    channel_names : dict, optional\n        Required if injections_sites is not empty, dict mapping channel names to a\n        display name.\n    ax : Axes or None, optional\n        Axes in which to plot the figure, if None, a new figure is created (default).\n    **kwargs : passed to seaborn.lineplot()\n\n    Returns\n    -------\n    ax : matplotlib axes\n        Handle to axes.\n\n    \"\"\"\n    if not ax:\n        # create figure\n        _, ax = plt.subplots(figsize=(10, 6))\n\n    ax = sns.lineplot(\n        df,\n        x=x,\n        y=y,\n        hue=hue,\n        estimator=\"mean\",\n        errorbar=\"se\",\n        ax=ax,\n        **kwargs,\n    )\n\n    for channel in injections_sites.keys():\n        ax = add_injection_patch(\n            injections_sites[channel],\n            ax,\n            color=channel_colors[channel],\n            edgecolor=None,\n            alpha=0.25,\n            label=channel_names[channel] + \": inj. site\",\n        )\n\n    ax.legend()\n    ax.set_xlabel(xlabel)\n    ax.set_ylabel(ylabel)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.nice_heatmap","title":"nice_heatmap(df, animals, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, **kwargs)","text":"

Nice plots of 2D distribution of boutons as a heatmap per animal.

Parameters:

Name Type Description Default df DataFrame required animals list-like of str

List of animals.

required x str

Keys in df.

'' y str

Keys in df.

'' xlabel str

Labels of x and y axes.

'' ylabel str

Labels of x and y axes.

'' invertx bool

Wether to inverse the x or y axes. Default is False.

False inverty bool

Wether to inverse the x or y axes. Default is False.

False **kwargs passed to seaborn.histplot() {}

Returns:

Name Type Description ax Axes or list of Axes

Handle to axes.

Source code in cuisto/display.py
def nice_heatmap(\n    df: pd.DataFrame,\n    animals: tuple[str] | list[str],\n    x: str = \"\",\n    y: str = \"\",\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    invertx: bool = False,\n    inverty: bool = False,\n    **kwargs,\n) -> list[plt.Axes] | plt.Axes:\n    \"\"\"\n    Nice plots of 2D distribution of boutons as a heatmap per animal.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    animals : list-like of str\n        List of animals.\n    x, y : str\n        Keys in `df`.\n    xlabel, ylabel : str\n        Labels of x and y axes.\n    invertx, inverty : bool, optional\n        Wether to inverse the x or y axes. Default is False.\n    **kwargs : passed to seaborn.histplot()\n\n    Returns\n    -------\n    ax : Axes or list of Axes\n        Handle to axes.\n\n    \"\"\"\n\n    # 2D distribution, per animal\n    _, axs = plt.subplots(len(animals), 1, sharex=\"all\")\n\n    for animal, ax in zip(animals, axs):\n        ax = sns.histplot(\n            df[df[\"animal\"] == animal],\n            x=x,\n            y=y,\n            ax=ax,\n            **kwargs,\n        )\n        ax.set_xlabel(xlabel)\n        ax.set_ylabel(ylabel)\n        ax.set_title(animal)\n\n        if inverty:\n            ax.invert_yaxis()\n\n    if invertx:\n        axs[-1].invert_xaxis()  # only once since all x axes are shared\n\n    return axs\n
"},{"location":"api-display.html#cuisto.display.nice_joint_plot","title":"nice_joint_plot(df, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, outline_kws={}, ax=None, **kwargs)","text":"

Joint distribution.

Used to display a 2D heatmap of objects. This is more qualitative than quantitative, for display purposes.

Parameters:

Name Type Description Default df DataFrame required x str

Keys in df.

'' y str

Keys in df.

'' xlabel str

Label of x and y axes.

'' ylabel str

Label of x and y axes.

'' invertx bool

Whether to inverse the x or y axes. Default is False for both.

False inverty bool

Whether to inverse the x or y axes. Default is False for both.

False outline_kws dict

Passed to draw_structure_outline().

{} ax Axes or None

Axes to plot in. If None, draws in current axes (default).

None **kwargs

Passed to seaborn.histplot.

{}

Returns:

Name Type Description ax Axes Source code in cuisto/display.py
def nice_joint_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: str = \"\",\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    invertx: bool = False,\n    inverty: bool = False,\n    outline_kws: dict = {},\n    ax: plt.Axes | None = None,\n    **kwargs,\n) -> plt.Figure:\n    \"\"\"\n    Joint distribution.\n\n    Used to display a 2D heatmap of objects. This is more qualitative than quantitative,\n    for display purposes.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y : str\n        Keys in `df`.\n    xlabel, ylabel : str\n        Label of x and y axes.\n    invertx, inverty : bool, optional\n        Whether to inverse the x or y axes. Default is False for both.\n    outline_kws : dict\n        Passed to draw_structure_outline().\n    ax : plt.Axes or None, optional\n        Axes to plot in. If None, draws in current axes (default).\n    **kwargs\n        Passed to seaborn.histplot.\n\n    Returns\n    -------\n    ax : plt.Axes\n\n    \"\"\"\n    if not ax:\n        ax = plt.gca()\n\n    # plot outline\n    draw_structure_outline(ax=ax, **outline_kws)\n\n    # plot joint distribution\n    sns.histplot(\n        df,\n        x=x,\n        y=y,\n        ax=ax,\n        **kwargs,\n    )\n\n    # adjust axes\n    if invertx:\n        ax.invert_xaxis()\n    if inverty:\n        ax.invert_yaxis()\n\n    # labels\n    ax.set_xlabel(xlabel)\n    ax.set_ylabel(ylabel)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.plot_1D_distributions","title":"plot_1D_distributions(dfs_distributions, cfg, df_coordinates=None)","text":"

Wraps nice_distribution_plot().

Source code in cuisto/display.py
def plot_1D_distributions(\n    dfs_distributions: list[pd.DataFrame],\n    cfg,\n    df_coordinates: pd.DataFrame = None,\n):\n    \"\"\"\n    Wraps nice_distribution_plot().\n    \"\"\"\n    # prepare figures\n    fig, axs_dist = plt.subplots(1, 3, sharey=True, figsize=(13, 6))\n    xlabels = [\n        \"Rostro-caudal position (mm)\",\n        \"Dorso-ventral position (mm)\",\n        \"Medio-lateral position (mm)\",\n    ]\n\n    # get animals\n    animals = []\n    for df in dfs_distributions:\n        animals.extend(df[\"animal\"].unique())\n    animals = set(animals)\n\n    # get injection sites\n    if cfg.distributions[\"display\"][\"show_injection\"]:\n        injection_sites = cfg.get_injection_sites(animals)\n    else:\n        injection_sites = {k: {} for k in range(3)}\n\n    # get color palette based on hue\n    hue = cfg.distributions[\"hue\"]\n    palette = cfg.get_hue_palette(\"distributions\")\n\n    # loop through each axis\n    for df_dist, ax_dist, xlabel, inj_sites in zip(\n        dfs_distributions, axs_dist, xlabels, injection_sites.values()\n    ):\n        # select data\n        if cfg.distributions[\"hue\"] == \"hemisphere\":\n            dfplt = df_dist[df_dist[\"hemisphere\"] != \"both\"]\n        elif cfg.distributions[\"hue\"] == \"channel\":\n            dfplt = df_dist[df_dist[\"channel\"] != \"all\"]\n\n        # plot\n        ax_dist = nice_distribution_plot(\n            dfplt,\n            x=\"bins\",\n            y=\"distribution\",\n            hue=hue,\n            xlabel=xlabel,\n            ylabel=\"normalized distribution\",\n            injections_sites=inj_sites,\n            channel_colors=cfg.channels[\"colors\"],\n            channel_names=cfg.channels[\"names\"],\n            linewidth=2,\n            palette=palette,\n            ax=ax_dist,\n        )\n\n        # add data coverage\n        if (\"Atlas_AP\" in df_dist[\"axis\"].unique()) & (df_coordinates is not None):\n            df_coverage = utils.get_data_coverage(df_coordinates)\n            ax_dist = add_data_coverage(df_coverage, ax_dist, edgecolor=None, alpha=0.5)\n            ax_dist.legend()\n        else:\n            ax_dist.legend().remove()\n\n    # - Distributions, per animal\n    if len(animals) > 1:\n        _, axs_dist = plt.subplots(1, 3, sharey=True)\n\n        # loop through each axis\n        for df_dist, ax_dist, xlabel, inj_sites in zip(\n            dfs_distributions, axs_dist, xlabels, injection_sites.values()\n        ):\n            # select data\n            df_dist_plot = df_dist[df_dist[\"hemisphere\"] == \"both\"]\n\n            # plot\n            ax_dist = nice_distribution_plot(\n                df_dist_plot,\n                x=\"bins\",\n                y=\"distribution\",\n                hue=\"animal\",\n                xlabel=xlabel,\n                ylabel=\"normalized distribution\",\n                injections_sites=inj_sites,\n                channel_colors=cfg.channels[\"colors\"],\n                channel_names=cfg.channels[\"names\"],\n                linewidth=2,\n                ax=ax_dist,\n            )\n\n    return fig\n
"},{"location":"api-display.html#cuisto.display.plot_2D_distributions","title":"plot_2D_distributions(df, cfg)","text":"

Wraps nice_joint_plot().

Source code in cuisto/display.py
def plot_2D_distributions(df: pd.DataFrame, cfg):\n    \"\"\"\n    Wraps nice_joint_plot().\n    \"\"\"\n    # -- 2D heatmap, all animals pooled\n    # prepare figure\n    fig_heatmap = plt.figure(figsize=(12, 9))\n\n    ax_sag = fig_heatmap.add_subplot(2, 2, 1)\n    ax_cor = fig_heatmap.add_subplot(2, 2, 2, sharey=ax_sag)\n    ax_top = fig_heatmap.add_subplot(2, 2, 3, sharex=ax_sag)\n    ax_cbar = fig_heatmap.add_subplot(2, 2, 4, box_aspect=15)\n\n    # prepare options\n    map_options = dict(\n        bins=cfg.distributions[\"display\"][\"cmap_nbins\"],\n        cmap=cfg.distributions[\"display\"][\"cmap\"],\n        rasterized=True,\n        thresh=10,\n        stat=\"count\",\n        vmin=cfg.distributions[\"display\"][\"cmap_lim\"][0],\n        vmax=cfg.distributions[\"display\"][\"cmap_lim\"][1],\n    )\n    outline_kws = dict(\n        structures=cfg.atlas[\"outline_structures\"],\n        outline_file=cfg.files[\"outlines\"],\n        linewidth=1.5,\n        color=\"k\",\n    )\n    cbar_kws = dict(label=\"count\")\n\n    # determine which axes are going to be inverted\n    if cfg.atlas[\"type\"] == \"brain\":\n        cor_invertx = True\n        cor_inverty = False\n        top_invertx = True\n        top_inverty = False\n    elif cfg.atlas[\"type\"] == \"cord\":\n        cor_invertx = False\n        cor_inverty = False\n        top_invertx = True\n        top_inverty = True\n\n    # - sagittal\n    # no need to invert axes because they are shared with the two other views\n    outline_kws[\"view\"] = \"sagittal\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_X\",\n        y=\"Atlas_Y\",\n        xlabel=\"Rostro-caudal (mm)\",\n        ylabel=\"Dorso-ventral (mm)\",\n        outline_kws=outline_kws,\n        ax=ax_sag,\n        **map_options,\n    )\n\n    # - coronal\n    outline_kws[\"view\"] = \"coronal\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_Z\",\n        y=\"Atlas_Y\",\n        xlabel=\"Medio-lateral (mm)\",\n        ylabel=\"Dorso-ventral (mm)\",\n        invertx=cor_invertx,\n        inverty=cor_inverty,\n        outline_kws=outline_kws,\n        ax=ax_cor,\n        **map_options,\n    )\n    ax_cor.invert_yaxis()\n\n    # - top\n    outline_kws[\"view\"] = \"top\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_X\",\n        y=\"Atlas_Z\",\n        xlabel=\"Rostro-caudal (mm)\",\n        ylabel=\"Medio-lateral (mm)\",\n        invertx=top_invertx,\n        inverty=top_inverty,\n        outline_kws=outline_kws,\n        ax=ax_top,\n        cbar=True,\n        cbar_ax=ax_cbar,\n        cbar_kws=cbar_kws,\n        **map_options,\n    )\n    fig_heatmap.suptitle(\"sagittal, coronal and top-view projections\")\n\n    # -- 2D heatmap per animals\n    # get animals\n    animals = df[\"animal\"].unique()\n    if len(animals) > 1:\n        # Rostro-caudal, dorso-ventral (sagittal)\n        _ = nice_heatmap(\n            df,\n            animals,\n            x=\"Atlas_X\",\n            y=\"Atlas_Y\",\n            xlabel=\"Rostro-caudal (mm)\",\n            ylabel=\"Dorso-ventral (mm)\",\n            invertx=True,\n            inverty=True,\n            cmap=\"OrRd\",\n            rasterized=True,\n            cbar=True,\n        )\n\n        # Medio-lateral, dorso-ventral (coronal)\n        _ = nice_heatmap(\n            df,\n            animals,\n            x=\"Atlas_Z\",\n            y=\"Atlas_Y\",\n            xlabel=\"Medio-lateral (mm)\",\n            ylabel=\"Dorso-ventral (mm)\",\n            inverty=True,\n            invertx=True,\n            cmap=\"OrRd\",\n            rasterized=True,\n        )\n\n    return fig_heatmap\n
"},{"location":"api-display.html#cuisto.display.plot_regions","title":"plot_regions(df, cfg, **kwargs)","text":"

Wraps nice_bar_plot().

Source code in cuisto/display.py
def plot_regions(df: pd.DataFrame, cfg, **kwargs):\n    \"\"\"\n    Wraps nice_bar_plot().\n    \"\"\"\n    # get regions order\n    if cfg.regions[\"display\"][\"order\"] == \"ontology\":\n        regions_order = [d[\"acronym\"] for d in cfg.bg_atlas.structures_list]\n    elif cfg.regions[\"display\"][\"order\"] == \"max\":\n        regions_order = \"max\"\n    else:\n        regions_order = None\n\n    # determine metrics to be plotted and color palette based on hue\n    metrics = [*cfg.regions[\"display\"][\"metrics\"].keys()]\n    hue = cfg.regions[\"hue\"]\n    palette = cfg.get_hue_palette(\"regions\")\n\n    # select data\n    dfplt = utils.select_hemisphere_channel(\n        df, hue, cfg.regions[\"hue_filter\"], cfg.regions[\"hue_mirror\"]\n    )\n\n    # prepare options\n    bar_kws = dict(\n        err_kws={\"linewidth\": 1.5},\n        dodge=cfg.regions[\"display\"][\"dodge\"],\n        palette=palette,\n    )\n    pts_kws = dict(\n        size=4,\n        edgecolor=\"auto\",\n        linewidth=0.75,\n        dodge=cfg.regions[\"display\"][\"dodge\"],\n        palette=palette,\n    )\n    # draw\n    figs = nice_bar_plot(\n        dfplt,\n        x=\"Name\",\n        y=metrics,\n        hue=hue,\n        ylabel=[*cfg.regions[\"display\"][\"metrics\"].values()],\n        orient=cfg.regions[\"display\"][\"orientation\"],\n        nx=cfg.regions[\"display\"][\"nregions\"],\n        ordering=regions_order,\n        hue_mirror=cfg.regions[\"hue_mirror\"],\n        log_scale=cfg.regions[\"display\"][\"log_scale\"],\n        bar_kws=bar_kws,\n        pts_kws=pts_kws,\n        **kwargs,\n    )\n\n    return figs\n
"},{"location":"api-io.html","title":"cuisto.io","text":"

io module, part of cuisto.

Contains loading and saving functions.

"},{"location":"api-io.html#cuisto.io.cat_csv_dir","title":"cat_csv_dir(directory, **kwargs)","text":"

Scans a directory for csv files and concatenate them into a single DataFrame.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required **kwargs passed to pandas.read_csv() {}

Returns:

Name Type Description df DataFrame

All CSV files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_csv_dir(directory, **kwargs) -> pd.DataFrame:\n    \"\"\"\n    Scans a directory for csv files and concatenate them into a single DataFrame.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    **kwargs : passed to pandas.read_csv()\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        All CSV files concatenated in a single DataFrame.\n\n    \"\"\"\n    return pd.concat(\n        pd.read_csv(\n            os.path.join(directory, filename),\n            **kwargs,\n        )\n        for filename in os.listdir(directory)\n        if (filename.endswith(\".csv\"))\n        and not check_empty_file(os.path.join(directory, filename), threshold=1)\n    )\n
"},{"location":"api-io.html#cuisto.io.cat_data_dir","title":"cat_data_dir(directory, segtype, **kwargs)","text":"

Wraps either cat_csv_dir() or cat_json_dir() depending on segtype.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required segtype str

\"synaptophysin\" or \"fibers\".

required **kwargs passed to cat_csv_dir() or cat_json_dir(). {}

Returns:

Name Type Description df DataFrame

All files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_data_dir(directory: str, segtype: str, **kwargs) -> pd.DataFrame:\n    \"\"\"\n    Wraps either cat_csv_dir() or cat_json_dir() depending on `segtype`.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    segtype : str\n        \"synaptophysin\" or \"fibers\".\n    **kwargs : passed to cat_csv_dir() or cat_json_dir().\n\n    Returns\n    -------\n    df : pd.DataFrame\n        All files concatenated in a single DataFrame.\n\n    \"\"\"\n    if segtype in CSV_KW:\n        # remove kwargs for json\n        kwargs.pop(\"hemisphere_names\", None)\n        kwargs.pop(\"atlas\", None)\n        return cat_csv_dir(directory, **kwargs)\n    elif segtype in JSON_KW:\n        kwargs = {k: kwargs[k] for k in [\"hemisphere_names\", \"atlas\"] if k in kwargs}\n        return cat_json_dir(directory, **kwargs)\n    else:\n        raise ValueError(\n            f\"'{segtype}' not supported, unable to determine if CSV or JSON.\"\n        )\n
"},{"location":"api-io.html#cuisto.io.cat_json_dir","title":"cat_json_dir(directory, hemisphere_names, atlas)","text":"

Scans a directory for json files and concatenate them in a single DataFrame.

The json files must be generated with 'workflow_import_export.groovy\" from a QuPath project.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required hemisphere_names dict

Maps between hemisphere names in the json files (\"Right\" and \"Left\") to something else (eg. \"Ipsi.\" and \"Contra.\").

required atlas BrainGlobeAtlas

Atlas to read regions from.

required

Returns:

Name Type Description df DataFrame

All JSON files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_json_dir(\n    directory: str, hemisphere_names: dict, atlas: BrainGlobeAtlas\n) -> pd.DataFrame:\n    \"\"\"\n    Scans a directory for json files and concatenate them in a single DataFrame.\n\n    The json files must be generated with 'workflow_import_export.groovy\" from a QuPath\n    project.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    hemisphere_names : dict\n        Maps between hemisphere names in the json files (\"Right\" and \"Left\") to\n        something else (eg. \"Ipsi.\" and \"Contra.\").\n    atlas : BrainGlobeAtlas\n        Atlas to read regions from.\n\n    Returns\n    -------\n    df : pd.DataFrame\n        All JSON files concatenated in a single DataFrame.\n\n    \"\"\"\n    # list files\n    files_list = [\n        os.path.join(directory, filename)\n        for filename in os.listdir(directory)\n        if (filename.endswith(\".json\"))\n    ]\n\n    data = []  # prepare list of DataFrame\n    for filename in files_list:\n        with open(filename, \"rb\") as fid:\n            df = pd.DataFrame.from_dict(\n                orjson.loads(fid.read())[\"paths\"], orient=\"index\"\n            )\n            df[\"Image\"] = os.path.basename(filename).split(\"_detections\")[0]\n            data.append(df)\n\n    df = (\n        pd.concat(data)\n        .explode(\n            [\"x\", \"y\", \"z\", \"hemisphere\"]\n        )  # get an entry for each point of segments\n        .reset_index()\n        .rename(\n            columns=dict(\n                x=\"Atlas_X\",\n                y=\"Atlas_Y\",\n                z=\"Atlas_Z\",\n                index=\"Object ID\",\n                classification=\"Classification\",\n            )\n        )\n        .set_index(\"Object ID\")\n    )\n\n    # change hemisphere names\n    df[\"hemisphere\"] = df[\"hemisphere\"].map(hemisphere_names)\n\n    # add object type\n    df[\"Object type\"] = \"Detection\"\n\n    # add brain regions\n    df = utils.add_brain_region(df, atlas, col=\"Parent\")\n\n    return df\n
"},{"location":"api-io.html#cuisto.io.check_empty_file","title":"check_empty_file(filename, threshold=1)","text":"

Checks if a file is empty.

Empty is defined as a file whose number of lines is lower than or equal to threshold (to allow for headers).

Parameters:

Name Type Description Default filename str

Full path to the file to check.

required threshold int

If number of lines is lower than or equal to this value, it is considered as empty. Default is 1.

1

Returns:

Name Type Description empty bool

True if the file is empty as defined above.

Source code in cuisto/io.py
def check_empty_file(filename: str, threshold: int = 1) -> bool:\n    \"\"\"\n    Checks if a file is empty.\n\n    Empty is defined as a file whose number of lines is lower than or equal to\n    `threshold` (to allow for headers).\n\n    Parameters\n    ----------\n    filename : str\n        Full path to the file to check.\n    threshold : int, optional\n        If number of lines is lower than or equal to this value, it is considered as\n        empty. Default is 1.\n\n    Returns\n    -------\n    empty : bool\n        True if the file is empty as defined above.\n\n    \"\"\"\n    with open(filename, \"rb\") as fid:\n        nlines = sum(1 for _ in fid)\n\n    if nlines <= threshold:\n        return True\n    else:\n        return False\n
"},{"location":"api-io.html#cuisto.io.get_measurements_directory","title":"get_measurements_directory(wdir, animal, kind, segtype)","text":"

Get the directory with detections or annotations measurements for given animal ID.

Parameters:

Name Type Description Default wdir str

Base working directory.

required animal str

Animal ID.

required kind str

\"annotation\" or \"detection\".

required segtype str

Type of segmentation, eg. \"synaptophysin\".

required

Returns:

Name Type Description directory str

Path to detections or annotations directory.

Source code in cuisto/io.py
def get_measurements_directory(wdir, animal: str, kind: str, segtype: str) -> str:\n    \"\"\"\n    Get the directory with detections or annotations measurements for given animal ID.\n\n    Parameters\n    ----------\n    wdir : str\n        Base working directory.\n    animal : str\n        Animal ID.\n    kind : str\n        \"annotation\" or \"detection\".\n    segtype : str\n        Type of segmentation, eg. \"synaptophysin\".\n\n    Returns\n    -------\n    directory : str\n        Path to detections or annotations directory.\n\n    \"\"\"\n    bdir = os.path.join(wdir, animal, animal.lower() + \"_segmentation\", segtype)\n\n    if (kind == \"detection\") or (kind == \"detections\"):\n        return os.path.join(bdir, \"detections\")\n    elif (kind == \"annotation\") or (kind == \"annotations\"):\n        return os.path.join(bdir, \"annotations\")\n    else:\n        raise ValueError(\n            f\"kind = '{kind}' not supported. Choose 'detection' or 'annotation'.\"\n        )\n
"},{"location":"api-io.html#cuisto.io.load_dfs","title":"load_dfs(filepath, fmt, identifiers=['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml'])","text":"

Load DataFrames from file.

If fmt is \"h5\" (\"xslx\"), identifiers are interpreted as h5 group identifier (sheet name, respectively). If fmt is \"pickle\", \"csv\" or \"tsv\", identifiers are appended to filename. Path to the file can't have a dot (\".\") in it.

Parameters:

Name Type Description Default filepath str

Full path to the file(s), without extension.

required fmt (h5, csv, pickle, xlsx)

File(s) format.

\"h5\" identifiers list of str

List of identifiers to load from files. Defaults to the ones saved in cuisto.process.process_animals().

['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml']

Returns:

Type Description All requested DataFrames. Source code in cuisto/io.py
def load_dfs(\n    filepath: str,\n    fmt: str,\n    identifiers: list[str] = [\n        \"df_regions\",\n        \"df_coordinates\",\n        \"df_distribution_ap\",\n        \"df_distribution_dv\",\n        \"df_distribution_ml\",\n    ],\n):\n    \"\"\"\n    Load DataFrames from file.\n\n    If `fmt` is \"h5\" (\"xslx\"), identifiers are interpreted as h5 group identifier (sheet\n    name, respectively).\n    If `fmt` is \"pickle\", \"csv\" or \"tsv\", identifiers are appended to `filename`.\n    Path to the file can't have a dot (\".\") in it.\n\n    Parameters\n    ----------\n    filepath : str\n        Full path to the file(s), without extension.\n    fmt : {\"h5\", \"csv\", \"pickle\", \"xlsx\"}\n        File(s) format.\n    identifiers : list of str, optional\n        List of identifiers to load from files. Defaults to the ones saved in\n        cuisto.process.process_animals().\n\n    Returns\n    -------\n    All requested DataFrames.\n\n    \"\"\"\n    # ensure filename without extension\n    base_path = os.path.splitext(filepath)[0]\n    full_path = base_path + \".\" + fmt\n\n    res = []\n    if (fmt == \"h5\") or (fmt == \"hdf\") or (fmt == \"hdf5\"):\n        for identifier in identifiers:\n            res.append(pd.read_hdf(full_path, identifier))\n    elif fmt == \"xlsx\":\n        for identifier in identifiers:\n            res.append(pd.read_excel(full_path, sheet_name=identifier))\n    else:\n        for identifier in identifiers:\n            id_path = f\"{base_path}_{identifier}.{fmt}\"\n            if (fmt == \"pickle\") or (fmt == \"pkl\"):\n                res.append(pd.read_pickle(id_path))\n            elif fmt == \"csv\":\n                res.append(pd.read_csv(id_path))\n            elif fmt == \"tsv\":\n                res.append(pd.read_csv(id_path, sep=\"\\t\"))\n            else:\n                raise ValueError(f\"{fmt} is not supported.\")\n\n    return res\n
"},{"location":"api-io.html#cuisto.io.save_dfs","title":"save_dfs(out_dir, filename, dfs)","text":"

Save DataFrames to file.

File format is inferred from file name extension.

Parameters:

Name Type Description Default out_dir str

Output directory.

required filename _type_

File name.

required dfs dict

DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in the same file, otherwise identifier is appended to the file name.

required Source code in cuisto/io.py
def save_dfs(out_dir: str, filename, dfs: dict):\n    \"\"\"\n    Save DataFrames to file.\n\n    File format is inferred from file name extension.\n\n    Parameters\n    ----------\n    out_dir : str\n        Output directory.\n    filename : _type_\n        File name.\n    dfs : dict\n        DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in\n        the same file, otherwise identifier is appended to the file name.\n\n    \"\"\"\n    if not os.path.isdir(out_dir):\n        os.makedirs(out_dir)\n\n    basename, ext = os.path.splitext(filename)\n    if ext in [\".h5\", \".hdf\", \".hdf5\"]:\n        path = os.path.join(out_dir, filename)\n        for identifier, df in dfs.items():\n            df.to_hdf(path, key=identifier)\n    elif ext == \".xlsx\":\n        for identifier, df in dfs.items():\n            df.to_excel(path, sheet_name=identifier)\n    else:\n        for identifier, df in dfs.items():\n            path = os.path.join(out_dir, f\"{basename}_{identifier}{ext}\")\n            if ext in [\".pickle\", \".pkl\"]:\n                df.to_pickle(path)\n            elif ext == \".csv\":\n                df.to_csv(path)\n            elif ext == \".tsv\":\n                df.to_csv(path, sep=\"\\t\")\n            else:\n                raise ValueError(f\"{filename} has an unsupported extension.\")\n
"},{"location":"api-process.html","title":"cuisto.process","text":"

process module, part of cuisto.

Wraps other functions for a click&play behaviour. Relies on the configuration file.

"},{"location":"api-process.html#cuisto.process.process_animal","title":"process_animal(animal, df_annotations, df_detections, cfg, compute_distributions=True)","text":"

Quantify objects for one animal.

Fetch required files and compute objects' distributions in brain regions, spatial distributions and gather Atlas coordinates.

Parameters:

Name Type Description Default animal str

Animal ID.

required df_annotations DataFrame

DataFrames of QuPath Annotations and Detections.

required df_detections DataFrame

DataFrames of QuPath Annotations and Detections.

required cfg Config

The configuration loaded from TOML configuration file.

required compute_distributions bool

If False, do not compute the 1D distributions and return an empty list.Default is True.

True

Returns:

Name Type Description df_regions DataFrame

Metrics in brain regions. One entry for each hemisphere of each brain regions.

df_distribution list of pandas.DataFrame

Rostro-caudal distribution, as raw count and probability density function, in each axis.

df_coordinates DataFrame

Atlas coordinates of each points.

Source code in cuisto/process.py
def process_animal(\n    animal: str,\n    df_annotations: pd.DataFrame,\n    df_detections: pd.DataFrame,\n    cfg,\n    compute_distributions: bool = True,\n) -> tuple[pd.DataFrame, list[pd.DataFrame], pd.DataFrame]:\n    \"\"\"\n    Quantify objects for one animal.\n\n    Fetch required files and compute objects' distributions in brain regions, spatial\n    distributions and gather Atlas coordinates.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    df_annotations, df_detections : pd.DataFrame\n        DataFrames of QuPath Annotations and Detections.\n    cfg : cuisto.Config\n        The configuration loaded from TOML configuration file.\n    compute_distributions : bool, optional\n        If False, do not compute the 1D distributions and return an empty list.Default\n        is True.\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        Metrics in brain regions. One entry for each hemisphere of each brain regions.\n    df_distribution : list of pandas.DataFrame\n        Rostro-caudal distribution, as raw count and probability density function, in\n        each axis.\n    df_coordinates : pandas.DataFrame\n        Atlas coordinates of each points.\n\n    \"\"\"\n    # - Annotations data cleanup\n    # filter regions\n    df_annotations = utils.filter_df_regions(\n        df_annotations, [\"Root\", \"root\"], mode=\"remove\", col=\"Name\"\n    )\n    df_annotations = utils.filter_df_regions(\n        df_annotations, cfg.atlas[\"blacklist\"], mode=\"remove\", col=\"Name\"\n    )\n    # add hemisphere\n    df_annotations = utils.add_hemisphere(df_annotations, cfg.hemispheres[\"names\"])\n    # remove objects in non-leaf regions\n    df_annotations = utils.filter_df_regions(\n        df_annotations, cfg.atlas[\"leaveslist\"], mode=\"keep\", col=\"Name\"\n    )\n    # merge regions\n    df_annotations = utils.merge_regions(\n        df_annotations, col=\"Name\", fusion_file=cfg.files[\"fusion\"]\n    )\n    if compute_distributions:\n        # - Detections data cleanup\n        # remove objects not in selected classifications\n        df_detections = utils.filter_df_classifications(\n            df_detections, cfg.object_type, mode=\"keep\", col=\"Classification\"\n        )\n        # remove objects from blacklisted regions and \"Root\"\n        df_detections = utils.filter_df_regions(\n            df_detections, cfg.atlas[\"blacklist\"], mode=\"remove\", col=\"Parent\"\n        )\n        # add hemisphere\n        df_detections = utils.add_hemisphere(\n            df_detections,\n            cfg.hemispheres[\"names\"],\n            cfg.atlas[\"midline\"],\n            col=\"Atlas_Z\",\n            atlas_type=cfg.atlas[\"type\"],\n        )\n        # add detection channel\n        df_detections = utils.add_channel(\n            df_detections, cfg.object_type, cfg.channels[\"names\"]\n        )\n        # convert coordinates to mm\n        df_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[\n            [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]\n        ].divide(1000)\n        # convert to sterotaxic coordinates\n        if cfg.distributions[\"stereo\"]:\n            (\n                df_detections[\"Atlas_AP\"],\n                df_detections[\"Atlas_DV\"],\n                df_detections[\"Atlas_ML\"],\n            ) = utils.ccf_to_stereo(\n                df_detections[\"Atlas_X\"],\n                df_detections[\"Atlas_Y\"],\n                df_detections[\"Atlas_Z\"],\n            )\n        else:\n            (\n                df_detections[\"Atlas_AP\"],\n                df_detections[\"Atlas_DV\"],\n                df_detections[\"Atlas_ML\"],\n            ) = (\n                df_detections[\"Atlas_X\"],\n                df_detections[\"Atlas_Y\"],\n                df_detections[\"Atlas_Z\"],\n            )\n\n    # - Computations\n    # get regions distributions\n    df_regions = compute.get_regions_metrics(\n        df_annotations,\n        cfg.object_type,\n        cfg.channels[\"names\"],\n        cfg.regions[\"base_measurement\"],\n        cfg.regions[\"metrics\"],\n    )\n    colstonorm = [v for v in cfg.regions[\"metrics\"].values() if \"relative\" not in v]\n\n    # normalize by starter cells\n    if cfg.regions[\"normalize_starter_cells\"]:\n        df_regions = compute.normalize_starter_cells(\n            df_regions, colstonorm, animal, cfg.files[\"infos\"], cfg.channels[\"names\"]\n        )\n\n    # get AP, DV, ML distributions in stereotaxic coordinates\n    if compute_distributions:\n        dfs_distributions = [\n            compute.get_distribution(\n                df_detections,\n                axis,\n                cfg.distributions[\"hue\"],\n                cfg.distributions[\"hue_filter\"],\n                cfg.distributions[\"common_norm\"],\n                stereo_lim,\n                nbins=nbins,\n            )\n            for axis, stereo_lim, nbins in zip(\n                [\"Atlas_AP\", \"Atlas_DV\", \"Atlas_ML\"],\n                [\n                    cfg.distributions[\"ap_lim\"],\n                    cfg.distributions[\"dv_lim\"],\n                    cfg.distributions[\"ml_lim\"],\n                ],\n                [\n                    cfg.distributions[\"ap_nbins\"],\n                    cfg.distributions[\"dv_nbins\"],\n                    cfg.distributions[\"dv_nbins\"],\n                ],\n            )\n        ]\n    else:\n        dfs_distributions = []\n\n    # add animal tag to each DataFrame\n    df_detections[\"animal\"] = animal\n    df_regions[\"animal\"] = animal\n    for df in dfs_distributions:\n        df[\"animal\"] = animal\n\n    return df_regions, dfs_distributions, df_detections\n
"},{"location":"api-process.html#cuisto.process.process_animals","title":"process_animals(wdir, animals, cfg, out_fmt=None, compute_distributions=True)","text":"

Get data from all animals and plot.

Parameters:

Name Type Description Default wdir str

Base working directory, containing animals folders.

required animals list-like of str

List of animals ID.

required cfg

Configuration object.

required out_fmt (None, h5, csv, tsv, xslx, pickle)

Output file(s) format, if None, nothing is saved (default).

None compute_distributions bool

If False, do not compute the 1D distributions and return an empty list.Default is True.

True

Returns:

Name Type Description df_regions DataFrame

Metrics in brain regions. One entry for each hemisphere of each brain regions.

df_distribution list of pandas.DataFrame

Rostro-caudal distribution, as raw count and probability density function, in each axis.

df_coordinates DataFrame

Atlas coordinates of each points.

Source code in cuisto/process.py
def process_animals(\n    wdir: str,\n    animals: list[str] | tuple[str],\n    cfg,\n    out_fmt: str | None = None,\n    compute_distributions: bool = True,\n) -> tuple[pd.DataFrame]:\n    \"\"\"\n    Get data from all animals and plot.\n\n    Parameters\n    ----------\n    wdir : str\n        Base working directory, containing `animals` folders.\n    animals : list-like of str\n        List of animals ID.\n    cfg: cuisto.Config\n        Configuration object.\n    out_fmt : {None, \"h5\", \"csv\", \"tsv\", \"xslx\", \"pickle\"}\n        Output file(s) format, if None, nothing is saved (default).\n    compute_distributions : bool, optional\n        If False, do not compute the 1D distributions and return an empty list.Default\n        is True.\n\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        Metrics in brain regions. One entry for each hemisphere of each brain regions.\n    df_distribution : list of pandas.DataFrame\n        Rostro-caudal distribution, as raw count and probability density function, in\n        each axis.\n    df_coordinates : pandas.DataFrame\n        Atlas coordinates of each points.\n\n    \"\"\"\n\n    # -- Preparation\n    df_regions = []\n    dfs_distributions = []\n    df_coordinates = []\n\n    # -- Processing\n    pbar = tqdm(animals)\n\n    for animal in pbar:\n        pbar.set_description(f\"Processing {animal}\")\n\n        # combine all detections and annotations from this animal\n        df_annotations = io.cat_csv_dir(\n            io.get_measurements_directory(\n                wdir, animal, \"annotation\", cfg.segmentation_tag\n            ),\n            index_col=\"Object ID\",\n            sep=\"\\t\",\n        )\n        if compute_distributions:\n            df_detections = io.cat_data_dir(\n                io.get_measurements_directory(\n                    wdir, animal, \"detection\", cfg.segmentation_tag\n                ),\n                cfg.segmentation_tag,\n                index_col=\"Object ID\",\n                sep=\"\\t\",\n                hemisphere_names=cfg.hemispheres[\"names\"],\n                atlas=cfg.bg_atlas,\n            )\n        else:\n            df_detections = pd.DataFrame()\n\n        # get results\n        df_reg, dfs_dis, df_coo = process_animal(\n            animal,\n            df_annotations,\n            df_detections,\n            cfg,\n            compute_distributions=compute_distributions,\n        )\n\n        # collect results\n        df_regions.append(df_reg)\n        dfs_distributions.append(dfs_dis)\n        df_coordinates.append(df_coo)\n\n    # concatenate all results\n    df_regions = pd.concat(df_regions, ignore_index=True)\n    dfs_distributions = [\n        pd.concat(dfs_list, ignore_index=True) for dfs_list in zip(*dfs_distributions)\n    ]\n    df_coordinates = pd.concat(df_coordinates, ignore_index=True)\n\n    # -- Saving\n    if out_fmt:\n        outdir = os.path.join(wdir, \"quantification\")\n        outfile = f\"{cfg.object_type.lower()}_{cfg.atlas[\"type\"]}_{'-'.join(animals)}.{out_fmt}\"\n        dfs = dict(\n            df_regions=df_regions,\n            df_coordinates=df_coordinates,\n            df_distribution_ap=dfs_distributions[0],\n            df_distribution_dv=dfs_distributions[1],\n            df_distribution_ml=dfs_distributions[2],\n        )\n        io.save_dfs(outdir, outfile, dfs)\n\n    return df_regions, dfs_distributions, df_coordinates\n
"},{"location":"api-script-qupath-script-runner.html","title":"qupath_script_runner","text":"

Template to show how to run groovy script with QuPath, multi-threaded.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.EXCLUDE_LIST","title":"EXCLUDE_LIST = [] module-attribute","text":"

Images names to NOT run the script on.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.NTHREADS","title":"NTHREADS = 5 module-attribute","text":"

Number of threads to use.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QPROJ_PATH","title":"QPROJ_PATH = '/path/to/qupath/project.qproj' module-attribute","text":"

Full path to the QuPath project.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QUIET","title":"QUIET = True module-attribute","text":"

Use QuPath in quiet mode, eg. with minimal verbosity.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QUPATH_EXE","title":"QUPATH_EXE = '/path/to/the/qupath/QuPath-0.5.1 (console).exe' module-attribute","text":"

Path to the QuPath executable (console mode).

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.SAVE","title":"SAVE = True module-attribute","text":"

Whether to save the project after the script ran on an image.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.SCRIPT_PATH","title":"SCRIPT_PATH = '/path/to/the/script.groovy' module-attribute","text":"

Path to the groovy script.

"},{"location":"api-script-segment.html","title":"segment_images","text":"

Script to segment objects from images.

For fiber-like objects, binarize and skeletonize the image, then use skan to extract branches coordinates. For polygon-like objects, binarize the image and detect objects and extract contours coordinates. For points, treat that as polygons then extract the centroids instead of contours. Finally, export the coordinates as collections in geojson files, importable in QuPath. Supports any number of channel of interest within the same image. One file output file per channel will be created.

This script uses cuisto.seg. It is designed to work on probability maps generated from a pixel classifier in QuPath, but might work on raw images.

Usage : fill-in the Parameters section of the script and run it. A \"geojson\" folder will be created in the parent directory of IMAGES_DIR. To exclude objects near the edges of an ROI, specify the path to masks stored as images with the same names as probabilities images (without their suffix).

author : Guillaume Le Goc (g.legoc@posteo.org) @ NeuroPSI version : 2024.12.10

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.CHANNELS_PARAMS","title":"CHANNELS_PARAMS = [{'name': 'cy5', 'target_channel': 0, 'proba_threshold': 0.85, 'qp_class': 'Fibers: Cy5', 'qp_color': [164, 250, 120]}, {'name': 'dsred', 'target_channel': 1, 'proba_threshold': 0.65, 'qp_class': 'Fibers: DsRed', 'qp_color': [224, 153, 18]}, {'name': 'egfp', 'target_channel': 2, 'proba_threshold': 0.85, 'qp_class': 'Fibers: EGFP', 'qp_color': [135, 11, 191]}] module-attribute","text":"

This should be a list of dictionary (one per channel) with keys :

  • name: str, used as suffix for output geojson files, not used if only one channel
  • target_channel: int, index of the segmented channel of the image, 0-based
  • proba_threshold: float < 1, probability cut-off for that channel
  • qp_class: str, name of QuPath classification
  • qp_color: list of RGB values, associated color
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.EDGE_DIST","title":"EDGE_DIST = 0 module-attribute","text":"

Distance to brain edge to ignore, in \u00b5m. 0 to disable.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.FILTERS","title":"FILTERS = {'length_low': 1.5, 'area_low': 10, 'area_high': 1000, 'ecc_low': 0.0, 'ecc_high': 0.9, 'dist_thresh': 30} module-attribute","text":"

Dictionary with keys :

  • length_low: minimal length in microns - for lines
  • area_low: minimal area in \u00b5m\u00b2 - for polygons and points
  • area_high: maximal area in \u00b5m\u00b2 - for polygons and points
  • ecc_low: minimal eccentricity - for polygons and points (0 = circle)
  • ecc_high: maximal eccentricity - for polygons and points (1 = line)
  • dist_thresh: maximal inter-point distance in \u00b5m - for points
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.IMAGES_DIR","title":"IMAGES_DIR = '/path/to/images' module-attribute","text":"

Full path to the images to segment.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.IMG_SUFFIX","title":"IMG_SUFFIX = '_Probabilities.tiff' module-attribute","text":"

Images suffix, including extension. Masks must be the same name without the suffix.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MASKS_DIR","title":"MASKS_DIR = 'path/to/corresponding/masks' module-attribute","text":"

Full path to the masks, to exclude objects near the brain edges (set to None or empty string to disable this feature).

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MASKS_EXT","title":"MASKS_EXT = 'tiff' module-attribute","text":"

Masks files extension.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MAX_PIX_VALUE","title":"MAX_PIX_VALUE = 255 module-attribute","text":"

Maximum pixel possible value to adjust proba_threshold.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.ORIGINAL_PIXELSIZE","title":"ORIGINAL_PIXELSIZE = 0.45 module-attribute","text":"

Original images pixel size in microns. This is in case the pixel classifier uses a lower resolution, yielding smaller probability maps, so output objects coordinates need to be rescaled to the full size images. The pixel size is written in the \"Image\" tab in QuPath.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.QUPATH_TYPE","title":"QUPATH_TYPE = 'detection' module-attribute","text":"

QuPath object type.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.SEGTYPE","title":"SEGTYPE = 'boutons' module-attribute","text":"

Type of segmentation.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_geojson_dir","title":"get_geojson_dir(images_dir)","text":"

Get the directory of geojson files, which will be in the parent directory of images_dir.

If the directory does not exist, create it.

Parameters:

Name Type Description Default images_dir str required

Returns:

Name Type Description geojson_dir str Source code in scripts/segmentation/segment_images.py
def get_geojson_dir(images_dir: str):\n    \"\"\"\n    Get the directory of geojson files, which will be in the parent directory\n    of `images_dir`.\n\n    If the directory does not exist, create it.\n\n    Parameters\n    ----------\n    images_dir : str\n\n    Returns\n    -------\n    geojson_dir : str\n\n    \"\"\"\n\n    geojson_dir = os.path.join(Path(images_dir).parent, \"geojson\")\n\n    if not os.path.isdir(geojson_dir):\n        os.mkdir(geojson_dir)\n\n    return geojson_dir\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_geojson_properties","title":"get_geojson_properties(name, color, objtype='detection')","text":"

Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.

Parameters:

Name Type Description Default name str

Classification name.

required color tuple or list

Classification color in RGB (3-elements vector).

required objtype str

Object type (\"detection\" or \"annotation\"). Default is \"detection\".

'detection'

Returns:

Name Type Description props dict Source code in scripts/segmentation/segment_images.py
def get_geojson_properties(name: str, color: tuple | list, objtype: str = \"detection\"):\n    \"\"\"\n    Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.\n\n    Parameters\n    ----------\n    name : str\n        Classification name.\n    color : tuple or list\n        Classification color in RGB (3-elements vector).\n    objtype : str, optional\n        Object type (\"detection\" or \"annotation\"). Default is \"detection\".\n\n    Returns\n    -------\n    props : dict\n\n    \"\"\"\n\n    return {\n        \"objectType\": objtype,\n        \"classification\": {\"name\": name, \"color\": color},\n        \"isLocked\": \"true\",\n    }\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_seg_method","title":"get_seg_method(segtype)","text":"

Determine what kind of segmentation is performed.

Segmentation kind are, for now, lines, polygons or points. We detect that based on hardcoded keywords.

Parameters:

Name Type Description Default segtype str required

Returns:

Name Type Description seg_method str Source code in scripts/segmentation/segment_images.py
def get_seg_method(segtype: str):\n    \"\"\"\n    Determine what kind of segmentation is performed.\n\n    Segmentation kind are, for now, lines, polygons or points. We detect that based on\n    hardcoded keywords.\n\n    Parameters\n    ----------\n    segtype : str\n\n    Returns\n    -------\n    seg_method : str\n\n    \"\"\"\n\n    line_list = [\"fibers\", \"axons\", \"fiber\", \"axon\"]\n    point_list = [\"synapto\", \"synaptophysin\", \"syngfp\", \"boutons\", \"points\"]\n    polygon_list = [\"cells\", \"polygon\", \"polygons\", \"polygon\", \"cell\"]\n\n    if segtype in line_list:\n        seg_method = \"lines\"\n    elif segtype in polygon_list:\n        seg_method = \"polygons\"\n    elif segtype in point_list:\n        seg_method = \"points\"\n    else:\n        raise ValueError(\n            f\"Could not determine method to use based on segtype : {segtype}.\"\n        )\n\n    return seg_method\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.parameters_as_dict","title":"parameters_as_dict(images_dir, masks_dir, segtype, name, proba_threshold, edge_dist)","text":"

Get information as a dictionnary.

Parameters:

Name Type Description Default images_dir str

Path to images to be segmented.

required masks_dir str

Path to images masks.

required segtype str

Segmentation type (eg. \"fibers\").

required name str

Name of the segmentation (eg. \"green\").

required proba_threshold float < 1

Probability threshold.

required edge_dist float

Distance in \u00b5m to the brain edge that is ignored.

required

Returns:

Name Type Description params dict Source code in scripts/segmentation/segment_images.py
def parameters_as_dict(\n    images_dir: str,\n    masks_dir: str,\n    segtype: str,\n    name: str,\n    proba_threshold: float,\n    edge_dist: float,\n):\n    \"\"\"\n    Get information as a dictionnary.\n\n    Parameters\n    ----------\n    images_dir : str\n        Path to images to be segmented.\n    masks_dir : str\n        Path to images masks.\n    segtype : str\n        Segmentation type (eg. \"fibers\").\n    name : str\n        Name of the segmentation (eg. \"green\").\n    proba_threshold : float < 1\n        Probability threshold.\n    edge_dist : float\n        Distance in \u00b5m to the brain edge that is ignored.\n\n    Returns\n    -------\n    params : dict\n\n    \"\"\"\n\n    return {\n        \"images_location\": images_dir,\n        \"masks_location\": masks_dir,\n        \"type\": segtype,\n        \"probability threshold\": proba_threshold,\n        \"name\": name,\n        \"edge distance\": edge_dist,\n    }\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.process_directory","title":"process_directory(images_dir, img_suffix='', segtype='', original_pixelsize=1.0, target_channel=0, proba_threshold=0.0, qupath_class='Object', qupath_color=[0, 0, 0], channel_suffix='', edge_dist=0.0, filters={}, masks_dir='', masks_ext='')","text":"

Main function, processes the .ome.tiff files in the input directory.

Parameters:

Name Type Description Default images_dir str

Animal ID to process.

required img_suffix str

Images suffix, including extension.

'' segtype str

Segmentation type.

'' original_pixelsize float

Original images pixel size in microns.

1.0 target_channel int

Index of the channel containning the objects of interest (eg. not the background), in the probability map (not the original images channels).

0 proba_threshold float < 1

Probability below this value will be discarded (multiplied by MAX_PIXEL_VALUE)

0.0 qupath_class str

Name of the QuPath classification.

'Object' qupath_color list of three elements

Color associated to that classification in RGB.

[0, 0, 0] channel_suffix str

Channel name, will be used as a suffix in output geojson files.

'' edge_dist float

Distance to the edge of the brain masks that will be ignored, in microns. Set to 0 to disable this feature.

0.0 filters dict

Filters values to include or excludes objects. See the top of the script.

{} masks_dir str

Path to images masks, to exclude objects found near the edges. The masks must be with the same name as the corresponding image to be segmented, without its suffix. Default is \"\", which disables this feature.

'' masks_ext str

Masks files extension, without leading \".\". Default is \"\"

'' Source code in scripts/segmentation/segment_images.py
def process_directory(\n    images_dir: str,\n    img_suffix: str = \"\",\n    segtype: str = \"\",\n    original_pixelsize: float = 1.0,\n    target_channel: int = 0,\n    proba_threshold: float = 0.0,\n    qupath_class: str = \"Object\",\n    qupath_color: list = [0, 0, 0],\n    channel_suffix: str = \"\",\n    edge_dist: float = 0.0,\n    filters: dict = {},\n    masks_dir: str = \"\",\n    masks_ext: str = \"\",\n):\n    \"\"\"\n    Main function, processes the .ome.tiff files in the input directory.\n\n    Parameters\n    ----------\n    images_dir : str\n        Animal ID to process.\n    img_suffix : str\n        Images suffix, including extension.\n    segtype : str\n        Segmentation type.\n    original_pixelsize : float\n        Original images pixel size in microns.\n    target_channel : int\n        Index of the channel containning the objects of interest (eg. not the\n        background), in the probability map (*not* the original images channels).\n    proba_threshold : float < 1\n        Probability below this value will be discarded (multiplied by `MAX_PIXEL_VALUE`)\n    qupath_class : str\n        Name of the QuPath classification.\n    qupath_color : list of three elements\n        Color associated to that classification in RGB.\n    channel_suffix : str\n        Channel name, will be used as a suffix in output geojson files.\n    edge_dist : float\n        Distance to the edge of the brain masks that will be ignored, in microns. Set to\n        0 to disable this feature.\n    filters : dict\n        Filters values to include or excludes objects. See the top of the script.\n    masks_dir : str, optional\n        Path to images masks, to exclude objects found near the edges. The masks must be\n        with the same name as the corresponding image to be segmented, without its\n        suffix. Default is \"\", which disables this feature.\n    masks_ext : str, optional\n        Masks files extension, without leading \".\". Default is \"\"\n\n    \"\"\"\n\n    # -- Preparation\n    # get segmentation type\n    seg_method = get_seg_method(segtype)\n\n    # get output directory path\n    geojson_dir = get_geojson_dir(images_dir)\n\n    # get images list\n    images_list = [\n        os.path.join(images_dir, filename)\n        for filename in os.listdir(images_dir)\n        if filename.endswith(img_suffix)\n    ]\n\n    # write parameters\n    parameters = parameters_as_dict(\n        images_dir, masks_dir, segtype, channel_suffix, proba_threshold, edge_dist\n    )\n    param_file = os.path.join(geojson_dir, \"parameters\" + channel_suffix + \".txt\")\n    if os.path.isfile(param_file):\n        raise FileExistsError(\"Parameters file already exists.\")\n    else:\n        write_parameters(param_file, parameters, filters, original_pixelsize)\n\n    # convert parameters to pixels in probability map\n    pixelsize = hq.seg.get_pixelsize(images_list[0])  # get pixel size\n    edge_dist = int(edge_dist / pixelsize)\n    filters = hq.seg.convert_to_pixels(filters, pixelsize)\n\n    # get rescaling factor\n    rescale_factor = pixelsize / original_pixelsize\n\n    # get GeoJSON properties\n    geojson_props = get_geojson_properties(\n        qupath_class, qupath_color, objtype=QUPATH_TYPE\n    )\n\n    # -- Processing\n    pbar = tqdm(images_list)\n    for imgpath in pbar:\n        # build file names\n        imgname = os.path.basename(imgpath)\n        geoname = imgname.replace(img_suffix, \"\")\n        geojson_file = os.path.join(\n            geojson_dir, geoname + \"_segmentation\" + channel_suffix + \".geojson\"\n        )\n\n        # checks if output file already exists\n        if os.path.isfile(geojson_file):\n            continue\n\n        # read images\n        pbar.set_description(f\"{geoname}: Loading...\")\n        img = tifffile.imread(imgpath, key=target_channel)\n        if (edge_dist > 0) & (len(masks_dir) != 0):\n            mask = tifffile.imread(os.path.join(masks_dir, geoname + \".\" + masks_ext))\n            mask = hq.seg.pad_image(mask, img.shape)  # resize mask\n            # apply mask, eroding from the edges\n            img = img * hq.seg.erode_mask(mask, edge_dist)\n\n        # image processing\n        pbar.set_description(f\"{geoname}: IP...\")\n\n        # threshold probability and binarization\n        img = img >= proba_threshold * MAX_PIX_VALUE\n\n        # segmentation\n        pbar.set_description(f\"{geoname}: Segmenting...\")\n\n        if seg_method == \"lines\":\n            collection = hq.seg.segment_lines(\n                img,\n                geojson_props,\n                minsize=filters[\"length_low\"],\n                rescale_factor=rescale_factor,\n            )\n\n        elif seg_method == \"polygons\":\n            collection = hq.seg.segment_polygons(\n                img,\n                geojson_props,\n                area_min=filters[\"area_low\"],\n                area_max=filters[\"area_high\"],\n                ecc_min=filters[\"ecc_low\"],\n                ecc_max=filters[\"ecc_high\"],\n                rescale_factor=rescale_factor,\n            )\n\n        elif seg_method == \"points\":\n            collection = hq.seg.segment_points(\n                img,\n                geojson_props,\n                area_min=filters[\"area_low\"],\n                area_max=filters[\"area_high\"],\n                ecc_min=filters[\"ecc_low\"],\n                ecc_max=filters[\"ecc_high\"],\n                dist_thresh=filters[\"dist_thresh\"],\n                rescale_factor=rescale_factor,\n            )\n        else:\n            # we already printed an error message\n            return\n\n        # save geojson\n        pbar.set_description(f\"{geoname}: Saving...\")\n        with open(geojson_file, \"w\") as fid:\n            fid.write(geojson.dumps(collection))\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.write_parameters","title":"write_parameters(outfile, parameters, filters, original_pixelsize)","text":"

Write parameters to outfile.

A timestamp will be added. Parameters are written as key = value, and a [filters] is added before filters parameters.

Parameters:

Name Type Description Default outfile str

Full path to the output file.

required parameters dict

General parameters.

required filters dict

Filters parameters.

required original_pixelsize float

Size of pixels in original image.

required Source code in scripts/segmentation/segment_images.py
def write_parameters(\n    outfile: str, parameters: dict, filters: dict, original_pixelsize: float\n):\n    \"\"\"\n    Write parameters to `outfile`.\n\n    A timestamp will be added. Parameters are written as key = value,\n    and a [filters] is added before filters parameters.\n\n    Parameters\n    ----------\n    outfile : str\n        Full path to the output file.\n    parameters : dict\n        General parameters.\n    filters : dict\n        Filters parameters.\n    original_pixelsize : float\n        Size of pixels in original image.\n\n    \"\"\"\n\n    with open(outfile, \"w\") as fid:\n        fid.writelines(f\"date = {datetime.now().strftime('%d-%B-%Y %H:%M:%S')}\\n\")\n\n        fid.writelines(f\"original_pixelsize = {original_pixelsize}\\n\")\n\n        for key, value in parameters.items():\n            fid.writelines(f\"{key} = {value}\\n\")\n\n        fid.writelines(\"[filters]\\n\")\n\n        for key, value in filters.items():\n            fid.writelines(f\"{key} = {value}\\n\")\n
"},{"location":"api-seg.html","title":"cuisto.seg","text":"

seg module, part of cuisto.

Functions for segmentating probability map stored as an image.

"},{"location":"api-seg.html#cuisto.seg.convert_to_pixels","title":"convert_to_pixels(filters, pixelsize)","text":"

Convert some values in filters in pixels.

Parameters:

Name Type Description Default filters dict

Must contain the keys used below.

required pixelsize float

Pixel size in microns.

required

Returns:

Name Type Description filters dict

Same as input, with values in pixels.

Source code in cuisto/seg.py
def convert_to_pixels(filters, pixelsize):\n    \"\"\"\n    Convert some values in `filters` in pixels.\n\n    Parameters\n    ----------\n    filters : dict\n        Must contain the keys used below.\n    pixelsize : float\n        Pixel size in microns.\n\n    Returns\n    -------\n    filters : dict\n        Same as input, with values in pixels.\n\n    \"\"\"\n\n    filters[\"area_low\"] = filters[\"area_low\"] / pixelsize**2\n    filters[\"area_high\"] = filters[\"area_high\"] / pixelsize**2\n    filters[\"length_low\"] = filters[\"length_low\"] / pixelsize\n    filters[\"dist_thresh\"] = int(filters[\"dist_thresh\"] / pixelsize)\n\n    return filters\n
"},{"location":"api-seg.html#cuisto.seg.erode_mask","title":"erode_mask(mask, edge_dist)","text":"

Erode the mask outline so that is is edge_dist smaller from the border.

This allows discarding the edges.

Parameters:

Name Type Description Default mask ndarray required edge_dist float

Distance to edges, in pixels.

required

Returns:

Name Type Description eroded_mask ndarray of bool Source code in cuisto/seg.py
def erode_mask(mask: np.ndarray, edge_dist: float) -> np.ndarray:\n    \"\"\"\n    Erode the mask outline so that is is `edge_dist` smaller from the border.\n\n    This allows discarding the edges.\n\n    Parameters\n    ----------\n    mask : ndarray\n    edge_dist : float\n        Distance to edges, in pixels.\n\n    Returns\n    -------\n    eroded_mask : ndarray of bool\n\n    \"\"\"\n\n    if edge_dist % 2 == 0:\n        edge_dist += 1  # decomposition requires even number\n\n    footprint = morphology.square(edge_dist, decomposition=\"sequence\")\n\n    return mask * morphology.binary_erosion(mask, footprint=footprint)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_points","title":"get_collection_from_points(coords, properties, rescale_factor=1.0, offset=0.5)","text":"

Gather coordinates from coords and put them in GeoJSON format.

An entry in coords are pairs of (x, y) coordinates defining the point. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default coords list required properties dict required rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection Source code in cuisto/seg.py
def get_collection_from_points(\n    coords: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Gather coordinates from `coords` and put them in GeoJSON format.\n\n    An entry in `coords` are pairs of (x, y) coordinates defining the point.\n    `properties` is a dictionnary with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    coords : list\n    properties : dict\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n\n    \"\"\"\n\n    collection = [\n        geojson.Feature(\n            geometry=shapely.Point(\n                np.flip((coord + offset) * rescale_factor)\n            ),  # shape object\n            properties=properties,  # object properties\n            id=str(uuid.uuid4()),  # object uuid\n        )\n        for coord in coords\n    ]\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_poly","title":"get_collection_from_poly(contours, properties, rescale_factor=1.0, offset=0.5)","text":"

Gather coordinates in the list and put them in GeoJSON format as Polygons.

An entry in contours must define a closed polygon. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default contours list required properties dict

QuPatj objects' properties.

required rescale_factor float

Rescale output coordinates by this factor.

1.0 offset float

Shift coordinates by this amount, typically to get pixel centers or edges. Default is 0.5.

0.5

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def get_collection_from_poly(\n    contours: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Gather coordinates in the list and put them in GeoJSON format as Polygons.\n\n    An entry in `contours` must define a closed polygon. `properties` is a dictionnary\n    with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    contours : list\n    properties : dict\n        QuPatj objects' properties.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n    offset : float\n        Shift coordinates by this amount, typically to get pixel centers or edges.\n        Default is 0.5.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n    collection = [\n        geojson.Feature(\n            geometry=shapely.Polygon(\n                np.fliplr((contour + offset) * rescale_factor)\n            ),  # shape object\n            properties=properties,  # object properties\n            id=str(uuid.uuid4()),  # object uuid\n        )\n        for contour in contours\n    ]\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_skel","title":"get_collection_from_skel(skeleton, properties, rescale_factor=1.0, offset=0.5)","text":"

Get the coordinates of each skeleton path as a GeoJSON Features in a FeatureCollection. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default skeleton Skeleton required properties dict

QuPatj objects' properties.

required rescale_factor float

Rescale output coordinates by this factor.

1.0 offset float

Shift coordinates by this amount, typically to get pixel centers or edges. Default is 0.5.

0.5

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def get_collection_from_skel(\n    skeleton: Skeleton, properties: dict, rescale_factor: float = 1.0, offset=0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Get the coordinates of each skeleton path as a GeoJSON Features in a\n    FeatureCollection.\n    `properties` is a dictionnary with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    skeleton : skan.Skeleton\n    properties : dict\n        QuPatj objects' properties.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n    offset : float\n        Shift coordinates by this amount, typically to get pixel centers or edges.\n        Default is 0.5.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    branch_data = summarize(skeleton, separator=\"_\")\n\n    collection = []\n    for ind in range(skeleton.n_paths):\n        prop = properties.copy()\n        prop[\"measurements\"] = {\"skeleton_id\": int(branch_data.loc[ind, \"skeleton_id\"])}\n        collection.append(\n            geojson.Feature(\n                geometry=shapely.LineString(\n                    (skeleton.path_coordinates(ind)[:, ::-1] + offset) * rescale_factor\n                ),  # shape object\n                properties=prop,  # object properties\n                id=str(uuid.uuid4()),  # object uuid\n            )\n        )\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_image_skeleton","title":"get_image_skeleton(img, minsize=0)","text":"

Get the image skeleton.

Computes the image skeleton and removes objects smaller than minsize.

Parameters:

Name Type Description Default img ndarray of bool required minsize number

Min. size the object can have, as a number of pixels. Default is 0.

0

Returns:

Name Type Description skel ndarray of bool

Binary image with 1-pixel wide skeleton.

Source code in cuisto/seg.py
def get_image_skeleton(img: np.ndarray, minsize=0) -> np.ndarray:\n    \"\"\"\n    Get the image skeleton.\n\n    Computes the image skeleton and removes objects smaller than `minsize`.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n    minsize : number, optional\n        Min. size the object can have, as a number of pixels. Default is 0.\n\n    Returns\n    -------\n    skel : ndarray of bool\n        Binary image with 1-pixel wide skeleton.\n\n    \"\"\"\n\n    skel = morphology.skeletonize(img)\n\n    return morphology.remove_small_objects(skel, min_size=minsize, connectivity=2)\n
"},{"location":"api-seg.html#cuisto.seg.get_pixelsize","title":"get_pixelsize(image_name)","text":"

Get pixel size recorded in image_name TIFF metadata.

Parameters:

Name Type Description Default image_name str

Full path to image.

required

Returns:

Name Type Description pixelsize float

Pixel size in microns.

Source code in cuisto/seg.py
def get_pixelsize(image_name: str) -> float:\n    \"\"\"\n    Get pixel size recorded in `image_name` TIFF metadata.\n\n    Parameters\n    ----------\n    image_name : str\n        Full path to image.\n\n    Returns\n    -------\n    pixelsize : float\n        Pixel size in microns.\n\n    \"\"\"\n\n    with tifffile.TiffFile(image_name) as tif:\n        # XResolution is a tuple, numerator, denomitor. The inverse is the pixel size\n        return (\n            tif.pages[0].tags[\"XResolution\"].value[1]\n            / tif.pages[0].tags[\"XResolution\"].value[0]\n        )\n
"},{"location":"api-seg.html#cuisto.seg.pad_image","title":"pad_image(img, finalsize)","text":"

Pad image with zeroes to match expected final size.

Parameters:

Name Type Description Default img ndarray required finalsize tuple or list

nrows, ncolumns

required

Returns:

Name Type Description imgpad ndarray

img with black borders.

Source code in cuisto/seg.py
def pad_image(img: np.ndarray, finalsize: tuple | list) -> np.ndarray:\n    \"\"\"\n    Pad image with zeroes to match expected final size.\n\n    Parameters\n    ----------\n    img : ndarray\n    finalsize : tuple or list\n        nrows, ncolumns\n\n    Returns\n    -------\n    imgpad : ndarray\n        img with black borders.\n\n    \"\"\"\n\n    final_h = finalsize[0]  # requested number of rows (height)\n    final_w = finalsize[1]  # requested number of columns (width)\n    original_h = img.shape[0]  # input number of rows\n    original_w = img.shape[1]  # input number of columns\n\n    a = (final_h - original_h) // 2  # vertical padding before\n    aa = final_h - a - original_h  # vertical padding after\n    b = (final_w - original_w) // 2  # horizontal padding before\n    bb = final_w - b - original_w  # horizontal padding after\n\n    return np.pad(img, pad_width=((a, aa), (b, bb)), mode=\"constant\")\n
"},{"location":"api-seg.html#cuisto.seg.segment_lines","title":"segment_lines(img, geojson_props, minsize=0.0, rescale_factor=1.0)","text":"

Wraps skeleton analysis to get paths coordinates.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as lines.

required geojson_props dict

GeoJSON properties of objects.

required minsize float

Minimum size in pixels for an object.

0.0 rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_lines(\n    img: np.ndarray, geojson_props: dict, minsize=0.0, rescale_factor=1.0\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Wraps skeleton analysis to get paths coordinates.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as lines.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    minsize : float\n        Minimum size in pixels for an object.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    skel = get_image_skeleton(img, minsize=minsize)\n\n    # get paths coordinates as FeatureCollection\n    skeleton = Skeleton(skel, keep_images=False)\n    return get_collection_from_skel(\n        skeleton, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-seg.html#cuisto.seg.segment_points","title":"segment_points(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0, ecc_max=1, dist_thresh=0, rescale_factor=1)","text":"

Point segmentation.

First, segment polygons to apply shape filters, then extract their centroids, and remove isolated points as defined by dist_thresh.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as points.

required geojson_props dict

GeoJSON properties of objects.

required area_min float

Minimum and maximum area in pixels for an object.

0.0 area_max float

Minimum and maximum area in pixels for an object.

0.0 ecc_min float

Minimum and maximum eccentricity for an object.

0 ecc_max float

Minimum and maximum eccentricity for an object.

0 dist_thresh float

Maximal distance in pixels between objects before considering them as isolated and remove them. 0 disables it.

0 rescale_factor float

Rescale output coordinates by this factor.

1

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_points(\n    img: np.ndarray,\n    geojson_props: dict,\n    area_min: float = 0.0,\n    area_max: float = np.inf,\n    ecc_min: float = 0,\n    ecc_max: float = 1,\n    dist_thresh: float = 0,\n    rescale_factor: float = 1,\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Point segmentation.\n\n    First, segment polygons to apply shape filters, then extract their centroids,\n    and remove isolated points as defined by `dist_thresh`.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as points.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    area_min, area_max : float\n        Minimum and maximum area in pixels for an object.\n    ecc_min, ecc_max : float\n        Minimum and maximum eccentricity for an object.\n    dist_thresh : float\n        Maximal distance in pixels between objects before considering them as isolated and remove them.\n        0 disables it.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    # get objects properties\n    stats = pd.DataFrame(\n        measure.regionprops_table(\n            measure.label(img), properties=(\"label\", \"area\", \"eccentricity\", \"centroid\")\n        )\n    )\n\n    # keep objects matching filters\n    stats = stats[\n        (stats[\"area\"] >= area_min)\n        & (stats[\"area\"] <= area_max)\n        & (stats[\"eccentricity\"] >= ecc_min)\n        & (stats[\"eccentricity\"] <= ecc_max)\n    ]\n\n    # create an image from centroids only\n    stats[\"centroid-0\"] = stats[\"centroid-0\"].astype(int)\n    stats[\"centroid-1\"] = stats[\"centroid-1\"].astype(int)\n    bw = np.zeros(img.shape, dtype=bool)\n    bw[stats[\"centroid-0\"], stats[\"centroid-1\"]] = True\n\n    # filter isolated objects\n    if dist_thresh:\n        # dilation of points\n        if dist_thresh % 2 == 0:\n            dist_thresh += 1  # decomposition requires even number\n\n        footprint = morphology.square(int(dist_thresh), decomposition=\"sequence\")\n        dilated = measure.label(morphology.binary_dilation(bw, footprint=footprint))\n        stats = pd.DataFrame(\n            measure.regionprops_table(dilated, properties=(\"label\", \"area\"))\n        )\n\n        # objects that did not merge are alone\n        toremove = stats[(stats[\"area\"] <= dist_thresh**2)]\n        dilated[np.isin(dilated, toremove[\"label\"])] = 0  # remove them\n\n        # apply mask\n        bw = bw * dilated\n\n    # get points coordinates\n    coords = np.argwhere(bw)\n\n    return get_collection_from_points(\n        coords, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-seg.html#cuisto.seg.segment_polygons","title":"segment_polygons(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0.0, ecc_max=1.0, rescale_factor=1.0)","text":"

Polygon segmentation.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as polygons.

required geojson_props dict

GeoJSON properties of objects.

required area_min float

Minimum and maximum area in pixels for an object.

0.0 area_max float

Minimum and maximum area in pixels for an object.

0.0 ecc_min float

Minimum and maximum eccentricity for an object.

0.0 ecc_max float

Minimum and maximum eccentricity for an object.

0.0 rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_polygons(\n    img: np.ndarray,\n    geojson_props: dict,\n    area_min: float = 0.0,\n    area_max: float = np.inf,\n    ecc_min: float = 0.0,\n    ecc_max: float = 1.0,\n    rescale_factor: float = 1.0,\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Polygon segmentation.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as polygons.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    area_min, area_max : float\n        Minimum and maximum area in pixels for an object.\n    ecc_min, ecc_max : float\n        Minimum and maximum eccentricity for an object.\n    rescale_factor: float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    label_image = measure.label(img)\n\n    # get objects properties\n    stats = pd.DataFrame(\n        measure.regionprops_table(\n            label_image, properties=(\"label\", \"area\", \"eccentricity\")\n        )\n    )\n\n    # remove objects not matching filters\n    toremove = stats[\n        (stats[\"area\"] < area_min)\n        | (stats[\"area\"] > area_max)\n        | (stats[\"eccentricity\"] < ecc_min)\n        | (stats[\"eccentricity\"] > ecc_max)\n    ]\n\n    label_image[np.isin(label_image, toremove[\"label\"])] = 0\n\n    # find objects countours\n    label_image = label_image > 0\n    contours = measure.find_contours(label_image)\n\n    return get_collection_from_poly(\n        contours, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-utils.html","title":"cuisto.utils","text":"

utils module, part of cuisto.

Contains utilities functions.

"},{"location":"api-utils.html#cuisto.utils.add_brain_region","title":"add_brain_region(df, atlas, col='Parent')","text":"

Add brain region to a DataFrame with Atlas_X, Atlas_Y and Atlas_Z columns.

This uses Brainglobe Atlas API to query the atlas. It does not use the structure_from_coords() method, instead it manually converts the coordinates in stack indices, then get the corresponding annotation id and query the corresponding acronym -- because brainglobe-atlasapi is not vectorized at all.

Parameters:

Name Type Description Default df DataFrame

DataFrame with atlas coordinates in microns.

required atlas BrainGlobeAtlas required col str

Column in which to put the regions acronyms. Default is \"Parent\".

'Parent'

Returns:

Name Type Description df DataFrame

Same DataFrame with a new \"Parent\" column.

Source code in cuisto/utils.py
def add_brain_region(\n    df: pd.DataFrame, atlas: BrainGlobeAtlas, col=\"Parent\"\n) -> pd.DataFrame:\n    \"\"\"\n    Add brain region to a DataFrame with `Atlas_X`, `Atlas_Y` and `Atlas_Z` columns.\n\n    This uses Brainglobe Atlas API to query the atlas. It does not use the\n    structure_from_coords() method, instead it manually converts the coordinates in\n    stack indices, then get the corresponding annotation id and query the corresponding\n    acronym -- because brainglobe-atlasapi is not vectorized at all.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame with atlas coordinates in microns.\n    atlas : BrainGlobeAtlas\n    col : str, optional\n        Column in which to put the regions acronyms. Default is \"Parent\".\n\n    Returns\n    -------\n    df : pd.DataFrame\n        Same DataFrame with a new \"Parent\" column.\n\n    \"\"\"\n    df_in = df.copy()\n\n    res = atlas.resolution  # microns <-> pixels conversion\n    lims = atlas.shape_um  # out of brain\n\n    # set out-of-brain objects at 0 so we get \"root\" as their parent\n    df_in.loc[(df_in[\"Atlas_X\"] >= lims[0]) | (df_in[\"Atlas_X\"] < 0), \"Atlas_X\"] = 0\n    df_in.loc[(df_in[\"Atlas_Y\"] >= lims[1]) | (df_in[\"Atlas_Y\"] < 0), \"Atlas_Y\"] = 0\n    df_in.loc[(df_in[\"Atlas_Z\"] >= lims[2]) | (df_in[\"Atlas_Z\"] < 0), \"Atlas_Z\"] = 0\n\n    # build the multi index, in pixels and integers\n    ixyz = (\n        df_in[\"Atlas_X\"].divide(res[0]).astype(int),\n        df_in[\"Atlas_Y\"].divide(res[1]).astype(int),\n        df_in[\"Atlas_Z\"].divide(res[2]).astype(int),\n    )\n    # convert i, j, k indices in raveled indices\n    linear_indices = np.ravel_multi_index(ixyz, dims=atlas.annotation.shape)\n    # get the structure id from the annotation stack\n    idlist = atlas.annotation.ravel()[linear_indices]\n    # replace 0 which does not exist to 997 (root)\n    idlist[idlist == 0] = 997\n\n    # query the corresponding acronyms\n    lookup = atlas.lookup_df.set_index(\"id\")\n    df.loc[:, col] = lookup.loc[idlist, \"acronym\"].values\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.add_channel","title":"add_channel(df, object_type, channel_names)","text":"

Add channel as a measurement for detections DataFrame.

The channel is read from the Classification column, the latter having to be formatted as \"object_type: channel\".

Parameters:

Name Type Description Default df DataFrame

DataFrame with detections measurements.

required object_type str

Object type (primary classification).

required channel_names dict

Map between original channel names to something else.

required

Returns:

Type Description DataFrame

Same DataFrame with a \"channel\" column.

Source code in cuisto/utils.py
def add_channel(\n    df: pd.DataFrame, object_type: str, channel_names: dict\n) -> pd.DataFrame:\n    \"\"\"\n    Add channel as a measurement for detections DataFrame.\n\n    The channel is read from the Classification column, the latter having to be\n    formatted as \"object_type: channel\".\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame with detections measurements.\n    object_type : str\n        Object type (primary classification).\n    channel_names : dict\n        Map between original channel names to something else.\n\n    Returns\n    -------\n    pd.DataFrame\n        Same DataFrame with a \"channel\" column.\n\n    \"\"\"\n    # check if there is something to do\n    if \"channel\" in df.columns:\n        return df\n\n    kind = get_df_kind(df)\n    if kind == \"annotation\":\n        warnings.warn(\"Annotation DataFrame not supported.\")\n        return df\n\n    # add channel, from {class_name: channel} classification\n    df[\"channel\"] = (\n        df[\"Classification\"].str.replace(object_type + \": \", \"\").map(channel_names)\n    )\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.add_hemisphere","title":"add_hemisphere(df, hemisphere_names, midline=5700, col='Atlas_Z', atlas_type='brain')","text":"

Add hemisphere (left/right) as a measurement for detections or annotations.

The hemisphere is read in the \"Classification\" column for annotations. The latter needs to be in the form \"Right: Name\" or \"Left: Name\". For detections, the input col of df is compared to midline to assess if the object belong to the left or right hemispheres.

Parameters:

Name Type Description Default df DataFrame

DataFrame with detections or annotations measurements.

required hemisphere_names dict

Map between \"Left\" and \"Right\" to something else.

required midline float

Used only for \"detections\" df. Corresponds to the brain midline in microns, should be 5700 for CCFv3 and 1610 for spinal cord.

5700 col str

Name of the column containing the Z coordinate (medio-lateral) in microns. Default is \"Atlas_Z\".

'Atlas_Z' atlas_type (brain, cord)

Type of atlas used for registration. Required because the brain atlas is swapped between left and right while the spinal cord atlas is not. Default is \"brain\".

\"brain\"

Returns:

Name Type Description df DataFrame

The same DataFrame with a new \"hemisphere\" column

Source code in cuisto/utils.py
def add_hemisphere(\n    df: pd.DataFrame,\n    hemisphere_names: dict,\n    midline: float = 5700,\n    col: str = \"Atlas_Z\",\n    atlas_type: str = \"brain\",\n) -> pd.DataFrame:\n    \"\"\"\n    Add hemisphere (left/right) as a measurement for detections or annotations.\n\n    The hemisphere is read in the \"Classification\" column for annotations. The latter\n    needs to be in the form \"Right: Name\" or \"Left: Name\". For detections, the input\n    `col` of `df` is compared to `midline` to assess if the object belong to the left or\n    right hemispheres.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n        DataFrame with detections or annotations measurements.\n    hemisphere_names : dict\n        Map between \"Left\" and \"Right\" to something else.\n    midline : float\n        Used only for \"detections\" `df`. Corresponds to the brain midline in microns,\n        should be 5700 for CCFv3 and 1610 for spinal cord.\n    col : str, optional\n        Name of the column containing the Z coordinate (medio-lateral) in microns.\n        Default is \"Atlas_Z\".\n    atlas_type : {\"brain\", \"cord\"}, optional\n        Type of atlas used for registration. Required because the brain atlas is swapped\n        between left and right while the spinal cord atlas is not. Default is \"brain\".\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        The same DataFrame with a new \"hemisphere\" column\n\n    \"\"\"\n    # check if there is something to do\n    if \"hemisphere\" in df.columns:\n        return df\n\n    # get kind of DataFrame\n    kind = get_df_kind(df)\n\n    if kind == \"detection\":\n        # use midline\n        if atlas_type == \"brain\":\n            # brain atlas : beyond midline, it's left\n            df.loc[df[col] >= midline, \"hemisphere\"] = hemisphere_names[\"Left\"]\n            df.loc[df[col] < midline, \"hemisphere\"] = hemisphere_names[\"Right\"]\n        elif atlas_type == \"cord\":\n            # cord atlas : below midline, it's left\n            df.loc[df[col] <= midline, \"hemisphere\"] = hemisphere_names[\"Left\"]\n            df.loc[df[col] > midline, \"hemisphere\"] = hemisphere_names[\"Right\"]\n\n    elif kind == \"annotation\":\n        # use Classification name -- this does not depend on atlas type\n        df[\"hemisphere\"] = [name.split(\":\")[0] for name in df[\"Classification\"]]\n        df[\"hemisphere\"] = df[\"hemisphere\"].map(hemisphere_names)\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.ccf_to_stereo","title":"ccf_to_stereo(x_ccf, y_ccf, z_ccf=0)","text":"

Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in Paxinos-Franklin atlas).

Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be in mm. x_ccf corresponds to the anterio-posterior (rostro-caudal) axis. y_ccf corresponds to the dorso-ventral axis. z_ccf corresponds to the medio-lateral axis (left-right) axis.

Warning : it is a rough estimation.

(1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858

Parameters:

Name Type Description Default x_ccf floats or ndarray

Coordinates in CCFv3 space in mm.

required y_ccf floats or ndarray

Coordinates in CCFv3 space in mm.

required z_ccf float or ndarray

Coordinate in CCFv3 space in mm. Default is 0.

0

Returns:

Type Description ap, dv, ml : floats or np.ndarray

Stereotaxic coordinates in mm.

Source code in cuisto/utils.py
def ccf_to_stereo(\n    x_ccf: float | np.ndarray, y_ccf: float | np.ndarray, z_ccf: float | np.ndarray = 0\n) -> tuple:\n    \"\"\"\n    Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in\n    Paxinos-Franklin atlas).\n\n    Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be\n    in mm.\n    `x_ccf` corresponds to the anterio-posterior (rostro-caudal) axis.\n    `y_ccf` corresponds to the dorso-ventral axis.\n    `z_ccf` corresponds to the medio-lateral axis (left-right) axis.\n\n    Warning : it is a rough estimation.\n\n    (1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858\n\n    Parameters\n    ----------\n    x_ccf, y_ccf : floats or np.ndarray\n        Coordinates in CCFv3 space in mm.\n    z_ccf : float or np.ndarray, optional\n        Coordinate in CCFv3 space in mm. Default is 0.\n\n    Returns\n    -------\n    ap, dv, ml : floats or np.ndarray\n        Stereotaxic coordinates in mm.\n\n    \"\"\"\n    # Center CCF on Bregma\n    xstereo = -(x_ccf - 5.40)  # anterio-posterior coordinate (rostro-caudal)\n    ystereo = y_ccf - 0.44  # dorso-ventral coordinate\n    ml = z_ccf - 5.70  # medio-lateral coordinate (left-right)\n\n    # Rotate CCF of 5\u00b0\n    angle = np.deg2rad(5)\n    ap = xstereo * np.cos(angle) - ystereo * np.sin(angle)\n    dv = xstereo * np.sin(angle) + ystereo * np.cos(angle)\n\n    # Squeeze the dorso-ventral axis by 94.34%\n    dv *= 0.9434\n\n    return ap, dv, ml\n
"},{"location":"api-utils.html#cuisto.utils.filter_df_classifications","title":"filter_df_classifications(df, filter_list, mode='keep', col='Classification')","text":"

Filter a DataFrame whether specified col column entries contain elements in filter_list. Case insensitive.

If mode is \"keep\", keep entries only if their col in is in the list (default). If mode is \"remove\", remove entries if their col is in the list.

Parameters:

Name Type Description Default df DataFrame required filter_list list | tuple | str

List of words that should be present to trigger the filter.

required mode keep or remove

Keep or remove entries from the list. Default is \"keep\".

'keep' col str

Key in df. Default is \"Classification\".

'Classification'

Returns:

Type Description DataFrame

Filtered DataFrame.

Source code in cuisto/utils.py
def filter_df_classifications(\n    df: pd.DataFrame, filter_list: list | tuple | str, mode=\"keep\", col=\"Classification\"\n) -> pd.DataFrame:\n    \"\"\"\n    Filter a DataFrame whether specified `col` column entries contain elements in\n    `filter_list`. Case insensitive.\n\n    If `mode` is \"keep\", keep entries only if their `col` in is in the list (default).\n    If `mode` is \"remove\", remove entries if their `col` is in the list.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    filter_list : list | tuple | str\n        List of words that should be present to trigger the filter.\n    mode : \"keep\" or \"remove\", optional\n        Keep or remove entries from the list. Default is \"keep\".\n    col : str, optional\n        Key in `df`. Default is \"Classification\".\n\n    Returns\n    -------\n    pd.DataFrame\n        Filtered DataFrame.\n\n    \"\"\"\n    # check input\n    if isinstance(filter_list, str):\n        filter_list = [filter_list]  # make sure it is a list\n\n    if col not in df.columns:\n        # might be because of 'Classification' instead of 'classification'\n        col = col.capitalize()\n        if col not in df.columns:\n            raise KeyError(f\"{col} not in DataFrame.\")\n\n    pattern = \"|\".join(f\".*{s}.*\" for s in filter_list)\n\n    if mode == \"keep\":\n        df_return = df[df[col].str.contains(pattern, case=False, regex=True)]\n    elif mode == \"remove\":\n        df_return = df[~df[col].str.contains(pattern, case=False, regex=True)]\n\n    # check\n    if len(df_return) == 0:\n        raise ValueError(\n            (\n                f\"Filtering '{col}' with {filter_list} resulted in an\"\n                + \" empty DataFrame, check your config file.\"\n            )\n        )\n    return df_return\n
"},{"location":"api-utils.html#cuisto.utils.filter_df_regions","title":"filter_df_regions(df, filter_list, mode='keep', col='Parent')","text":"

Filters entries in df based on wether their col is in filter_list or not.

If mode is \"keep\", keep entries only if their col in is in the list (default). If mode is \"remove\", remove entries if their col is in the list.

Parameters:

Name Type Description Default df DataFrame required filter_list list - like

List of regions to keep or remove from the DataFrame.

required mode keep or remove

Keep or remove entries from the list. Default is \"keep\".

'keep' col str

Key in df. Default is \"Parent\".

'Parent'

Returns:

Name Type Description df DataFrame

Filtered DataFrame.

Source code in cuisto/utils.py
def filter_df_regions(\n    df: pd.DataFrame, filter_list: list | tuple, mode=\"keep\", col=\"Parent\"\n) -> pd.DataFrame:\n    \"\"\"\n    Filters entries in `df` based on wether their `col` is in `filter_list` or not.\n\n    If `mode` is \"keep\", keep entries only if their `col` in is in the list (default).\n    If `mode` is \"remove\", remove entries if their `col` is in the list.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    filter_list : list-like\n        List of regions to keep or remove from the DataFrame.\n    mode : \"keep\" or \"remove\", optional\n        Keep or remove entries from the list. Default is \"keep\".\n    col : str, optional\n        Key in `df`. Default is \"Parent\".\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        Filtered DataFrame.\n\n    \"\"\"\n\n    if mode == \"keep\":\n        return df[df[col].isin(filter_list)]\n    if mode == \"remove\":\n        return df[~df[col].isin(filter_list)]\n
"},{"location":"api-utils.html#cuisto.utils.get_blacklist","title":"get_blacklist(file, atlas)","text":"

Build a list of regions to exclude from file.

File must be a TOML with [WITH_CHILDS] and [EXACT] sections.

Parameters:

Name Type Description Default file str

Full path the atlas_blacklist.toml file.

required atlas BrainGlobeAtlas

Atlas to extract regions from.

required

Returns:

Name Type Description black_list list

Full list of acronyms to discard.

Source code in cuisto/utils.py
def get_blacklist(file: str, atlas: BrainGlobeAtlas) -> list:\n    \"\"\"\n    Build a list of regions to exclude from file.\n\n    File must be a TOML with [WITH_CHILDS] and [EXACT] sections.\n\n    Parameters\n    ----------\n    file : str\n        Full path the atlas_blacklist.toml file.\n    atlas : BrainGlobeAtlas\n        Atlas to extract regions from.\n\n    Returns\n    -------\n    black_list : list\n        Full list of acronyms to discard.\n\n    \"\"\"\n    with open(file, \"rb\") as fid:\n        content = tomllib.load(fid)\n\n    blacklist = []  # init. the list\n\n    # add regions and their descendants\n    for region in content[\"WITH_CHILDS\"][\"members\"]:\n        blacklist.extend(\n            [\n                atlas.structures[id][\"acronym\"]\n                for id in atlas.structures.tree.expand_tree(\n                    atlas.structures[region][\"id\"]\n                )\n            ]\n        )\n\n    # add regions specified exactly (no descendants)\n    blacklist.extend(content[\"EXACT\"][\"members\"])\n\n    return blacklist\n
"},{"location":"api-utils.html#cuisto.utils.get_data_coverage","title":"get_data_coverage(df, col='Atlas_AP', by='animal')","text":"

Get min and max in col for each by.

Used to get data coverage for each animal to plot in distributions.

Parameters:

Name Type Description Default df DataFrame

description

required col str

Key in df, default is \"Atlas_X\".

'Atlas_AP' by str

Key in df , default is \"animal\".

'animal'

Returns:

Type Description DataFrame

min and max of col for each by, named \"X_min\", and \"X_max\".

Source code in cuisto/utils.py
def get_data_coverage(df: pd.DataFrame, col=\"Atlas_AP\", by=\"animal\") -> pd.DataFrame:\n    \"\"\"\n    Get min and max in `col` for each `by`.\n\n    Used to get data coverage for each animal to plot in distributions.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        _description_\n    col : str, optional\n        Key in `df`, default is \"Atlas_X\".\n    by : str, optional\n        Key in `df` , default is \"animal\".\n\n    Returns\n    -------\n    pd.DataFrame\n        min and max of `col` for each `by`, named \"X_min\", and \"X_max\".\n\n    \"\"\"\n    df_group = df.groupby([by])\n    return pd.DataFrame(\n        [\n            df_group[col].min(),\n            df_group[col].max(),\n        ],\n        index=[\"X_min\", \"X_max\"],\n    )\n
"},{"location":"api-utils.html#cuisto.utils.get_df_kind","title":"get_df_kind(df)","text":"

Get DataFrame kind, eg. Annotations or Detections.

It is based on reading the Object Type of the first entry, so the DataFrame must have only one kind of object.

Parameters:

Name Type Description Default df DataFrame required

Returns:

Name Type Description kind str

\"detection\" or \"annotation\".

Source code in cuisto/utils.py
def get_df_kind(df: pd.DataFrame) -> str:\n    \"\"\"\n    Get DataFrame kind, eg. Annotations or Detections.\n\n    It is based on reading the Object Type of the first entry, so the DataFrame must\n    have only one kind of object.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n\n    Returns\n    -------\n    kind : str\n        \"detection\" or \"annotation\".\n\n    \"\"\"\n    return df[\"Object type\"].iloc[0].lower()\n
"},{"location":"api-utils.html#cuisto.utils.get_injection_site","title":"get_injection_site(animal, info_file, channel, stereo=False)","text":"

Get the injection site coordinates associated with animal.

Parameters:

Name Type Description Default animal str

Animal ID.

required info_file str

Path to TOML info file.

required channel str

Channel ID as in the TOML file.

required stereo bool

Wether to convert coordinates in stereotaxis coordinates. Default is False.

False

Returns:

Type Description x, y, z : floats

Injection site coordinates.

Source code in cuisto/utils.py
def get_injection_site(\n    animal: str, info_file: str, channel: str, stereo: bool = False\n) -> tuple:\n    \"\"\"\n    Get the injection site coordinates associated with animal.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    info_file : str\n        Path to TOML info file.\n    channel : str\n        Channel ID as in the TOML file.\n    stereo : bool, optional\n        Wether to convert coordinates in stereotaxis coordinates. Default is False.\n\n    Returns\n    -------\n    x, y, z : floats\n        Injection site coordinates.\n\n    \"\"\"\n    with open(info_file, \"rb\") as fid:\n        info = tomllib.load(fid)\n\n    if channel in info[animal]:\n        x, y, z = info[animal][channel][\"injection_site\"]\n        if stereo:\n            x, y, z = ccf_to_stereo(x, y, z)\n    else:\n        x, y, z = None, None, None\n\n    return x, y, z\n
"},{"location":"api-utils.html#cuisto.utils.get_leaves_list","title":"get_leaves_list(atlas)","text":"

Get the list of leaf brain regions.

Leaf brain regions are defined as regions without childs, eg. regions that are at the bottom of the hiearchy.

Parameters:

Name Type Description Default atlas BrainGlobeAtlas

Atlas to extract regions from.

required

Returns:

Name Type Description leaves_list list

Acronyms of leaf brain regions.

Source code in cuisto/utils.py
def get_leaves_list(atlas: BrainGlobeAtlas) -> list:\n    \"\"\"\n    Get the list of leaf brain regions.\n\n    Leaf brain regions are defined as regions without childs, eg. regions that are at\n    the bottom of the hiearchy.\n\n    Parameters\n    ----------\n    atlas : BrainGlobeAtlas\n        Atlas to extract regions from.\n\n    Returns\n    -------\n    leaves_list : list\n        Acronyms of leaf brain regions.\n\n    \"\"\"\n    leaves_list = []\n    for region in atlas.structures_list:\n        if atlas.structures.tree[region[\"id\"]].is_leaf():\n            leaves_list.append(region[\"acronym\"])\n\n    return leaves_list\n
"},{"location":"api-utils.html#cuisto.utils.get_mapping_fusion","title":"get_mapping_fusion(fusion_file)","text":"

Get mapping dictionnary between input brain regions and new regions defined in atlas_fusion.toml file.

The returned dictionnary can be used in DataFrame.replace().

Parameters:

Name Type Description Default fusion_file str

Path to the TOML file with the merging rules.

required

Returns:

Name Type Description m dict

Mapping as {old: new}.

Source code in cuisto/utils.py
def get_mapping_fusion(fusion_file: str) -> dict:\n    \"\"\"\n    Get mapping dictionnary between input brain regions and new regions defined in\n    `atlas_fusion.toml` file.\n\n    The returned dictionnary can be used in DataFrame.replace().\n\n    Parameters\n    ----------\n    fusion_file : str\n        Path to the TOML file with the merging rules.\n\n    Returns\n    -------\n    m : dict\n        Mapping as {old: new}.\n\n    \"\"\"\n    with open(fusion_file, \"rb\") as fid:\n        df = pd.DataFrame.from_dict(tomllib.load(fid), orient=\"index\").set_index(\n            \"acronym\"\n        )\n\n    return (\n        df.drop(columns=\"name\")[\"members\"]\n        .explode()\n        .reset_index()\n        .set_index(\"members\")\n        .to_dict()[\"acronym\"]\n    )\n
"},{"location":"api-utils.html#cuisto.utils.get_starter_cells","title":"get_starter_cells(animal, channel, info_file)","text":"

Get the number of starter cells associated with animal.

Parameters:

Name Type Description Default animal str

Animal ID.

required channel str

Channel ID.

required info_file str

Path to TOML info file.

required

Returns:

Name Type Description n_starters int

Number of starter cells.

Source code in cuisto/utils.py
def get_starter_cells(animal: str, channel: str, info_file: str) -> int:\n    \"\"\"\n    Get the number of starter cells associated with animal.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    channel : str\n        Channel ID.\n    info_file : str\n        Path to TOML info file.\n\n    Returns\n    -------\n    n_starters : int\n        Number of starter cells.\n\n    \"\"\"\n    with open(info_file, \"rb\") as fid:\n        info = tomllib.load(fid)\n\n    return info[animal][channel][\"starter_cells\"]\n
"},{"location":"api-utils.html#cuisto.utils.merge_regions","title":"merge_regions(df, col, fusion_file)","text":"

Merge brain regions following rules in the fusion_file.toml file.

Apply this merging on col of the input DataFrame. col whose value is found in the members sections in the file will be changed to the new acronym.

Parameters:

Name Type Description Default df DataFrame required col str

Column of df on which to apply the mapping.

required fusion_file str

Path to the toml file with the merging rules.

required

Returns:

Name Type Description df DataFrame

Same DataFrame with regions renamed.

Source code in cuisto/utils.py
def merge_regions(df: pd.DataFrame, col: str, fusion_file: str) -> pd.DataFrame:\n    \"\"\"\n    Merge brain regions following rules in the `fusion_file.toml` file.\n\n    Apply this merging on `col` of the input DataFrame. `col` whose value is found in\n    the `members` sections in the file will be changed to the new acronym.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    col : str\n        Column of `df` on which to apply the mapping.\n    fusion_file : str\n        Path to the toml file with the merging rules.\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        Same DataFrame with regions renamed.\n\n    \"\"\"\n    df[col] = df[col].replace(get_mapping_fusion(fusion_file))\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.renormalize_per_key","title":"renormalize_per_key(df, by, on)","text":"

Renormalize on column by its sum for each by.

Use case : relative density is computed for both hemispheres, so if one wants to plot only one hemisphere, the sum of the bars corresponding to one channel (by) should be 1. So :

df = df[df[\"hemisphere\"] == \"Ipsi.\"] df = renormalize_per_key(df, \"channel\", \"relative density\") Then, the sum of \"relative density\" for each \"channel\" equals 1.

Parameters:

Name Type Description Default df DataFrame required by str

Key in df. df is normalized for each by.

required on str

Key in df. Measurement to be normalized.

required

Returns:

Name Type Description df DataFrame

Same DataFrame with normalized on column.

Source code in cuisto/utils.py
def renormalize_per_key(df: pd.DataFrame, by: str, on: str):\n    \"\"\"\n    Renormalize `on` column by its sum for each `by`.\n\n    Use case : relative density is computed for both hemispheres, so if one wants to\n    plot only one hemisphere, the sum of the bars corresponding to one channel (`by`)\n    should be 1. So :\n    >>> df = df[df[\"hemisphere\"] == \"Ipsi.\"]\n    >>> df = renormalize_per_key(df, \"channel\", \"relative density\")\n    Then, the sum of \"relative density\" for each \"channel\" equals 1.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    by : str\n        Key in `df`. `df` is normalized for each `by`.\n    on : str\n        Key in `df`. Measurement to be normalized.\n\n    Returns\n    -------\n    df : pd.DataFrame\n        Same DataFrame with normalized `on` column.\n\n    \"\"\"\n    norm = df.groupby(by)[on].sum()\n    bys = df[by].unique()\n    for key in bys:\n        df.loc[df[by] == key, on] = df.loc[df[by] == key, on].divide(norm[key])\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.select_hemisphere_channel","title":"select_hemisphere_channel(df, hue, hue_filter, hue_mirror)","text":"

Select relevant data given hue and filters.

Returns the DataFrame with only things to be used.

Parameters:

Name Type Description Default df DataFrame

DataFrame to filter.

required hue (hemisphere, channel)

hue that will be used in seaborn plots.

\"hemisphere\" hue_filter str

Selected data.

required hue_mirror bool

Instead of keeping only hue_filter values, they will be plotted in mirror.

required

Returns:

Name Type Description dfplt DataFrame

DataFrame to be used in plots.

Source code in cuisto/utils.py
def select_hemisphere_channel(\n    df: pd.DataFrame, hue: str, hue_filter: str, hue_mirror: bool\n) -> pd.DataFrame:\n    \"\"\"\n    Select relevant data given hue and filters.\n\n    Returns the DataFrame with only things to be used.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame to filter.\n    hue : {\"hemisphere\", \"channel\"}\n        hue that will be used in seaborn plots.\n    hue_filter : str\n        Selected data.\n    hue_mirror : bool\n        Instead of keeping only hue_filter values, they will be plotted in mirror.\n\n    Returns\n    -------\n    dfplt : pd.DataFrame\n        DataFrame to be used in plots.\n\n    \"\"\"\n    dfplt = df.copy()\n\n    if hue == \"hemisphere\":\n        # hue_filter is used to select channels\n        # keep only left and right hemispheres, not \"both\"\n        dfplt = dfplt[dfplt[\"hemisphere\"] != \"both\"]\n        if hue_filter == \"all\":\n            hue_filter = dfplt[\"channel\"].unique()\n        elif not isinstance(hue_filter, (list, tuple)):\n            # it is allowed to select several channels so handle lists\n            hue_filter = [hue_filter]\n        dfplt = dfplt[dfplt[\"channel\"].isin(hue_filter)]\n    elif hue == \"channel\":\n        # hue_filter is used to select hemispheres\n        # it can only be left, right, both or empty\n        if hue_filter == \"both\":\n            # handle if it's a coordinates DataFrame which doesn't have \"both\"\n            if \"both\" not in dfplt[\"hemisphere\"].unique():\n                # keep both hemispheres, don't do anything\n                pass\n            else:\n                if hue_mirror:\n                    # we need to keep both hemispheres to plot them in mirror\n                    dfplt = dfplt[dfplt[\"hemisphere\"] != \"both\"]\n                else:\n                    # we keep the metrics computed in both hemispheres\n                    dfplt = dfplt[dfplt[\"hemisphere\"] == \"both\"]\n        else:\n            # hue_filter should correspond to an hemisphere name\n            dfplt = dfplt[dfplt[\"hemisphere\"] == hue_filter]\n    else:\n        # not handled. Just return the DataFrame without filtering, maybe it'll make\n        # sense.\n        warnings.warn(f\"{hue} should be 'channel' or 'hemisphere'.\")\n\n    # check result\n    if len(dfplt) == 0:\n        warnings.warn(\n            f\"hue={hue} and hue_filter={hue_filter} resulted in an empty subset.\"\n        )\n\n    return dfplt\n
"},{"location":"guide-create-pyramids.html","title":"Create pyramidal OME-TIFF","text":"

This page will guide you to use the pyramid-creator package, in the event the CZI file does not work directly in QuPath. The script will generate pyramids from OME-TIFF files exported from ZEN.

Tip

pyramid-creator can also pyramidalize images using Python only with the --no-use-qupath option.

This Python script uses QuPath under the hood, via a companion script called createPyramids.groovy. It will find the OME-TIFF files and make QuPath run the groovy script on it, in console mode (without graphical user interface).

This script is standalone, eg. it does not rely on the cuisto package. But installing the later makes sure all dependencies are installed (namely typer and tqdm with the QuPath backend and quite a few more for the Python backend).

pyramid-creator moved to a standalone package that you can find here with installation and usage instructions.

"},{"location":"guide-create-pyramids.html#installation","title":"Installation","text":"

You will find instructions on the dedicated project page over at Github.

For reference :

You will need conda, follow those instructions to install it.

Then, create a virtual environment if you didn't already (pyramid-creator can be installed in the environment for cuisto) and install the pyramid-creator package.

conda create -c conda-forge -n cuisto-env python=3.12  # not required if you already create an environment\nconda activate cuisto-env\npip install pyramid-creator\n
To use the Python backend (with tifffile), replace the last line with :
pip install pyramid-creator[python-backend]\n
To use the QuPath backend, a working QuPath installation is required, and the pyramid-creator command needs to be aware of its location.

To do so, first, install QuPath. By default, it will install in ~\\AppData\\QuPath-0.X.Y. In any case, note down the installation location.

Then, you have several options : - Create a file in your user directory called \"QUPATH_PATH\" (without extension), containing the full path to the QuPath console executable. In my case, it reads : C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe. Then, the pyramid-creator script will read this file to find the QuPath executable. - Specify the QuPath path as an option when calling the command line interface (see the Usage section) :

pyramid-creator /path/to/your/images --qupath-path \"C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe\"\n
- Specify the QuPath path as an option when using the package in a Python script (see the Usage section) :
from pyramid_creator import pyramidalize_directory\npyramidalize_directory(\"/path/to/your/images/\", qupath_path=\"C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe\")\n
- If you're using Windows, using QuPath v0.6.0, v0.5.1 or v0.5.0 and chose the default installation location, pyramid-creator should find it automatically and write it down in the \"QUPATH_PATH\" file by itself.

"},{"location":"guide-create-pyramids.html#export-czi-to-ome-tiff","title":"Export CZI to OME-TIFF","text":"

OME-TIFF is a specification of the TIFF image format. It specifies how the metadata should be written to the file to be interoperable between softwares. ZEN can export to OME-TIFF so you don't need to pay attention to metadata. Therefore, you won't need to specify pixel size and channels names and colors as it will be read directly from the OME-TIFF files.

  1. Open your CZI file in ZEN.
  2. Open the \"Processing tab\" on the left panel.
  3. Under method, choose Export/Import > OME TIFF-Export.
  4. In Parameters, make sure to tick the \"Show all\" tiny box on the right.
  5. The following parameters should be used (checked), the other should be unchecked :
    • Use Tiles
    • Original data \"Convert to 8 Bit\" should be UNCHECKED
    • OME-XML Scheme : 2016-06
    • Use full set of dimensions (unless you want to select slices and/or channels)
  6. In Input, choose your file
  7. Go back to Parameters to choose the output directory and file prefix. \"_s1\", \"_s2\"... will be appended to the prefix.
  8. Back on the top, click the \"Apply\" button.

The OME-TIFF files should be ready to be pyramidalized with the create_pyramids.py script.

"},{"location":"guide-create-pyramids.html#usage","title":"Usage","text":"

See the instructions on the dedicated project page over at Github.

"},{"location":"guide-install-abba.html","title":"Install ABBA","text":"

You can head to the ABBA documentation for installation instructions. You'll see that a Windows installer is available. While it might be working great, I prefer to do it manually step-by-step to make sure everything is going well.

You will find below installation instructions for the regular ABBA Fiji plugin, which proposes only the mouse and rat brain atlases. To be able to use the Brainglobe atlases, you will need the Python version. The two can be installed alongside each other.

"},{"location":"guide-install-abba.html#abba-fiji","title":"ABBA Fiji","text":""},{"location":"guide-install-abba.html#install-fiji","title":"Install Fiji","text":"

Install the \"batteries-included\" distribution of ImageJ, Fiji, from the official website.

Warning

Extract Fiji somewhere you have write access, otherwise Fiji will not be able to download and install plugins. In other words, put the folder in your User directory and not in C:\\, C:\\Program Files and the like.

  1. Download the zip archive and extract it somewhere relevant.
  2. Launch ImageJ.exe.
"},{"location":"guide-install-abba.html#install-the-abba-plugin","title":"Install the ABBA plugin","text":"

We need to add the PTBIOP update site, managed by the bio-imaging and optics facility at EPFL, that contains the ABBA plugin.

  1. In Fiji, head to Help > Update...
  2. In the ImageJ updater window, click on Manage Update Sites. Look up PTBIOP, and click on the check box. Apply and Close, and Apply Changes. This will download and install the required plugins. Restart ImageJ as suggested.
  3. In Fiji, head to Plugins > BIOP > Atlas > ABBA - ABBA start, or simply type abba start in the search box. Choose the \"Adult Mouse Brain - Allen Brain Atlas V3p1\". It will download this atlas and might take a while, depending on your Internet connection.
"},{"location":"guide-install-abba.html#install-the-automatic-registration-tools","title":"Install the automatic registration tools","text":"

ABBA can leverage the elastix toolbox for automatic 2D in-plane registration.

  1. You need to download it here, which will redirect you to the Github releases page (5.2.0 should work).
  2. Download the zip archive and extract it somewhere relevant.
  3. In Fiji, in the search box, type \"set and check\" and launch the \"Set and Check Wrappers\" command. Set the paths to \"elastix.exe\" and \"transformix.exe\" you just downloaded.

ABBA should be installed and functional ! You can check the official documentation for usage instructions and some tips here.

"},{"location":"guide-install-abba.html#abba-python","title":"ABBA Python","text":"

Brainglobe is an initiative aiming at providing interoperable, model-agnostic Python-based tools for neuroanatomy. They package various published volumetric anatomical atlases of different species (check the list), including the Allen Mouse brain atlas (CCFv3, ref.) and a 3D version of the Allen mouse spinal cord atlas (ref).

To be able to leverage those atlases, we need to make ImageJ and Python be able to talk to each other. This is the purpose of abba_python, that will install ImageJ and its ABBA plugins inside a python environment, with bindings between the two worlds.

"},{"location":"guide-install-abba.html#install-conda","title":"Install conda","text":"

If not done already, follow those instructions to install conda.

"},{"location":"guide-install-abba.html#install-abba_python-in-a-virtual-environment","title":"Install abba_python in a virtual environment","text":"
  1. Open a terminal (PowerShell).
  2. Create a virtual environment with Python 3.10, OpenJDK and PyImageJ :
    conda create -c conda-forge -n abba_python python=3.10 openjdk=11 maven pyimagej notebook\n
  3. Install the latest functional version of abba_python with pip :
    pip install abba-python==0.9.6.dev0\n
  4. Restart the terminal and activate the new environment :
    conda activate abba_python\n
  5. Download the Brainglobe atlas you want (eg. Allen mouse spinal cord) :
    brainglobe install -a allen_cord_20um\n
  6. Launch an interactive Python shell :
    ipython\n
    You should see the IPython prompt, that looks like this :
    In [1]:\n
  7. Import abba_python and launch ImageJ from Python :
    from abba_python import abba\nabba.start_imagej()\n
    The first launch needs to initialize ImageJ and install all required plugins, which takes a while (>5min).
  8. Use ABBA as the regular Fiji version ! The main difference is that the dropdown menu to select which atlas to use is populated with the Brainglobe atlases.

Tip

Afterwards, to launch ImageJ from Python and do some registration work, you just need to launch a terminal (PowerShell), and do steps 4., 6., and 7.

"},{"location":"guide-install-abba.html#install-the-automatic-registration-tools_1","title":"Install the automatic registration tools","text":"

You can follow the same instructions as the regular Fiji version. You can do it from either the \"normal\" Fiji or the ImageJ instance launched from Python, they share the same configuration files. Therefore, if you already did it in regular Fiji, elastix should already be set up and ready to use in ImageJ from Python.

"},{"location":"guide-install-abba.html#troubleshooting","title":"Troubleshooting","text":""},{"location":"guide-install-abba.html#java_home-errors","title":"JAVA_HOME errors","text":"

Unfortunately on some computers, Python does not find the Java virtual machine even though it should have been installed when installing OpenJDK with conda. This will result in an error mentionning \"java.dll\" and suggesting to check the JAVA_HOME environment variable.

The only fix I could find is to install Java system-wide. You can grab a (free) installer on Adoptium, choosing JRE 17.X for your platform. During the installation :

  • choose to install \"just for you\",
  • enable \"Modify PATH variable\" as well as \"Set or override JAVA_HOME\" variable.

Restart the terminal and try again. Now, ImageJ should use the system-wide Java and it should work.

"},{"location":"guide-install-abba.html#abba-qupath-extension","title":"ABBA QuPath extension","text":"

To import registered regions in your QuPath project and be able to convert objects' coordinates in atlas space, the ABBA QuPath extension is required.

  1. In QuPath, head to Edit > Preferences. In the Extension tab, set your QuPath user directory to a local directory (usually C:\\Users\\USERNAME\\QuPath\\v0.X.Y).
  2. Create a folder named extensions in your QuPath user directory.
  3. Download the latest ABBA extension for QuPath from GitHub (choose the file qupath-extension-abba-x.y.z.zip).
  4. Uncompress the archive and copy all .jar files into the extensions folder in your QuPath user directory.
  5. Restart QuPath. Now, in Extensions, you should have an ABBA entry.
"},{"location":"guide-pipeline.html","title":"Pipeline","text":"

While you can use QuPath and cuisto functionalities as you see fit, there exists a pipeline version of those. It requires a specific structure to store files (so that the different scripts know where to look for data). It also requires that you have detections stored as geojson files, which can be achieved using a pixel classifier and further segmentation (see here) for example.

"},{"location":"guide-pipeline.html#purpose","title":"Purpose","text":"

This is especially useful to perform quantification for several animals at once, where you'll only need to specify the root directory and the animals identifiers that should be pooled together, instead of having to manually specify each detections and annotations files.

Three main scripts and function are used within the pipeline :

  • exportPixelClassifierProbabilities.groovy to create prediction maps of objects of interest
  • segment_image.py to segment those maps and create geojson files to be imported back to QuPath as detections
  • pipelineImportExport.groovy to :
    • clear all objects
    • import ABBA regions
    • mirror regions names
    • import geojson detections (from $folderPrefix$segmentation/$segTag$/geojson)
    • add measurements to detections
    • add atlas coordinates to detections
    • add hemisphere to detections' parents
    • add regions measurements
      • count for punctal objects
      • cumulated length for lines objects
    • export detections measurements
      • as CSV for punctual objects
      • as JSON for lines
    • export annotations as CSV
"},{"location":"guide-pipeline.html#directory-structure","title":"Directory structure","text":"

Following a specific directory structure ensures subsequent scripts and functions can find required files. The good news is that this structure will mostly be created automatically using the segmentation scripts (from QuPath and Python), as long as you stay consistent filling the parameters of each script. The structure expected by the groovy all-in-one script and cuisto batch-process function is the following :

some_directory/\n    \u251c\u2500\u2500AnimalID0/  \n    \u2502   \u251c\u2500\u2500 animalid0_qupath/\n    \u2502   \u2514\u2500\u2500 animalid0_segmentation/  \n    \u2502       \u2514\u2500\u2500 segtag/  \n    \u2502           \u251c\u2500\u2500 annotations/  \n    \u2502           \u251c\u2500\u2500 detections/  \n    \u2502           \u251c\u2500\u2500 geojson/  \n    \u2502           \u2514\u2500\u2500 probabilities/  \n    \u251c\u2500\u2500AnimalID1/  \n    \u2502   \u251c\u2500\u2500 animalid1_qupath/\n    \u2502   \u2514\u2500\u2500 animalid1_segmentation/  \n    \u2502       \u2514\u2500\u2500 segtag/  \n    \u2502           \u251c\u2500\u2500 annotations/  \n    \u2502           \u251c\u2500\u2500 detections/  \n    \u2502           \u251c\u2500\u2500 geojson/  \n    \u2502           \u2514\u2500\u2500 probabilities/  \n

Info

Except the root directory and the QuPath project, the rest is automatically created based on the parameters provided in the different scripts. Here's the description of the structure and the requirements :

  • animalid0 should be a convenient animal identifier.
  • The hierarchy must be followed.
  • The experiment root directory, AnimalID0, can be anything but should correspond to one and only one animal.
  • Subsequent animalid0 should be lower case.
  • animalid0_qupath can be named as you wish in practice, but should be the QuPath project.
  • animalid0_segmentation should be called exactly like this -- replacing animalid0 with the actual animal ID. It will be created automatically with the exportPixelClassifierProbabilities.groovy script.
  • segtag corresponds to the type of segmentation (cells, fibers...). It is specified in the exportPixelClassifierProbabilities script. It could be anything, but to recognize if the objects are polygons (and should be counted per regions) or polylines (and the cumulated length should be measured), there are some hardcoded keywords in the segment_images.py and pipelineImportExport.groovy scripts :
    • Cells-like when you need measurements related to its shape (area, circularity...) : cells, cell, polygons, polygon
    • Cells-like when you consider them as punctual : synapto, synaptophysin, syngfp, boutons, points
    • Fibers-like (polylines) : fibers, fiber, axons, axon
  • annotations contains the atlas regions measurements as TSV files.
  • detections contains the objects atlas coordinates and measurements as CSV files (for punctal objects) or JSON (for polylines objects).
  • geojson contains objects stored as geojson files. They could be generated with the pixel classifier prediction map segmentation.
  • probabilities contains the prediction maps to be segmented by the segment_images.py script.

Tip

You can see an example minimal directory structure with only annotations stored in resources/multi.

"},{"location":"guide-pipeline.html#usage","title":"Usage","text":"

Tip

Remember that this is merely an example pipeline, you can shortcut it at any points, as long as you end up with TSV files following the requirements for cuisto.

  1. Create a QuPath project.
  2. Register your images on an atlas with ABBA and export the registration back to QuPath.
  3. Use a pixel classifier and export the prediction maps with the exportPixelClassifierProbabilities.groovy script. You need to get a pixel classifier or create one.
  4. Segment those maps with the segment_images.py script to generate the geojson files containing the objects of interest.
  5. Run the pipelineImportExport.groovy script on your QuPath project.
  6. Set up your configuration files.
  7. Then, analysing your data with any number of animals should be as easy as executing those lines in Python (either from IPython directly or in a script to easily run it later) :
import cuisto\n\n# Parameters\nwdir = \"/path/to/some_directory\"\nanimals = [\"AnimalID0\", \"AnimalID1\"]\nconfig_file = \"/path/to/your/config.toml\"\noutput_format = \"h5\"  # to save the quantification values as hdf5 file\n\n# Processing\ncfg = cuisto.Config(config_file)\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animals(\n    wdir, animals, cfg, out_fmt=output_format\n)\n\n# Display\ncuisto.display.plot_regions(df_regions, cfg)\ncuisto.display.plot_1D_distributions(dfs_distributions, cfg, df_coordinates=df_coordinates)\ncuisto.display.plot_2D_distributions(df_coordinates, cfg)\n

Tip

You can see a live example in this demo notebook.

"},{"location":"guide-prepare-qupath.html","title":"Prepare QuPath data","text":"

cuisto uses some QuPath classifications concepts, make sure to be familiar with them with the official documentation. Notably, we use the concept of primary classification and derived classification : an object classfied as First: second is of classification First and of derived classification second.

"},{"location":"guide-prepare-qupath.html#qupath-requirements","title":"QuPath requirements","text":"

cuisto assumes a specific way of storing regions and objects information in the TSV files exported from QuPath. Note that only one primary classification is supported, but you can have any number of derived classifications.

"},{"location":"guide-prepare-qupath.html#detections","title":"Detections","text":"

Detections are the objects of interest. Their information must respect the following :

  • Atlas coordinates should be in millimetres (mm) and stored as Atlas_X, Atlas_Y, Atlas_Z. They correspond, respectively, to the anterio-posterior (rostro-caudal) axis, the inferio-superior (dorso-ventral) axis and the left-right (medio-lateral) axis.
  • They must have a derived classification, in the form Primary: second. Primary would be an object type (cells, fibers, ...), the second one would be a biological marker or a detection channel (fluorescence channel name), for instance : Cells: some marker, or Fibers: EGFP.
  • The classification must match exactly the corresponding measurement in the annotations (see below).
"},{"location":"guide-prepare-qupath.html#annotations","title":"Annotations","text":"

Annotations correspond to the atlas regions. Their information must respect the following :

  • They should be imported with the ABBA extension as acronyms and splitting left/right. Therefore, the annotation name should be the region acronym and its classification should be formatted as Hemisphere: acronym (for ex. Left: PAG).
  • Measurements names should be formatted as : Primary classification: derived classification measurement name. For instance :
    • if one has cells with some marker and count them in each atlas regions, the measurement name would be : Cells: some marker Count.
    • if one segments fibers revealed in the EGFP channel and measures the cumulated length in \u00b5m in each atlas regions, the measurement name would be : Fibers: EGFP Length \u00b5m.
  • Any number of markers or channels are supported.
"},{"location":"guide-prepare-qupath.html#measurements","title":"Measurements","text":""},{"location":"guide-prepare-qupath.html#metrics-supported-by-cuisto","title":"Metrics supported by cuisto","text":"

While you're free to add any measurements as long as they follow the requirements, keep in mind that for atlas regions quantification, cuisto will only compute, pool and average the following metrics :

  • the base measurement itself
    • if \"\u00b5m\" is contained in the measurement name, it will also be converted to mm (\\(\\div\\)1000)
  • the base measurement divided by the region area in \u00b5m\u00b2 (density in something/\u00b5m\u00b2)
  • the base measurement divided by the region area in mm\u00b2 (density in something/mm\u00b2)
  • the squared base measurement divided by the region area in \u00b5m\u00b2 (could be an index, in weird units...)
  • the relative base measurement : the base measurement divided by the total base measurement across all regions in each hemisphere
  • the relative density : density divided by total density across all regions in each hemisphere

It is then up to you to select which metrics among those to compute and display and name them, via the configuration file.

For punctal detections (eg. objects whose only the centroid is considered), only the atlas coordinates are used, to compute and display spatial distributions of objects across the brain (using their classifications to give each distributions different hues). For fibers-like objects, it requires to export the lines detections atlas coordinates as JSON files, with the exportFibersAtlasCoordinates.groovy script (this is done automatically when using the pipeline).

"},{"location":"guide-prepare-qupath.html#adding-measurements","title":"Adding measurements","text":""},{"location":"guide-prepare-qupath.html#count-for-cell-like-objects","title":"Count for cell-like objects","text":"

The groovy script under scripts/qupath-utils/measurements/addRegionsCount.groovy will add a properly formatted count of objects of selected classifications in all atlas regions. This is used for punctual objects (polygons or points), for example objects created in QuPath or with the segmentation script.

"},{"location":"guide-prepare-qupath.html#cumulated-length-for-fibers-like-objects","title":"Cumulated length for fibers-like objects","text":"

The groovy script under scripts/qupath-utils/measurements/addRegionsLength.groovy will add the properly formatted cumulated lenghth in microns of fibers-like objects in all atlas regions. This is used for polylines objects, for example generated with the segmentation script.

"},{"location":"guide-prepare-qupath.html#custom-measurements","title":"Custom measurements","text":"

Keeping in mind cuisto limitations, you can add any measurements you'd like.

For example, you can run a pixel classifier in all annotations (eg. atlas regions). Using the Measure button, it will add a measurement of the area covered by classified pixels. Then, you can use the script located under scripts/qupath-utils/measurements/renameMeasurements.groovy to rename the generated measurements with a properly-formatted name. Finally, you can export regions measurements.

Since cuisto will compute a \"density\", eg. the measurement divided by the region area, in this case, it will correspond to the fraction of surface occupied by classified pixels. This is showcased in the Examples.

"},{"location":"guide-prepare-qupath.html#qupath-export","title":"QuPath export","text":"

Once you imported atlas regions registered with ABBA, detected objects in your images and added properly formatted measurements to detections and annotations, you can :

  • Head to Measure > Export measurements
  • Select relevant images
  • Choose the Output file (specify in the file name if it is a detections or annotations file)
  • Chose either Detections or Annoations in Export type
  • Click Export

Do this for both Detections and Annotations, you can then use those files with cuisto (see the Examples).

"},{"location":"guide-qupath-objects.html","title":"Detect objects with QuPath","text":"

The QuPath documentation is quite extensive, detailed, very well explained and contains full guides on how to create a QuPath project and how to find objects of interests. It is therefore a highly recommended read, nevertheless, you will find below some quick reminders.

"},{"location":"guide-qupath-objects.html#qupath-project","title":"QuPath project","text":"

QuPath works with projects. It is basically a folder with a main project.qproj file, which is a JSON file that contains all the data about your images except the images themselves. Algonside, there is a data folder with an entry for each image, that stores the thumbnails, metadata about the image and detections and annotations but, again, not the image itself. The actual images can be stored anywhere (including a remote server), the QuPath project merely contains the information needed to fetch them and display them. QuPath will never modify your image data.

This design makes the QuPath project itself lightweight (should never exceed 500MB even with millions of detections), and portable : upon opening, if QuPath is not able to find the images where they should be, it will ask for their new locations.

Tip

It is recommended to create the QuPath project locally on your computer, to avoid any risk of conflicts if two people open it at the same time. Nevertheless, you should backup the project regularly on a remote server.

To create a new project, simply drag & drop an empty folder into QuPath window and accept to create a new empty project. Then, add images :

  • If you have a single file, just drag & drop it in the main window.
  • If you have several images, in the left panel, click Add images, then Choose files on the bottom. Drag & drop does not really work as the images will not be sorted properly.

Then, choose the following options :

Image server

Default (let QuPath decide)

Set image type

Most likely, fluorescence

Rotate image

No rotation (unless all your images should be rotated)

Optional args

Leave empty

Auto-generate pyramids

Uncheck

Import objects

Uncheck

Show image selector

Might be useful to check if the images are read correctly (mostly for CZI files).

"},{"location":"guide-qupath-objects.html#detect-objects","title":"Detect objects","text":""},{"location":"guide-qupath-objects.html#built-in-cell-detection","title":"Built-in cell detection","text":"

QuPath has a built-in cell detection feature, available in Analyze > Cell detection. You hava a full tutorial in the official documentation.

Briefly, this uses a watershed algorithm to find bright spots and can perform a cell expansion to estimate the full cell shape based on the detected nuclei. Therefore, this works best to segment nuclei but one can expect good performance for cells as well, depending on the imaging and staining conditions.

Tip

In scripts/qupath-utils/segmentation, there is watershedDetectionFilters.groovy which uses this feature from a script. It further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#pixel-classifier","title":"Pixel classifier","text":"

Another very powerful and versatile way to segment cells if through machine learning. Note the term \"machine\" and not \"deep\" as it relies on statistics theory from the 1980s. QuPath provides an user-friendly interface to that, similar to what ilastik provides.

The general idea is to train a model to classify every pixel as a signal or as background. You can find good resources on how to procede in the official documentation and some additionnal tips and tutorials on Michael Neslon's blog (here and here).

Specifically, you will manually annotate some pixels of objects of interest and background. Then, you will apply some image processing filters (gaussian blur, laplacian...) to reveal specific features in your images (shapes, textures...). Finally, the pixel classifier will fit a model on those pixel values, so that it will be able to predict if a pixel, given the values with the different filters you applied, belongs to an object of interest or to the background.

This is done in an intuitive GUI with live predictions to get an instant feedback on the effects of the filters and manual annotations.

"},{"location":"guide-qupath-objects.html#train-a-model","title":"Train a model","text":"

First and foremost, you should use a QuPath project dedicated to the training of a pixel classifier, as it is the only way to be able to edit it later on.

  1. You should choose some images from different animals, with different imaging conditions (staining efficiency and LED intensity) in different regions (eg. with different objects' shape, size, sparsity...). The goal is to get the most diversity of objects you could encounter in your experiments. 10 images is more than enough !
  2. Import those images to the new, dedicated QuPath project.
  3. Create the classifications you'll need, \"Cells: marker+\" for example. The \"Ignore*\" classification is used for the background.
  4. Head to Classify > Pixel classification > Train pixel classifier, and turn on Live prediction.
  5. Load all your images in Load training.
  6. In Advanced settings, check Reweight samples to help make sure a classification is not over-represented.
  7. Modify the different parameters :
    • Classifier : typically, RTrees or ANN_MLP. This can be changed dynamically afterwards to see which works best for you.
    • Resolution : this is the pixel size used. This is a trade-off between accuracy and speed. If your objects are only composed of a few pixels, you'll the full resolution, for big objects reducing the resolution will be faster.
    • Features : this is the core of the process -- where you choose the filters. In Edit, you'll need to choose :
      • The fluorescence channels
      • The scales, eg. the size of the filters applied to the image. The bigger, the coarser the filter is. Again, this will depend on the size of the objects you want to segment.
      • The features themselves, eg. the filters applied to your images before feeding the pixel values to the model. For starters, you can select them all to see what they look like.
    • Output :
      • Classification : QuPath will directly classify the pixels. Use that to create objects directly from the pixel classifier within QuPath.
      • Probability : this will output an image where each pixel is its probability to belong to each of the classifications. This is useful to create objects externally.
  8. In the bottom-right corner of the pixel classifier window, you can select to display each filters individually. Then in the QuPath main window, hitting C will switch the view to appreciate what the filter looks like. Identify the ones that makes your objects the most distinct from the background as possible. Switch back to Show classification once you begin to make annotations.
  9. Begin to annotate ! Use the Polyline annotation tool (V) to classify some pixels belonging to an object and some pixels belonging to the background across your images.

    Tip

    You can select the RTrees Classifier, then Edit : check the Calculate variable importance checkbox. Then in the log (Ctrl+Shift+L), you can inspect the weight each features have. This can help discard some filters to keep only the ones most efficient to distinguish the objects of interest.

  10. See in live the effect of your annotations on the classification using C and continue until you're satisfied.

    Important

    This is machine learning. The lesser annotations, the better, as this will make your model more general and adapt to new images. The goal is to find the minimal number of annotations to make it work.

  11. Once you're done, give your classifier a name in the text box in the bottom and save it. It will be stored as a JSON file in the classifiers folder of the QuPath project. This file can be imported in your other QuPath projects.

"},{"location":"guide-qupath-objects.html#built-in-create-objects","title":"Built-in create objects","text":"

Once you imported your model JSON file (Classify > Pixel classification > Load pixel classifier, three-dotted menu and Import from file), you can create objects out of it, measure the surface occupied by classified pixels in each annotation or classify existing detections based on the prediction at their centroid.

In scripts/qupath-utils/segmentation, there is a createDetectionsFromPixelClassifier.groovy script to batch-process your project.

"},{"location":"guide-qupath-objects.html#probability-map-segmentation","title":"Probability map segmentation","text":"

Alternatively, a Python script provided with cuisto can be used to segment the probability map generated by the pixel classifier (the script is located in scripts/segmentation).

You will first need to export those with the exportPixelClassifierProbabilities.groovy script (located in scripts/qupath-utils).

Then the segmentation script can :

  • find punctal objects as polygons (with a shape) or points (punctal) than can be counted.
  • trace fibers with skeletonization to create lines whose lengths can be measured.

Several parameters have to be specified by the user, see the segmentation script API reference. This script will generate GeoJson files that can be imported back to QuPath with the importGeojsonFiles.groovy script.

"},{"location":"guide-qupath-objects.html#third-party-extensions","title":"Third-party extensions","text":"

QuPath being open-source and extensible, there are third-party extensions that implement popular deep learning segmentation algorithms directly in QuPath. They can be used to find objects of interest as detections in the QuPath project and thus integrate nicely with cuisto to quantify them afterwards.

"},{"location":"guide-qupath-objects.html#instanseg","title":"InstanSeg","text":"

QuPath extension : https://github.com/qupath/qupath-extension-instanseg Original repository : https://github.com/instanseg/instanseg Reference papers : doi:10.48550/arXiv.2408.15954, doi:10.1101/2024.09.04.611150

"},{"location":"guide-qupath-objects.html#stardist","title":"Stardist","text":"

QuPath extension : https://github.com/qupath/qupath-extension-stardist Original repository : https://github.com/stardist/stardist Reference paper : doi:10.48550/arXiv.1806.03535

There is a stardistDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#cellpose","title":"Cellpose","text":"

QuPath extension : https://github.com/BIOP/qupath-extension-cellpose Original repository : https://github.com/MouseLand/cellpose Reference papers : doi:10.1038/s41592-020-01018-x, doi:10.1038/s41592-022-01663-4, doi:10.1101/2024.02.10.579780

There is a cellposeDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#sam","title":"SAM","text":"

QuPath extension : https://github.com/ksugar/qupath-extension-sam Original repositories : samapi, SAM Reference papers : doi:10.1101/2023.06.13.544786, doi:10.48550/arXiv.2304.02643

This is more an interactive annotation tool than a fully automatic segmentation algorithm.

"},{"location":"guide-register-abba.html","title":"Registration with ABBA","text":"

The ABBA documentation is quite extensive and contains guided tutorials and a video tutorial. You should therefore check it out ! Nevertheless, you will find below some quick reminders.

"},{"location":"guide-register-abba.html#import-a-qupath-project","title":"Import a QuPath project","text":"

Always use ABBA with a QuPath project, if you import the images directly it will not be possible to export the results back to QuPath. In the toolbar, head to Import > Import QuPath Project.

  • Select the .qproj file corresponding to the QuPath project to be aligned.
  • Initial axis position : this is the initial position where to put your stack. It will be modified afterwards.
  • Axis increment between slices : this is the spatial spacing, in mm, between two slices. This would correspond to the slice thickness multiplied by the number of set. If your images are ordered from rostral to caudal, set it negative.

Warning

ABBA is not the most stable software, it is highly recommended to save in a different file each time you do anything.

"},{"location":"guide-register-abba.html#navigation","title":"Navigation","text":""},{"location":"guide-register-abba.html#interface","title":"Interface","text":"
  • Left Button + drag to select slices
  • Right Button for display options
  • Right Button + drag to browse the view
  • Middle Button to zoom in and or out
"},{"location":"guide-register-abba.html#right-panel","title":"Right panel","text":"

In the right panel, there is everything related to the images, both yours and the atlas.

In the Atlas Display section, you can turn on and off different channels (the first is the reference image, the last is the regions outlines). The Displayed slicing [atlas steps] slider can increase or decrease the number of displayed 2D slices extracted from the 3D volume. It is comfortable to set to to the same spacing as your slices. Remember it is in \"altas steps\", so for an atlas imaged at 10\u00b5m, a 120\u00b5m spacing corresponds to 12 atlas steps.

The Slices Display section lists all your slices. Ctrl+A to select all, and click on the Vis. header to make them visible. Then, you can turn on and off each channels (generally the NISSL channel and the ChAT channel will be used) by clicking on the corresponding header. Finally, set the display limits clicking on the empty header containing the colors.

Right Button in the main view to Change overlap mode twice to get the slices right under the atlas slices.

Tip

Every action in ABBA are stored and are cancellable with Right Button+Z, except the Interactive transform.

"},{"location":"guide-register-abba.html#find-position-and-angle","title":"Find position and angle","text":"

This is the hardest task. You need to drag the slices along the rostro-caudal axis and modify the virtual slicing angle (X Rotation [deg] and Y Rotation [deg] sliders at the bottom of the right panel) until you match the brain structures observed in both your images and the atlas.

Tip

With a high number of slices, most likely, it will be impossible to find a position and slicing angle that works for all your slices. In that case, you should procede in batch, eg. sub-stack of images with a unique position and slicing angle that works for all images in the sub-stack. Then, remove the remaining slices (select them, Right Button > Remove Selected Slices), but do not remove them from the QuPath project.

Procede as usual, including saving (note the slices range it corresponds to) and exporting the registration back to QuPath. Then, reimport the project in a fresh ABBA instance, remove the slices that were already registered and redo the whole process with the next sub-stack and so on.

Once you found the correct position and slicing angle, it must not change anymore, otherwise the registration operations you perform will not make any sense anymore.

"},{"location":"guide-register-abba.html#in-plane-registration","title":"In-plane registration","text":"

The next step is to deform your slices to match the corresponding atlas image, extracted from the 3D volume given the position and virtual slicing angle defined at the previous step.

Info

ABBA makes the choice to deform your slices to the atlas, but the transformations are invertible. This means that you will still be able to work on your raw data and deform the altas onto it instead.

In image processing, there are two kinds of deformation one can apply on an image :

  • Affine (or linear) : simple, image-wide, linear operations - translation, rotation, scaling, shearing.
  • Spline (or non-linear) : complex non-linear operations that can allow for local deformation.

Both can be applied manually or automatically (if the imaging quality allows it). You have different tools to achieve this, all of which can be combined in any order, except the Interactive transform tool (coarse, linear manual deformation).

Change the overlap mode (Right Button) to overlay the slice onto the atlas regions borders. Select the slice you want to align.

"},{"location":"guide-register-abba.html#coarse-linear-manual-deformation","title":"Coarse, linear manual deformation","text":"

While not mandatory, if this tool shall be used, it must be before any operation as it is not cancellable. Head to Register > Affine > Interactive transform. This will open a box where you can rotate, translate and resize the image to make a first, coarse alignment.

Close the box. Again, this is not cancellable. Afterwards, you're free to apply any numbers of transformations in any order.

"},{"location":"guide-register-abba.html#automatic-registration","title":"Automatic registration","text":"

This uses the elastix toolbox to compute the transformations needed to best match two images. It is available in both affine and spline mode, in the Register > Affine and Register > Spline menus respectively.

In both cases, it will open a dialog where you need to choose :

  • Atlas channels : the reference image of the atlas, usually channel number 0
  • Slices channels : the fluorescence channel that looks like the most to the reference image, usually channel number 0
  • Registration re-sampling (micrometers) : the pixel size to resize the images before registration, as it is a computationally intensive task. Going below 20\u00b5m won't help much.

For the Spline mode, there an additional parameter :

  • Number of control points along X : the algorithm will set points as a grid in the image and perform the transformations from those. The higher number of points, the more local transformations will be.
"},{"location":"guide-register-abba.html#manual-registration","title":"Manual registration","text":"

This uses BigWarp to manually deform the images with the mouse. It can be done from scratch (eg. you place the points yourself) or from a previous registration (either a previous BigWarp session or elastix in Spline mode).

"},{"location":"guide-register-abba.html#from-scratch","title":"From scratch","text":"

Register > Spline > BigWarp registration to launch the tool. Choose the atlas that allows you to best see the brain structures (usually the regions outlines channels, the last one), and the reference fluorescence channel.

It will open two viewers, called \"BigWarp moving image\" and \"BigWarp fixed image\". Briefly, they correspond to the two spaces you're working in, the \"Atlas space\" and the \"Slice space\".

Tip

Do not panick yet, while the explanations might be confusing (at least they were to me), in practice, it is easy, intuitive and can even be fun (sometimes, at small dose).

To browse the viewer, use Right Button + drag (Left Button is used to rotate the viewer), Middle Button zooms in and out.

The idea is to place points, called landmarks, that always go in pairs : one in the moving image and one where it corresponds to in the fixed image (or vice-versa). In practice, we will only work in the BigWarp fixed image viewer to place landmarks in both space in one click, then drag it to the corresponding location, with a live feedback of the transformation needed to go from one to another.

To do so :

  1. Press Space to switch to the \"Landmark mode\".

    Warning

    In \"Landmark mode\", Right Button can't be used to browse the view anymore. To do so, turn off the \"Landmark mode\" hitting Space again.

  2. Use Ctrl+Left Button to place a landmark.

    Info

    At least 4 landmarks are needed before activating the live-transform view.

  3. When there are at least 4 landmarks, hit T to activate the \"Transformed\" view. Transformed will be written at the bottom.

  4. Hold Left Button on a landmark to drag it to deform the image onto the atlas.
  5. Add as many landmarks as needed, when you're done, find the Fiji window called \"Big Warp registration\" that opened at the beginning and click OK.

Important remarks and tips

  • A landmark is a location where you said \"this location correspond to this one\". Therefore, BigWarp is not allowed to move this particular location. Everywhere else, it is free to transform the image without any restrictions, including the borders. Thus, it is a good idea to delimit the coarse contour of the brain with landmarks to constrain the registration.
  • Left Button without holding Ctrl will place a landmark in the fixed image only, without pair, and BigWarp won't like it. To delete landmarks, head to the \"Landmarks\" window that lists all of them. They highlight in the viewer upon selection. Hit Del to delete one. Alternatively, click on it on the viewer and hit Del.
"},{"location":"guide-register-abba.html#from-a-previous-registration","title":"From a previous registration","text":"

Head to Register > Edit last Registration to work on a previous registration.

If the previous registration was done with elastix (Spline) or BigWarp, it will launch the BigWarp interface exactly like above, but with landmarks already placed, either on a grid (elastix) or the one you manually placed (BigWarp).

Tip

It will ask which channels to use, you can modify the channel for your slices to work on two channels successively. For instance, one could make a first registration using the NISSL staining, then refine the motoneurons with the ChAT staining, if available.

"},{"location":"guide-register-abba.html#abba-state-file","title":"ABBA state file","text":"

ABBA can save the state you're in, from the File > Save State menu. It will be saved as a .abba file, which is actually a zip archive containing a bunch of JSON, listing every actions you made and in which order, meaning you will stil be able to cancel actions after quitting ABBA.

To load a state, quit ABBA, launch it again, then choose File > Load State and select the .abba file to carry on with the registration.

Save, save, save !

Those state files are cheap, eg. they are lightweight (less than 200KB). You should save the state each time you finish a slice, and you can keep all your files, without overwritting the previous ones, appending a number to its file name. This will allow to roll back to the previous slice in the event of any problem you might face.

"},{"location":"guide-register-abba.html#export-registration-back-to-qupath","title":"Export registration back to QuPath","text":""},{"location":"guide-register-abba.html#export-the-registration-from-abba","title":"Export the registration from ABBA","text":"

Once you are satisfied with your registration, select the registered slices and head to Export > QuPath > Export Registrations To QuPath Project. Check the box to make sure to get the latest registered regions.

It will export several files in the QuPath projects, including the transformed atlas regions ready to be imported in QuPath and the transformations parameters to be able to convert coordinates from the extension.

"},{"location":"guide-register-abba.html#import-the-registration-in-qupath","title":"Import the registration in QuPath","text":"

Make sure you installed the ABBA extension in QuPath.

From your project with an image open, the basic usage is to head to Extensions > ABBA > Load Atlas Annotations into Open Image. Choose to Split Left and Right Regions to make the two hemispheres independent, and choose the \"acronym\" to name the regions. The registered regions should be imported as Annotations in the image.

Tip

With ABBA in regular Fiji using the CCFv3 Allen mouse brain atlas, the left and right regions are flipped, because ABBA considers the slices as backward facing. The importAbba.groovy script located in scripts/qupath-utils-atlas allows you to flip left/right regions names. This is OK because the Allen brain is symmetrical by construction.

For more complex use, check the Groovy scripts in scripts/qupath-utils/atlas. ABBA registration is used throughout the guides, to either work with brain regions (and count objects for instance) or to get the detections' coordinates in the atlas space.

"},{"location":"main-citing.html","title":"Citing","text":"

While cuisto does not have a reference paper as of now, you can reference the GitHub repository.

Please make sure to cite all the softwares used in your research. Citations are usually the only metric used by funding agencies, so citing properly the tools used in your research ensures the continuation of those projects.

  • Fiji : https://imagej.net/software/fiji/#publication
  • QuPath : https://qupath.readthedocs.io/en/stable/docs/intro/citing.html
  • ABBA : doi:10.1101/2024.09.06.611625
  • Brainglobe :
    • AtlasAPI : https://brainglobe.info/documentation/brainglobe-atlasapi/index.html#citation
    • Brainrender : https://brainglobe.info/documentation/brainrender/index.html#citation
  • Allen brain atlas (CCFv3) : doi:10.1016/j.cell.2020.04.007
  • 3D Allen spinal cord atlas : doi:10.1016/j.crmeth.2021.100074
  • Skeleton analysis (for fibers-like segmentation) : doi:10.7717/peerj.4312
"},{"location":"main-configuration-files.html","title":"The configuration files","text":"

There are three configuration files : altas_blacklist, atlas_fusion and a modality-specific file, that we'll call config in this document. The former two are related to the atlas you're using, the latter is what is used by cuisto to know what and how to compute and display things. There is a fourth, optional, file, used to provide some information on a specific experiment, info.

The configuration files are in the TOML file format, that are basically text files formatted in a way that is easy to parse in Python. See here for a basic explanation of the syntax.

Most lines of each template file are commented to explain what each parameter do.

"},{"location":"main-configuration-files.html#atlas_blacklisttoml","title":"atlas_blacklist.toml","text":"Click to see an example file atlas_blacklist.toml
# TOML file to list Allen brain regions to ignore during analysis.\n# \n# It is used to blacklist regions and all descendants regions (\"WITH_CHILD\").\n# Objects belonging to those regions and their descendants will be discarded.\n# And you can specify an exact region where to remove objects (\"EXACT\"),\n# descendants won't be affected.\n# Use it to remove noise in CBX, ventricual systems and fiber tracts.\n# Regions are referenced by their exact acronym.\n#\n# Syntax :\n#   [WITH_CHILDS]\n#   members = [\"CBX\", \"fiber tracts\", \"VS\"]\n#\n#   [EXACT]\n#   members = [\"CB\"]\n\n\n[WITH_CHILDS]\nmembers = [\"CBX\", \"fiber tracts\", \"VS\"]\n\n[EXACT]\nmembers = [\"CB\"]\n

This file is used to filter out specified regions and objects belonging to them.

  • The atlas regions present in the members keys will be ignored. Objects whose parents are in here will be ignored as well.
  • In the [WITH_CHILDS] section, regions and objects belonging to those regions and all descending regions (child regions, as per the altas hierarchy) will be removed.
  • In the [EXACT] section, only regions and objects belonging to those exact regions are removed. Descendants regions are not taken into account.
"},{"location":"main-configuration-files.html#atlas_fusiontoml","title":"atlas_fusion.toml","text":"Click to see an example file atlas_blacklist.toml
# TOML file to determine which brain regions should be merged together.\n# Regions are referenced by their exact acronym.\n# The syntax should be the following :\n# \n#   [MY]\n#   name = \"Medulla\"  # new or existing full name\n#   acronym = \"MY\"  # new or existing acronym\n#   members = [\"MY-mot\", \"MY-sat\"]  # existing Allen Brain acronyms that should belong to the new region\n#\n# Then, regions labelled \"MY-mot\" and \"MY-sat\" will be labelled \"MY\" and will join regions already labelled \"MY\".\n# What's in [] does not matter but must be unique and is used to group.\n# The new \"name\" and \"acronym\" can be existing Allen Brain regions or a new (meaningful) one.\n# Note that it is case sensitive.\n\n[PHY]\nname = \"Perihypoglossal nuclei\"\nacronym = \"PHY\"\nmembers = [\"NR\", \"PRP\"]\n\n[NTS]\nname = \"Nucleus of the solitary tract\"\nacronym = \"NTS\"\nmembers = [\"ts\", \"NTSce\", \"NTSco\", \"NTSge\", \"NTSl\", \"NTSm\"]\n\n[AMB]\nname = \"Nucleus ambiguus\"\nacronym = \"AMB\"\nmembers = [\"AMBd\", \"AMBv\"]\n\n[MY]\nname = \"Medulla undertermined\"\nacronym = \"MYu\"\nmembers = [\"MY-mot\", \"MY-sat\"]\n\n[IRN]\nname = \"Intermediate reticular nucleus\"\nacronym = \"IRN\"\nmembers = [\"IRN\", \"LIN\"]\n

This file is used to group regions together, to customize the atlas' hierarchy. It is particularly useful to group smalls brain regions that are impossible to register precisely. Keys name, acronym and members should belong to a [section].

  • [section] is just for organizing, the name does not matter but should be unique.
  • name should be a human-readable name for your new region.
  • acronym is how the region will be refered to. It can be a new acronym, or an existing one.
  • members is a list of acronyms of atlas regions that should be part of the new one.
"},{"location":"main-configuration-files.html#configtoml","title":"config.toml","text":"Click to see an example file config_template.toml
########################################################################################\n# Configuration file for cuisto package\n# -----------------------------------------\n# This is a TOML file. It maps a key to a value : `key = value`.\n# Each key must exist and be filled. The keys' names can't be modified, except:\n#   - entries in the [channels.names] section and its corresponding [channels.colors] section,\n#   - entries in the [regions.metrics] section.                                                                                   \n#\n# It is strongly advised to NOT modify this template but rather copy it and modify the copy.\n# Useful resources :\n#   - the TOML specification : https://toml.io/en/\n#   - matplotlib colors : https://matplotlib.org/stable/gallery/color/color_demo.html\n#\n# Configuration file part of the python cuisto package.\n# version : 2.1\n########################################################################################\n\nobject_type = \"Cells\"  # name of QuPath base classification (eg. without the \": subclass\" part)\nsegmentation_tag = \"cells\"  # type of segmentation, matches directory name, used only in the full pipeline\n\n[atlas]  # information related to the atlas used\nname = \"allen_mouse_10um\"  # brainglobe-atlasapi atlas name\ntype = \"brain\"  # brain or cord (eg. registration done in ABBA or abba_python)\nmidline = 5700  # midline Z coordinates (left/right limit) in microns\noutline_structures = [\"root\", \"CB\", \"MY\", \"P\"]  # structures to show an outline of in heatmaps\n\n[channels]  # information related to imaging channels\n[channels.names]  # must contain all classifications derived from \"object_type\"\n\"marker+\" = \"Positive\"  # classification name = name to display\n\"marker-\" = \"Negative\"\n[channels.colors]  # must have same keys as names' keys\n\"marker+\" = \"#96c896\"  # classification name = matplotlib color (either #hex, color name or RGB list)\n\"marker-\" = \"#688ba6\"\n\n[hemispheres]  # information related to hemispheres\n[hemispheres.names]\nLeft = \"Left\"  # Left = name to display\nRight = \"Right\"  # Right = name to display\n[hemispheres.colors]  # must have same keys as names' keys\nLeft = \"#ff516e\"  # Left = matplotlib color (either #hex, color name or RGB list)\nRight = \"#960010\"  # Right = matplotlib color\n\n[distributions]  # spatial distributions parameters\nstereo = true  # use stereotaxic coordinates (Paxinos, only for brain)\nap_lim = [-8.0, 0.0]  # bins limits for anterio-posterior\nap_nbins = 75  # number of bins for anterio-posterior\ndv_lim = [-1.0, 7.0]  # bins limits for dorso-ventral\ndv_nbins = 50  # number of bins for dorso-ventral\nml_lim = [-5.0, 5.0]  # bins limits for medio-lateral\nml_nbins = 50  # number of bins for medio-lateral\nhue = \"channel\"  # color curves with this parameter, must be \"hemisphere\" or \"channel\"\nhue_filter = \"Left\"  # use only a subset of data. If hue=hemisphere : channel name, list of such or \"all\". If hue=channel : hemisphere name or \"both\".\ncommon_norm = true  # use a global normalization for each hue (eg. the sum of areas under all curves is 1)\n[distributions.display]\nshow_injection = false  # add a patch showing the extent of injection sites. Uses corresponding channel colors\ncmap = \"OrRd\"  # matplotlib color map for heatmaps\ncmap_nbins = 50  # number of bins for heatmaps\ncmap_lim = [1, 50]  # color limits for heatmaps\n\n[regions]  # distributions per regions parameters\nbase_measurement = \"Count\"  # the name of the measurement in QuPath to derive others from\nhue = \"channel\"  # color bars with this parameter, must be \"hemisphere\" or \"channel\"\nhue_filter = \"Left\"  # use only a subset of data. If hue=hemisphere : channel name, list of such or \"all\". If hue=channel : hemisphere name or \"both\".\nhue_mirror = false  # plot two hue_filter in mirror instead of discarding the other\nnormalize_starter_cells = false  # normalize non-relative metrics by the number of starter cells\n[regions.metrics]  # names of metrics. Do not change the keys !\n\"density \u00b5m^-2\" = \"density \u00b5m^-2\"\n\"density mm^-2\" = \"density mm^-2\"\n\"coverage index\" = \"coverage index\"\n\"relative measurement\" = \"relative count\"\n\"relative density\" = \"relative density\"\n[regions.display]\nnregions = 18  # number of regions to display (sorted by max.)\norientation = \"h\"  # orientation of the bars (\"h\" or \"v\")\norder = \"max\"  # order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order\ndodge = true  # enforce the bar not being stacked\nlog_scale = false  # use log. scale for metrics\n[regions.display.metrics]  # name of metrics to display\n\"count\" = \"count\"  # real_name = display_name, with real_name the \"values\" in [regions.metrics]\n\"density mm^-2\" = \"density (mm^-2)\"\n\n[files]  # full path to information TOML files\nblacklist = \"../../atlas/atlas_blacklist.toml\"\nfusion = \"../../atlas/atlas_fusion.toml\"\noutlines = \"/data/atlases/allen_mouse_10um_outlines.h5\"\ninfos = \"../../configs/infos_template.toml\"\n

This file is used to configure cuisto behavior. It specifies what to compute, how, and display parameters such as colors associated to each classifications, hemisphere names, distributions bins limits...

Warning

When editing your config.toml file, you're allowed to modify the keys only in the [channels] section.

Click for a more readable parameters explanation

object_type : name of QuPath base classification (eg. without the \": subclass\" part) segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

atlas Information related to the atlas used

name : brainglobe-atlasapi atlas name type : \"brain\" or \"cord\" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps. midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates. outline_structures : structures to show an outline of in heatmaps

channels Information related to imaging channels

names Must contain all classifications derived from \"object_type\" you want to process. In the form subclassification name = name to display on the plots

\"marker+\" : classification name = name to display \"marker-\" : add any number of sub-classification

colors Must have same keys as \"names\" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

\"marker+\" : classification name = matplotlib color \"marker-\" : must have the same entries as \"names\".

hemispheres Information related to hemispheres, same structure as channels

names

Left : Left = name to display Right : Right = name to display

colors Must have same keys as names' keys

Left : ff516e\" # Left = matplotlib color (either #hex, color name or RGB list) Right : 960010\" # Right = matplotlib color

distributions Spatial distributions parameters

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3) ap_lim : bins limits for anterio-posterior in mm ap_nbins : number of bins for anterio-posterior dv_lim : bins limits for dorso-ventral in mm dv_nbins : number of bins for dorso-ventral ml_lim : bins limits for medio-lateral in mm ml_nbins : number of bins for medio-lateral hue : color curves with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

display Display parameters

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up cmap : matplotlib color map for 2D heatmaps cmap_nbins : number of bins for 2D heatmaps cmap_lim : color limits for 2D heatmaps

regions Distributions per regions parameters

base_measurement : the name of the measurement in QuPath to derive others from. Usually \"Count\" or \"Length \u00b5m\" hue : color bars with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter=\"both\", plots the two hemisphere in mirror. normalize_starter_cells : normalize non-relative metrics by the number of starter cells

metrics Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

\"density \u00b5m^-2\" : relevant name \"density mm^-2\" : relevant name \"coverage index\" : relevant name \"relative measurement\" : relevant name \"relative density\" : relevant name

display

nregions : number of regions to display (sorted by max.) orientation : orientation of the bars (\"h\" or \"v\") order : order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order dodge : enforce the bar not being stacked log_scale : use log. scale for metrics

metrics name of metrics to display

\"count\" : real_name = display_name, with real_name the \"values\" in [regions.metrics] \"density mm^-2\"

files Full path to information TOML files and atlas outlines for 2D heatmaps.

blacklist fusion outlines infos

"},{"location":"main-configuration-files.html#infotoml","title":"info.toml","text":"Click to see an example file info_template.toml
# TOML file to specify experimental settings of each animals.\n# Syntax should be :\n#   [animalid0]  # animal ID\n#   slice_thickness = 30  # slice thickness in microns\n#   slice_spacing = 60  # spacing between two slices in microns\n#   [animalid0.marker-name]  # [{Animal id}.{segmented channel name}]\n#   starter_cells = 190  # number of starter cells\n#   injection_site = [x, y, z]  # approx. injection site in CCFv3 coordinates\n#\n# --------------------------------------------------------------------------\n[animalid0]\nslice_thickness = 30\nslice_spacing = 60\n[animalid0.\"marker+\"]\nstarter_cells = 150\ninjection_site = [ 10.8937328, 6.18522070, 6.841855301 ]\n[animalid0.\"marker-\"]\nstarter_cells = 175\ninjection_site = [ 10.7498512, 6.21545461, 6.815487203 ]\n# --------------------------------------------------------------------------\n[animalid1-SC]\nslice_thickness = 30\nslice_spacing = 120\n[animalid1-SC.EGFP]\nstarter_cells = 250\ninjection_site = [ 10.9468211, 6.3479642, 6.0061113 ]\n[animalid1-SC.DsRed]\nstarter_cells = 275\ninjection_site = [ 10.9154874, 6.2954872, 8.1587125 ]\n# --------------------------------------------------------------------------\n

This file is used to specify injection sites for each animal and each channel, to display it in distributions.

"},{"location":"main-getting-help.html","title":"Getting help","text":"

For help in QuPath, ABBA, Fiji or any image processing-related questions, your one stop is the image.sc forum. There, you can search with specific tags (#qupath, #abba, ...). You can also ask questions or even answer to some by creating an account !

For help with cuisto in particular, you can open an issue in Github (which requires an account as well), or send an email to me or Antoine Lesage.

"},{"location":"main-getting-started.html","title":"Getting started","text":""},{"location":"main-getting-started.html#quick-start","title":"Quick start","text":"
  1. Install QuPath, ABBA and conda.
  2. Create an environment :
    conda create -c conda-forge -n cuisto-env python=3.12\n
  3. Activate it :
    conda activate cuisto-env\n
  4. Download the latest release .zip, unzip it and install it with pip, from inside the cuisto-xxx folder :
    pip install .\n
    If you want to build the doc :
    pip install .[doc]\n
"},{"location":"main-getting-started.html#slow-start","title":"Slow start","text":"

Tip

If all goes well, you shouldn't need any admin rights to install the various pieces of software used before cuisto.

Important

Remember to cite all softwares you use ! See Citing.

"},{"location":"main-getting-started.html#qupath","title":"QuPath","text":"

QuPath is an \"open source software for bioimage analysis\". You can install it from the official website : https://qupath.github.io/. The documentation is quite clear and comprehensive : https://qupath.readthedocs.io/en/stable/index.html.

This is where you'll create QuPath projects, in which you'll be able to browse your images, annotate them, import registered brain regions and find objects of interests (via automatic segmentation, thresholding, pixel classification, ...). Then, those annotations and detections can be exported to be processed by cuisto.

"},{"location":"main-getting-started.html#aligning-big-brain-and-atlases-abba","title":"Aligning Big Brain and Atlases (ABBA)","text":"

This is the tool you'll use to register 2D histological sections to 3D atlases. See the dedicated page.

"},{"location":"main-getting-started.html#python-virtual-environment-manager-conda","title":"Python virtual environment manager (conda)","text":"

The cuisto package is written in Python. It depends on scientific libraries (such as NumPy, pandas and many more). Those libraries need to be installed in versions that are compatible with each other and with cuisto. To make sure those versions do not conflict with other Python tools you might be using (deeplabcut, abba_python, ...), we will install cuisto and its dependencies in a dedicated virtual environment.

conda is a software that takes care of this. It comes with a \"base\" environment, from which we will create and manage other, project-specific environments. It is also used to download and install python in each of those environments, as well as third-party libraries. conda in itself is free and open-source and can be used freely by anyone.

It is included with the Anaconda distribution, which is subject to specific terms of service, which state that unless you're an individual, a member of a company with less than 200 employees or a member of an university (but not a national research lab) it's free to use, otherwise, you need to pay a licence. conda, while being free, is by default configured to use the \"defaults\" channel to fetch the packages (including Python itself), a repository operated by Anaconda, which is, itself, subject to the Anaconda terms of service.

In contrast, conda-forge is a community-run repository that contains more numerous and more update-to-date packages. This is free to use for anyone. The idea is to use conda directly (instead of Anaconda graphical interface) and download packages from conda-forge (instead of the Anaconda-run defaults). To try to decipher this mess, Anaconda provides this figure :

Furthermore, the \"base\" conda environment installed with the Anaconda distribution is bloated and already contains tons of libraries, and tends to self-destruct at some point (eg. becomes unable to resolve the inter-dependencies), which makes you unable to install new libraries nor create new environments.

This is why it is highly recommended to install Miniconda instead, a minimal installer for conda, and configure it to use the free, community-run channel conda-forge, or, even better, use Miniforge which is basically the same but pre-configured to use conda-forge. The only downside is that will not get the Anaonda graphical user interface and you'll need to use the terminal instead, but worry not ! We got you covered.

  1. Download and install Miniforge (choose the latest release for your system). During the installation, choose to install for the current user, add conda to PATH and make python the default interpreter.
  2. Open a terminal (PowerShell in Windows). Run :
    conda init\n
    This will activate conda and its base environment whenever you open a new PowerShell window. Now, when opening a new PowerShell (or terminal), you should see a prompt like this :
    (base) PS C:\\Users\\myname>\n

Tip

If Anaconda is already installed and you don't have the rights to uninstall it, you'll have to use it instead. You can launch the \"Anaconda Prompt (PowerShell)\", run conda init. Open a regular PowerShell window and run conda config --add channels conda-forge, so that subsequent installations and environments creation will fetch required dependencies from conda-forge.

"},{"location":"main-getting-started.html#installation","title":"Installation","text":"

This section explains how to actually install the cuisto package. The following commands should be run from a terminal (PowerShell). Remember that the -c conda-forge bits are not necessary if you installed conda with the miniforge distribution.

  1. Create a virtual environment with python 3.12 :
    conda create -c conda-forge -n cuisto-env python=3.12\n
  2. Get a copy of the cuisto Source code .zip package, from the Releases page.
  3. We need to install it inside the cuisto-env environment we just created. First, you need to activate the cuisto-env environment :
    conda activate cuisto-env\n
    Now, the prompt should look like this :
    (cuisto-env) PS C:\\Users\\myname>\n
    This means that Python packages will now be installed in the cuisto-env environment and won't conflict with other toolboxes you might be using. Then, we use pip to install cuisto. pip was installed with Python, and will scan the cuisto folder, specifically the \"pyproject.toml\" file that lists all the required dependencies. To do so, you can either :
    • pip install /path/to/cuisto\n
    • Change directory from the terminal :
      cd /path/to/cuisto\n
      Then install the package, \".\" denotes \"here\" :
      pip install .\n
    • Use the file explorer to get to the cuisto folder, use Shift+Right Button to \"Open PowerShell window here\" and run :
      pip install .\n

cuisto is now installed inside the cuisto-env environment and will be available in Python from that environment !

Tip

You will need to perform step 3. each time you want to update the package.

If you already have registered data and cells in QuPath, you can export Annotations and Detections as TSV files and head to the Example section.

"},{"location":"main-using-notebooks.html","title":"Using notebooks","text":"

A Jupyter notebook is a way to use Python in an interactive manner. It uses cells that contain Python code, and that are to be executed to immediately see the output, including figures.

You can see some rendered notebooks in the examples here, but you can also download them (downward arrow button on the top right corner of each notebook) and run them locally with your own data.

To do so, you can either use an integrated development environment (basically a supercharged text editor) that supports Jupyter notebooks, or directly the Jupyter web interface.

IDEJupyter web interface

You can use for instance Visual Studio Code, also known as vscode.

  1. Download it and install it.
  2. Launch vscode.
  3. Follow or skip tutorials.
  4. In the left panel, open Extension (squared pieces).
  5. Install the \"Python\" and \"Jupyter\" extensions (by Microsoft).
  6. You now should be able to open .ipynb (notebooks) files with vscode. On the top right, you should be able to Select kernel : choose \"cuisto-env\".
  1. Create a folder dedicated to working with notebooks, for example \"Documents\\notebooks\".
  2. Copy the notebooks you're interested in in this folder.
  3. Open a terminal inside this folder (by either using cd Documents\\notebooks or, in the file explorer in your \"notebooks\" folder, Shift+Right Button to \"Open PowerShell window here\")
  4. Activate the conda environment :
    conda activate cuisto-env\n
  5. Launch the Jupyter Lab web interface :
    jupyter lab\n
    This should open a web page where you can open the ipynb files.
"},{"location":"tips-abba.html","title":"ABBA","text":""},{"location":"tips-brain-contours.html","title":"Brain contours","text":"

With cuisto, it is possible to plot 2D heatmaps on brain contours.

All the detections are projected in a single plane, thus it is up to you to select a relevant data range. It is primarily intended to give a quick, qualitative overview of the spreading of your data.

To do so, it requires the brain regions outlines, stored in a hdf5 file. This can be generated with brainglobe-atlasapi. The generate_atlas_outlines.py located in scripts/atlas will show you how to make such a file, that the cuisto.display module can use.

Alternatively it is possible to directly plot density maps without cuisto, using brainglobe-heatmap. An example is shown here.

"},{"location":"tips-formats.html","title":"Data format","text":""},{"location":"tips-formats.html#some-concepts","title":"Some concepts","text":""},{"location":"tips-formats.html#tiles","title":"Tiles","text":"

The representation of an image in a computer is basically a table where each element represents the pixel value (see more here). It can be n-dimensional, where the typical dimensions would be \\((x, y, z)\\), time and the fluorescence channels.

In large images, such as histological slices that are more than 10000\\(\\times\\)10000 pixels, a strategy called tiling is used to optimize access to specific regions in the image. Storing the whole image at once in a file would imply to load the whole thing at once in the memory (RAM), even though one would only need to access a given rectangular region with a given zoom. Instead, the image is stored as tiles, small squares (512--2048 pixels) that pave the whole image and are used to reconstruct the original image. Therefore, when zooming-in, only the relevant tiles are loaded and displayed, allowing for smooth large image navigation. This process is done seamlessly by software like QuPath and BigDataViewer (the Fiji plugin ABBA is based on) when loading tiled images. This is also leveraged for image processing in QuPath, which will work on tiles instead of the whole image to not saturate your computer RAM.

Most images are already tiled, including Zeiss CZI images. Note that those tiles do not necessarily correspond to the actual, real-world, tiles the microscope did to image the whole slide.

"},{"location":"tips-formats.html#pyramids","title":"Pyramids","text":"

In the same spirit as tiles, it would be a waste to have to load the entire image (and all the tiles) at once when viewing the image at max zoom-out, as your monitor nor your eyes would handle it. Instead, smaller, rescaled versions of the original image are stored alongside it, and depending on the zoom you are using, the sub-resolution version is displayed. Again, this is done seamlessly by QuPath and ABBA, allowing you to quickly switch from an image to another, without having to load the GB-sized image. Also, for image processing that does not require the original pixel size, QuPath can also leverage pyramids to go faster.

Usually, upon openning a CZI file in ZEN, there is a pop-up suggesting you to generate pyramids. It is a very good idea to say yes, wait a bit and save the file so that the pyramidal levels are saved within the file.

"},{"location":"tips-formats.html#metadata","title":"Metadata","text":"

Metadata, while often overlooked, are of paramount importance in microscopy data. It allows both softwares and users to interpret the raw data of images, eg. the values of each pixels. Most image file formats support this, including the microcope manufacturer file formats. Metadata may include :

  • Pixel size. Usually expressed in \u00b5m for microscopy, this maps computer pixel units into real world distance. QuPath and ABBA uses that calibration to scale your image properly, so that it match the atlas you'll register your slices on,
  • Channels colors and names,
  • Image type (fluorescence, brightfield, ...),
  • Dimensions,
  • Magnification...

Pixel size is the parameter that is absolutely necessary. Channel names and colors are more a quality of life feature, to make sure not to mix your difference fluorescence channels. CZI files or exported OME-TIFF files include this out of the box so you don't really need to pay attention.

"},{"location":"tips-formats.html#bio-formats","title":"Bio-formats","text":"

Bio-formats is an initiative of the Open Microscopy Environment (OME) consortium, aiming at being able to read proprietary microscopy image data and metadata. It is used in QuPath, Fiji and ABBA.

This page summarizes the level of support of numerous file formats. You can see that Zeiss CZI files and Leica LIF are quite well supported, and should therefore work out of the box in QuPath.

"},{"location":"tips-formats.html#zeiss-czi-files","title":"Zeiss CZI files","text":"

QuPath and ABBA supports any Bio-formats supported, tiled, pyramidal images.

If you're in luck, adding the pyramidal CZI file to your QuPath project will just work. If it doesn't, you'll notice immediately : the tiles will be shuffled and you'll see only a part of the image instead of the whole one. Unfortunately I was not able to determine why this happens and did not find a way to even predict if a file will or will not work.

In the event you experience this bug, you'll need to export the CZI files to OME-TIFF files from ZEN, then generate tiled pyramidal images with the pyramid-creator package that you can find here.

"},{"location":"tips-formats.html#markdown-md-files","title":"Markdown (.md) files","text":"

Markdown is a markup language to create formatted text. It is basically a simple text file that could be opened with any text editor software (notepad and the like), but features specific tags to format the text with heading levels, typesetting (bold, itallic), links, lists... This very page is actually written in markdown, and the engine that builds it renders the text in a nicely formatted manner.

If you open a .md file with vscode for example, you'll get a magnigying glass on the top right corner to switch to the rendered version of the file.

"},{"location":"tips-formats.html#toml-toml-files","title":"TOML (.toml) files","text":"

TOML, or Tom's Obvious Minimal Language, is a configuration file format (similar to YAML). Again, it is basically a simple text file that can be opened with any text editor and is human-readable, but also computer-readable. This means that it is easy for most software and programming language to parse the file to associate a variable (or \"key\") to a value, thus making it a good file format for configuration. It is used in cuisto (see The configuration files page).

The syntax looks like this :

# a comment, ignored by the computer\nkey1 = 10  # the key \"key1\" is mapped to the number 10\nkey2 = \"something\"  # \"key2\" is mapped to the string \"something\"\nkey3 = [\"something else\", 1.10, -25]  # \"key3\" is mapped to a list with 3 elements\n[section]  # we can declare sections\nkey1 = 5  # this is not \"key1\", it actually is section.key1\n[section.example]  # we can have nested sections\nkey1 = true  # this is section.example.key1, mapped to the boolean True\n

You can check the full specification of this language here.

"},{"location":"tips-formats.html#csv-csv-tsv-files","title":"CSV (.csv, .tsv) files","text":"

CSV (or TSV) stands for Comma-Separated Values (or Tab-Separated Values) and is, once again, a simple text file formatted in a way that allows LibreOffice Calc (or Excel) to open them as a table. Lines of the table are delimited with new lines, and columns are separated with commas (,) or tabulations. Those files are easily parsed by programming languages (including Python). QuPath can export annotations and detections measurements in TSV format.

"},{"location":"tips-formats.html#json-and-geojson-files","title":"JSON and GeoJSON files","text":"

JSON is a \"data-interchange format\". It is used to store data, very much like toml, but supports more complex data and is more efficient to read and write, but is less human-readable. It is used in cuisto to store fibers-like objects coordinates, as they can contain several millions of points (making CSV not usable).

GeoJson is a file format used to store geographic data structures, basically objects coordinates with various shapes. It is based on and compatible with JSON, which makes it easy to parse in numerous programming language. It used in QuPath to import and export objects, that can be point, line, polygons...

"},{"location":"tips-qupath.html","title":"QuPath","text":""},{"location":"tips-qupath.html#custom-scripts","title":"Custom scripts","text":"

While QuPath graphical user interface (GUI) should meet a lot of your needs, it is very convenient to use scripting to automate certain tasks, execute them in batch (on all your images) and do things you couldn't do otherwise. QuPath uses the Groovy programming language, which is mostly Java.

Warning

Not all commands will appear in the history.

In QuPath, in the left panel in the \"Workflow\" tab, there is an history of most of the commands you used during the session. On the bottom, you can click on Create workflow to select the relevant commands and create a script. This will open the built-in script editor that will contain the groovy version of what you did graphically.

Tip

The scripts/qupath-utils folder contains a bunch of utility scripts.

They can be run in batch with the three-dotted menu on the bottom right corner of the script editor : Run for project, then choose the images you want the script to run on.

"},{"location":"demo_notebooks/cells_distributions.html","title":"Cells distributions","text":"

This notebook shows how to load data exported from QuPath, compute metrics and display them, according to the configuration file. This is meant for a single-animal.

There are some conventions that need to be met in the QuPath project so that the measurements are usable with cuisto:

  • Objects' classifications must be derived, eg. be in the form \"something: else\". The primary classification (\"something\") will be refered to \"object_type\" and the secondary classification (\"else\") to \"channel\" in the configuration file.
  • Only one \"object_type\" can be processed at once, but supports any numbers of channels.
  • Annotations (brain regions) must have properly formatted measurements. For punctual objects, it would be the count. Run the \"add_regions_count.groovy\" script to add them. The measurements names must be in the form \"something: else name\", for instance, \"something: else Count\". \"name\" is refered to \"base_measurement\" in the configuration file.

You should copy this notebook, the configuration file and the atlas-related configuration files (blacklist and fusion) elsewhere and edit them according to your need.

The data was generated from QuPath with stardist cell detection on toy data.

In\u00a0[1]: Copied!
import pandas as pd\n\nimport cuisto\n
import pandas as pd import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_cells.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_cells.toml\" In\u00a0[3]: Copied!
# - Files\n# animal identifier\nanimal = \"animalid0\"\n# set the full path to the annotations tsv file from QuPath\nannotations_file = \"../../resources/cells_measurements_annotations.tsv\"\n# set the full path to the detections tsv file from QuPath\ndetections_file = \"../../resources/cells_measurements_detections.tsv\"\n
# - Files # animal identifier animal = \"animalid0\" # set the full path to the annotations tsv file from QuPath annotations_file = \"../../resources/cells_measurements_annotations.tsv\" # set the full path to the detections tsv file from QuPath detections_file = \"../../resources/cells_measurements_detections.tsv\" In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.config.Config(config_file)\n
# get configuration cfg = cuisto.config.Config(config_file) In\u00a0[5]: Copied!
# read data\ndf_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\ndf_detections = pd.read_csv(detections_file, index_col=\"Object ID\", sep=\"\\t\")\n\n# remove annotations that are not brain regions\ndf_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\ndf_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n\n# convert atlas coordinates from mm to microns\ndf_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[\n    [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]\n].multiply(1000)\n\n# have a look\ndisplay(df_annotations.head())\ndisplay(df_detections.head())\n
# read data df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\") df_detections = pd.read_csv(detections_file, index_col=\"Object ID\", sep=\"\\t\") # remove annotations that are not brain regions df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"] df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"] # convert atlas coordinates from mm to microns df_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[ [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"] ].multiply(1000) # have a look display(df_annotations.head()) display(df_detections.head()) Image Object type Name Classification Parent ROI Centroid X \u00b5m Centroid Y \u00b5m Cells: marker+ Count Cells: marker- Count ID Side Parent ID Num Detections Num Cells: marker+ Num Cells: marker- Area \u00b5m^2 Perimeter \u00b5m Object ID 4781ed63-0d8e-422e-aead-b685fbe20eb5 animalid0_030.ome.tiff Annotation Root NaN Root object (Image) Geometry 5372.5 3922.1 0 0 NaN NaN NaN 2441 136 2305 31666431.6 37111.9 aa4b133d-13f9-42d9-8c21-45f143b41a85 animalid0_030.ome.tiff Annotation root Right: root Root Polygon 7094.9 4085.7 0 0 997 0.0 NaN 1284 41 1243 15882755.9 18819.5 42c3b914-91c5-4b65-a603-3f9431717d48 animalid0_030.ome.tiff Annotation grey Right: grey root Geometry 7256.8 4290.6 0 0 8 0.0 997.0 1009 24 985 12026268.7 49600.3 887af3eb-4061-4f8a-aa4c-fe9b81184061 animalid0_030.ome.tiff Annotation CB Right: CB grey Geometry 7778.7 3679.2 0 16 512 0.0 8.0 542 5 537 6943579.0 30600.2 adaabc05-36d1-4aad-91fe-2e904adc574f animalid0_030.ome.tiff Annotation CBN Right: CBN CB Geometry 6790.5 3567.9 0 0 519 0.0 512.0 55 1 54 864212.3 7147.4 Image Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z Object ID 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11523.0 4272.4 4276.7 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11520.2 4278.4 4418.6 481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11506.0 4317.2 4356.3 fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11528.4 4257.4 4336.4 3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11548.7 4203.3 4294.3 In\u00a0[6]: Copied!
# get distributions per regions, spatial distributions and coordinates\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n    animal, df_annotations, df_detections, cfg, compute_distributions=True\n)\n\n# have a look\ndisplay(df_regions.head())\ndisplay(df_coordinates.head())\n
# get distributions per regions, spatial distributions and coordinates df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal( animal, df_annotations, df_detections, cfg, compute_distributions=True ) # have a look display(df_regions.head()) display(df_coordinates.head()) Name hemisphere Area \u00b5m^2 Area mm^2 count density \u00b5m^-2 density mm^-2 coverage index relative count relative density channel animal 0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 0.00012 0.002132 0.205275 Positive animalid0 0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 0.00012 0.000189 0.020671 Negative animalid0 1 ACVII Right 7061.4 0.007061 0 0.0 0.0 0.0 0.0 0.0 Positive animalid0 1 ACVII Right 7061.4 0.007061 1 0.000142 141.614977 0.000142 0.000144 0.021646 Negative animalid0 2 ACVII both 15368.5 0.015369 1 0.000065 65.068159 0.000065 0.001362 0.153797 Positive animalid0 Image Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z hemisphere channel Atlas_AP Atlas_DV Atlas_ML animal Object ID 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5230 4.2724 4.2767 Right Negative -6.433716 3.098278 -1.4233 animalid0 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5202 4.2784 4.4186 Right Negative -6.431449 3.104147 -1.2814 animalid0 481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5060 4.3172 4.3563 Right Negative -6.420685 3.141780 -1.3437 animalid0 fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5284 4.2574 4.3364 Right Negative -6.437788 3.083737 -1.3636 animalid0 3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5487 4.2033 4.2943 Right Negative -6.453296 3.031224 -1.4057 animalid0 In\u00a0[7]: Copied!
# plot distributions per regions\nfigs_regions = cuisto.display.plot_regions(df_regions, cfg)\n# specify which regions to plot\n# figs_regions = cuisto.display.plot_regions(df_regions, cfg, names_list=[\"GRN\", \"IRN\", \"MDRNv\"])\n\n# save as svg\n# figs_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_count.svg\")\n# figs_regions[1].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_density.svg\")\n
# plot distributions per regions figs_regions = cuisto.display.plot_regions(df_regions, cfg) # specify which regions to plot # figs_regions = cuisto.display.plot_regions(df_regions, cfg, names_list=[\"GRN\", \"IRN\", \"MDRNv\"]) # save as svg # figs_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_count.svg\") # figs_regions[1].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_density.svg\") In\u00a0[8]: Copied!
# plot 1D distributions\nfig_distrib = cuisto.display.plot_1D_distributions(\n    dfs_distributions, cfg, df_coordinates=df_coordinates\n)\n
# plot 1D distributions fig_distrib = cuisto.display.plot_1D_distributions( dfs_distributions, cfg, df_coordinates=df_coordinates )

If there were several animal in the measurement file, it would be displayed as mean +/- sem instead.

In\u00a0[9]: Copied!
# plot heatmap (all types of cells pooled)\nfig_heatmap = cuisto.display.plot_2D_distributions(df_coordinates, cfg)\n
# plot heatmap (all types of cells pooled) fig_heatmap = cuisto.display.plot_2D_distributions(df_coordinates, cfg)"},{"location":"demo_notebooks/density_map.html","title":"Density map","text":"

Draw 2D heatmaps as density isolines.

This notebook does not actually use histoquant and relies only on brainglobe-heatmap to extract brain structures outlines.

Only the detections measurements with atlas coordinates exported from QuPath are used.

You need to select the range of data to be used, the regions outlines will be extracted at the centroid of that range. Therefore, a range that is too large will be misleading and irrelevant.

In\u00a0[1]: Copied!
import brainglobe_heatmap as bgh\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n
import brainglobe_heatmap as bgh import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as sns In\u00a0[2]: Copied!
# path to the exported measurements from QuPath\nfilename = \"../../resources/cells_measurements_detections.tsv\"\n
# path to the exported measurements from QuPath filename = \"../../resources/cells_measurements_detections.tsv\"

Settings

In\u00a0[3]: Copied!
# atlas to use\natlas_name = \"allen_mouse_10um\"\n# brain regions whose outlines will be plotted\nregions = [\"root\", \"CB\", \"MY\", \"GRN\", \"IRN\"]\n# range to include, in Allen coordinates, in microns\nap_lims = [9800, 10000]  # lims : [0, 13200] for coronal\nml_lims = [5600, 5800]  # lims : [0, 11400] for sagittal\ndv_lims = [3900, 4100]  # lims : [0, 8000] for top\n# number of isolines\nnlevels = 5\n# color mapping between classification and matplotlib color\npalette = {\"Cells: marker-\": \"#d8782f\", \"Cells: marker+\": \"#8ccb73\"}\n
# atlas to use atlas_name = \"allen_mouse_10um\" # brain regions whose outlines will be plotted regions = [\"root\", \"CB\", \"MY\", \"GRN\", \"IRN\"] # range to include, in Allen coordinates, in microns ap_lims = [9800, 10000] # lims : [0, 13200] for coronal ml_lims = [5600, 5800] # lims : [0, 11400] for sagittal dv_lims = [3900, 4100] # lims : [0, 8000] for top # number of isolines nlevels = 5 # color mapping between classification and matplotlib color palette = {\"Cells: marker-\": \"#d8782f\", \"Cells: marker+\": \"#8ccb73\"} In\u00a0[4]: Copied!
df = pd.read_csv(filename, sep=\"\\t\")\ndisplay(df.head())\n
df = pd.read_csv(filename, sep=\"\\t\") display(df.head())
 Image Object ID Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z 0 animalid0_030.ome.tiff 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 Detection NaN Cells: marker- VeCB Polygon 11.5230 4.2724 4.2767 1 animalid0_030.ome.tiff 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 Detection NaN Cells: marker- VeCB Polygon 11.5202 4.2784 4.4186 2 animalid0_030.ome.tiff 481a519b-8b40-4450-9ec6-725181807d72 Detection NaN Cells: marker- VeCB Polygon 11.5060 4.3172 4.3563 3 animalid0_030.ome.tiff fd28e09c-2c64-4750-b026-cd99e3526a57 Detection NaN Cells: marker- VeCB Polygon 11.5284 4.2574 4.3364 4 animalid0_030.ome.tiff 3d9ce034-f2ed-4c73-99be-f782363cf323 Detection NaN Cells: marker- VeCB Polygon 11.5487 4.2033 4.2943 

Here we can filter out classifications we don't wan't to display.

In\u00a0[5]: Copied!
# select objects\n# df = df[df[\"Classification\"] == \"example: classification\"]\n
# select objects # df = df[df[\"Classification\"] == \"example: classification\"] In\u00a0[6]: Copied!
# get outline coordinates in coronal (=frontal) orientation\ncoords_coronal = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"frontal\",\n    atlas_name=atlas_name,\n    position=(np.mean(ap_lims), 0, 0),\n)\n# get outline coordinates in sagittal orientation\ncoords_sagittal = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"sagittal\",\n    atlas_name=atlas_name,\n    position=(0, 0, np.mean(ml_lims)),\n)\n# get outline coordinates in top (=horizontal) orientation\ncoords_top = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"horizontal\",\n    atlas_name=atlas_name,\n    position=(0, np.mean(dv_lims), 0),\n)\n
# get outline coordinates in coronal (=frontal) orientation coords_coronal = bgh.get_structures_slice_coords( regions, orientation=\"frontal\", atlas_name=atlas_name, position=(np.mean(ap_lims), 0, 0), ) # get outline coordinates in sagittal orientation coords_sagittal = bgh.get_structures_slice_coords( regions, orientation=\"sagittal\", atlas_name=atlas_name, position=(0, 0, np.mean(ml_lims)), ) # get outline coordinates in top (=horizontal) orientation coords_top = bgh.get_structures_slice_coords( regions, orientation=\"horizontal\", atlas_name=atlas_name, position=(0, np.mean(dv_lims), 0), ) In\u00a0[7]: Copied!
# Coronal projection\n# select objects within the rostro-caudal range\ndf_coronal = df[\n    (df[\"Atlas_X\"] >= ap_lims[0] / 1000) & (df[\"Atlas_X\"] <= ap_lims[1] / 1000)\n]\n\nplt.figure()\n\nfor struct_name, contours in coords_coronal.items():\n    for cont in contours:\n        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_coronal,\n    x=\"Atlas_Z\",\n    y=\"Atlas_Y\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([2, 3], [8, 8], \"k\", linewidth=3)\nplt.text(2, 7.9, \"1 mm\")\n
# Coronal projection # select objects within the rostro-caudal range df_coronal = df[ (df[\"Atlas_X\"] >= ap_lims[0] / 1000) & (df[\"Atlas_X\"] <= ap_lims[1] / 1000) ] plt.figure() for struct_name, contours in coords_coronal.items(): for cont in contours: plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_coronal, x=\"Atlas_Z\", y=\"Atlas_Y\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([2, 3], [8, 8], \"k\", linewidth=3) plt.text(2, 7.9, \"1 mm\")
 Out[7]: 
Text(2, 7.9, '1 mm')
 In\u00a0[8]: Copied! 
# Sagittal projection\n# select objects within the medio-lateral range\ndf_sagittal = df[\n    (df[\"Atlas_Z\"] >= ml_lims[0] / 1000) & (df[\"Atlas_Z\"] <= ml_lims[1] / 1000)\n]\n\nplt.figure()\n\nfor struct_name, contours in coords_sagittal.items():\n    for cont in contours:\n        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_sagittal,\n    x=\"Atlas_X\",\n    y=\"Atlas_Y\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([2, 3], [7.1, 7.1], \"k\", linewidth=3)\nplt.text(2, 7, \"1 mm\")\n
# Sagittal projection # select objects within the medio-lateral range df_sagittal = df[ (df[\"Atlas_Z\"] >= ml_lims[0] / 1000) & (df[\"Atlas_Z\"] <= ml_lims[1] / 1000) ] plt.figure() for struct_name, contours in coords_sagittal.items(): for cont in contours: plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_sagittal, x=\"Atlas_X\", y=\"Atlas_Y\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([2, 3], [7.1, 7.1], \"k\", linewidth=3) plt.text(2, 7, \"1 mm\")
 Out[8]: 
Text(2, 7, '1 mm')
 In\u00a0[9]: Copied! 
# Top projection\n# select objects within the dorso-ventral range\ndf_top = df[(df[\"Atlas_Y\"] >= dv_lims[0] / 1000) & (df[\"Atlas_Y\"] <= dv_lims[1] / 1000)]\n\nplt.figure()\n\nfor struct_name, contours in coords_top.items():\n    for cont in contours:\n        plt.fill(-cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_top,\n    x=\"Atlas_Z\",\n    y=\"Atlas_X\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([0.5, 1.5], [0.5, 0.5], \"k\", linewidth=3)\nplt.text(0.5, 0.4, \"1 mm\")\n
# Top projection # select objects within the dorso-ventral range df_top = df[(df[\"Atlas_Y\"] >= dv_lims[0] / 1000) & (df[\"Atlas_Y\"] <= dv_lims[1] / 1000)] plt.figure() for struct_name, contours in coords_top.items(): for cont in contours: plt.fill(-cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_top, x=\"Atlas_Z\", y=\"Atlas_X\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([0.5, 1.5], [0.5, 0.5], \"k\", linewidth=3) plt.text(0.5, 0.4, \"1 mm\")
 Out[9]: 
Text(0.5, 0.4, '1 mm')
 In\u00a0[\u00a0]: Copied! 
\n
"},{"location":"demo_notebooks/fibers_coverage.html","title":"Fibers coverage","text":"

Plot regions coverage percentage in the spinal cord.

This showcases that any brainglobe atlases should be supported.

Here we're going to quantify the percentage of area of each spinal cord regions innervated by axons.

The \"area \u00b5m^2\" measurement for each annotations can be created in QuPath with a pixel classifier, using the Measure button.

We're going to consider that the \"area \u00b5m^2\" measurement generated by the pixel classifier is an object count. histoquant computes a density, which is the count in each region divided by its aera. Therefore, in this case, it will be actually the fraction of area covered by fibers in a given color.

The data was generated using QuPath with a pixel classifier on toy data.

In\u00a0[1]: Copied!
import pandas as pd\n\nimport cuisto\n
import pandas as pd import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_fibers.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_fibers.toml\" In\u00a0[3]: Copied!
# - Files\n# not important if only one animal\nanimal = \"animalid1-SC\"\n# set the full path to the annotations tsv file from QuPath\nannotations_file = \"../../resources/fibers_measurements_annotations.tsv\"\n
# - Files # not important if only one animal animal = \"animalid1-SC\" # set the full path to the annotations tsv file from QuPath annotations_file = \"../../resources/fibers_measurements_annotations.tsv\" In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.config.Config(config_file)\n
# get configuration cfg = cuisto.config.Config(config_file) In\u00a0[5]: Copied!
# read data\ndf_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\ndf_detections = pd.DataFrame()  # empty DataFrame\n\n# remove annotations that are not brain regions\ndf_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\ndf_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n\n# have a look\ndisplay(df_annotations.head())\n
# read data df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\") df_detections = pd.DataFrame() # empty DataFrame # remove annotations that are not brain regions df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"] df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"] # have a look display(df_annotations.head()) Image Object type Name Classification Parent ROI Centroid X \u00b5m Centroid Y \u00b5m Fibers: EGFP area \u00b5m^2 Fibers: DsRed area \u00b5m^2 ID Side Parent ID Area \u00b5m^2 Perimeter \u00b5m Object ID dcfe5196-4e8d-4126-b255-a9ea393c383a animalid1-SC_s1.ome.tiff Annotation Root NaN Root object (Image) Geometry 1353.70 1060.00 108993.1953 15533.3701 NaN NaN NaN 3172474.0 9853.3 acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 animalid1-SC_s1.ome.tiff Annotation root Right: root Root Polygon 864.44 989.95 39162.8906 5093.2798 250.0 0.0 NaN 1603335.7 4844.2 94571cf9-f22b-453f-860c-eb13d0e72440 animalid1-SC_s1.ome.tiff Annotation WM Right: WM root Geometry 791.00 1094.60 20189.0469 2582.4824 130.0 0.0 250.0 884002.0 7927.8 473d65fb-fda4-4721-ba6f-cc659efc1d5a animalid1-SC_s1.ome.tiff Annotation vf Right: vf WM Polygon 984.31 1599.00 6298.3574 940.4100 70.0 0.0 130.0 281816.9 2719.5 449e2cd1-eca2-4708-83fe-651f378c3a14 animalid1-SC_s1.ome.tiff Annotation df Right: df WM Polygon 1242.90 401.26 1545.0750 241.3800 74.0 0.0 130.0 152952.8 1694.4 In\u00a0[6]: Copied!
# get distributions per regions, spatial distributions and coordinates\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n    animal, df_annotations, df_detections, cfg, compute_distributions=False\n)\n\n# convert the \"density \u00b5m^-2\" column, which is actually the coverage fraction, to a percentage\ndf_regions[\"density \u00b5m^-2\"] = df_regions[\"density \u00b5m^-2\"] * 100\n\n# have a look\ndisplay(df_regions.head())\n
# get distributions per regions, spatial distributions and coordinates df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal( animal, df_annotations, df_detections, cfg, compute_distributions=False ) # convert the \"density \u00b5m^-2\" column, which is actually the coverage fraction, to a percentage df_regions[\"density \u00b5m^-2\"] = df_regions[\"density \u00b5m^-2\"] * 100 # have a look display(df_regions.head()) Name hemisphere Area \u00b5m^2 Area mm^2 area \u00b5m^2 area mm^2 density \u00b5m^-2 density mm^-2 coverage index relative count relative density channel animal 0 10Sp Contra. 1749462.18 1.749462 53117.3701 53.11737 3.036211 30362.113973 1612.755645 0.036535 0.033062 Negative animalid1-SC 0 10Sp Contra. 1749462.18 1.749462 5257.1025 5.257103 0.300498 3004.98208 15.797499 0.030766 0.02085 Positive animalid1-SC 1 10Sp Ipsi. 1439105.93 1.439106 64182.9823 64.182982 4.459921 44599.206328 2862.51007 0.023524 0.023265 Negative animalid1-SC 1 10Sp Ipsi. 1439105.93 1.439106 8046.3375 8.046337 0.559121 5591.205854 44.988729 0.028911 0.022984 Positive animalid1-SC 2 10Sp both 3188568.11 3.188568 117300.3524 117.300352 3.678778 36787.783216 4315.219935 0.028047 0.025734 Negative animalid1-SC In\u00a0[7]: Copied!
# plot distributions per regions\nfig_regions = cuisto.display.plot_regions(df_regions, cfg)\n# specify which regions to plot\n# fig_regions = hq.display.plot_regions(df_regions, cfg, names_list=[\"Rh9\", \"Sr9\", \"8Sp\"])\n\n# save as svg\n# fig_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\nice_figure.svg\")\n
# plot distributions per regions fig_regions = cuisto.display.plot_regions(df_regions, cfg) # specify which regions to plot # fig_regions = hq.display.plot_regions(df_regions, cfg, names_list=[\"Rh9\", \"Sr9\", \"8Sp\"]) # save as svg # fig_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\nice_figure.svg\")"},{"location":"demo_notebooks/fibers_length_multi.html","title":"Fibers length in multi animals","text":"In\u00a0[1]: Copied!
import cuisto\n
import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_multi.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_multi.toml\" In\u00a0[3]: Copied!
# Files\nwdir = \"../../resources/multi\"\nanimals = [\"mouse0\", \"mouse1\"]\n
# Files wdir = \"../../resources/multi\" animals = [\"mouse0\", \"mouse1\"] In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.Config(config_file)\n
# get configuration cfg = cuisto.Config(config_file) In\u00a0[5]: Copied!
# get distributions per regions\ndf_regions, _, _ = cuisto.process.process_animals(\n    wdir, animals, cfg, compute_distributions=False\n)\n\n# have a look\ndisplay(df_regions.head(10))\n
# get distributions per regions df_regions, _, _ = cuisto.process.process_animals( wdir, animals, cfg, compute_distributions=False ) # have a look display(df_regions.head(10))
Processing mouse1: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 2/2 [00:00<00:00, 15.66it/s]\n
Name hemisphere Area \u00b5m^2 Area mm^2 length \u00b5m length mm density \u00b5m^-1 density mm^-1 coverage index relative count relative density channel animal 0 ACVII Contra. 9099.04 0.009099 468.0381 0.468038 0.051438 51438.184688 24.07503 0.00064 0.022168 marker3 mouse0 1 ACVII Contra. 9099.04 0.009099 4260.4844 4.260484 0.468234 468234.495068 1994.905762 0.0019 0.056502 marker2 mouse0 2 ACVII Contra. 9099.04 0.009099 5337.7103 5.33771 0.586623 586623.45698 3131.226069 0.010104 0.242734 marker1 mouse0 3 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker3 mouse0 4 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker2 mouse0 5 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker1 mouse0 6 ACVII both 13708.94 0.013709 468.0381 0.468038 0.034141 34141.086036 15.979329 0.000284 0.011001 marker3 mouse0 7 ACVII both 13708.94 0.013709 4260.4844 4.260484 0.310781 310781.460857 1324.079566 0.000934 0.030688 marker2 mouse0 8 ACVII both 13708.94 0.013709 5337.7103 5.33771 0.38936 389359.811918 2078.289878 0.00534 0.142623 marker1 mouse0 9 AMB Contra. 122463.80 0.122464 30482.7815 30.482782 0.248913 248912.588863 7587.548059 0.041712 0.107271 marker3 mouse0 In\u00a0[6]: Copied!
figs_regions = cuisto.display.plot_regions(df_regions, cfg)\n
figs_regions = cuisto.display.plot_regions(df_regions, cfg)"},{"location":"demo_notebooks/fibers_length_multi.html#fibers-length-in-multi-animals","title":"Fibers length in multi animals\u00b6","text":"

This example uses synthetic data to showcase how histoquant can be used in a pipeline.

Annotations measurements should be exported from QuPath, following the required directory structure.

Alternatively, you can merge all your CSV files yourself, one per animal, adding an animal ID to each table. Those can be processed with the histoquant.process.process_animal() function, in a loop, collecting the results at each iteration and finally concatenating the results. Finally, those can be used with display module. See the API reference for the process module.

"}]} \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..68fcf9b --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"index.html","title":"Introduction","text":"

Info

The documentation is under construction.

cuisto is a Python package aiming at quantifying histological data.

After ABBA registration of 2D histological slices and QuPath objects' detection, cuisto is used to :

  • compute metrics, such as objects density in each brain regions,
  • compute objects distributions in three three axes (rostro-caudal, dorso-ventral and medio-lateral),
  • compute averages and sem across animals,
  • displaying all the above.

This documentation contains cuisto installation instructions, ABBA installation instructions, guides to prepare images for the pipeline, detect objects with QuPath, register 2D slices on a 3D atlas with ABBA, along with examples.

In theory, cuisto should work with any measurements table with the required columns, but has been designed with ABBA and QuPath in mind.

Due to the IT environment of the laboratory, this documentation is very Windows-oriented but most of it should be applicable to Linux and MacOS as well by slightly adapting terminal commands.

"},{"location":"index.html#documentation-navigation","title":"Documentation navigation","text":"

The documentation outline is on the left panel, you can click on items to browse it. In each page, you'll get the table of contents on the right panel.

"},{"location":"index.html#useful-external-resources","title":"Useful external resources","text":"
  • Project repository : https://github.com/TeamNCMC/cuisto
  • QuPath documentation : https://qupath.readthedocs.io/en/stable/
  • Aligning Big Brain and Atlases (ABBA) documentation : https://abba-documentation.readthedocs.io/en/latest/
  • Brainglobe : https://brainglobe.info/
  • BraiAn, a similar but published and way more feature-packed project : https://silvalab.codeberg.page/BraiAn/
  • Image.sc community forum : https://forum.image.sc/
  • Introduction to Bioimage Analysis, an interactive book written by QuPath's creator : https://bioimagebook.github.io/index.html
"},{"location":"index.html#credits","title":"Credits","text":"

cuisto has been primarly developed by Guillaume Le Goc in Julien Bouvier's lab at NeuroPSI. The clever name was found by Aur\u00e9lie Bodeau.

The documentation itself is built with MkDocs using the Material theme.

"},{"location":"api-compute.html","title":"cuisto.compute","text":"

compute module, part of cuisto.

Contains actual computation functions.

"},{"location":"api-compute.html#cuisto.compute.get_distribution","title":"get_distribution(df, col, hue, hue_filter, per_commonnorm, binlim, nbins=100)","text":"

Computes distribution of objects.

A global distribution using only col is computed, then it computes a distribution distinguishing values in the hue column. For the latter, it is possible to use a subset of the data ony, based on another column using hue_filter. This another column is determined with hue, if the latter is \"hemisphere\", then hue_filter is used in the \"channel\" color and vice-versa. per_commonnorm controls how they are normalized, either as a whole (True) or independantly (False).

Use cases : (1) single-channel, two hemispheres : col=x, hue=hemisphere, hue_filter=\"\", per_commonorm=True. Computes a distribution for each hemisphere, the sum of the area of both is equal to 1. (2) three-channels, one hemisphere : col=x, hue=channel, hue_filter=\"Ipsi.\", per_commonnorm=False. Computes a distribution for each channel only for points in the ipsilateral hemisphere. Each curve will have an area of 1.

Parameters:

Name Type Description Default df DataFrame required col str

Key in df, used to compute the distributions.

required hue str

Key in df. Criterion for additional distributions.

required hue_filter str

Further filtering for \"per\" distribution. - hue = channel : value is the name of one of the hemisphere - hue = hemisphere : value can be the name of a channel, a list of such or \"all\"

required per_commonnorm bool

Use common normalization for all hues (per argument).

required binlim list or tuple

First bin left edge and last bin right edge.

required nbins int

Number of bins. Default is 100.

100

Returns:

Name Type Description df_distribution DataFrame

DataFrame with bins, distribution, count and their per-hemisphere or per-channel variants.

Source code in cuisto/compute.py
def get_distribution(\n    df: pd.DataFrame,\n    col: str,\n    hue: str,\n    hue_filter: dict,\n    per_commonnorm: bool,\n    binlim: tuple | list,\n    nbins=100,\n) -> pd.DataFrame:\n    \"\"\"\n    Computes distribution of objects.\n\n    A global distribution using only `col` is computed, then it computes a distribution\n    distinguishing values in the `hue` column. For the latter, it is possible to use a\n    subset of the data ony, based on another column using `hue_filter`. This another\n    column is determined with `hue`, if the latter is \"hemisphere\", then `hue_filter` is\n    used in the \"channel\" color and vice-versa.\n    `per_commonnorm` controls how they are normalized, either as a whole (True) or\n    independantly (False).\n\n    Use cases :\n    (1) single-channel, two hemispheres : `col=x`, `hue=hemisphere`, `hue_filter=\"\"`,\n    `per_commonorm=True`. Computes a distribution for each hemisphere, the sum of the\n    area of both is equal to 1.\n    (2) three-channels, one hemisphere : `col=x`, hue=`channel`,\n    `hue_filter=\"Ipsi.\", per_commonnorm=False`. Computes a distribution for each channel\n    only for points in the ipsilateral hemisphere. Each curve will have an area of 1.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    col : str\n        Key in `df`, used to compute the distributions.\n    hue : str\n        Key in `df`. Criterion for additional distributions.\n    hue_filter : str\n        Further filtering for \"per\" distribution.\n        - hue = channel : value is the name of one of the hemisphere\n        - hue = hemisphere : value can be the name of a channel, a list of such or \"all\"\n    per_commonnorm : bool\n        Use common normalization for all hues (per argument).\n    binlim : list or tuple\n        First bin left edge and last bin right edge.\n    nbins : int, optional\n        Number of bins. Default is 100.\n\n    Returns\n    -------\n    df_distribution : pandas.DataFrame\n        DataFrame with `bins`, `distribution`, `count` and their per-hemisphere or\n        per-channel variants.\n\n    \"\"\"\n\n    # - Preparation\n    bin_edges = np.linspace(*binlim, nbins + 1)  # create bins\n    df_distribution = []  # prepare list of distributions\n\n    # - Both hemispheres, all channels\n    # get raw count per bins (histogram)\n    count, bin_edges = np.histogram(df[col], bin_edges)\n    # get normalized count (pdf)\n    distribution, _ = np.histogram(df[col], bin_edges, density=True)\n    # get bin centers rather than edges to plot them\n    bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2\n\n    # make a DataFrame out of that\n    df_distribution.append(\n        pd.DataFrame(\n            {\n                \"bins\": bin_centers,\n                \"distribution\": distribution,\n                \"count\": count,\n                \"hemisphere\": \"both\",\n                \"channel\": \"all\",\n                \"axis\": col,  # keep track of what col. was used\n            }\n        )\n    )\n\n    # - Per additional criterion\n    # select data\n    df_sub = select_hemisphere_channel(df, hue, hue_filter, False)\n    hue_values = df[hue].unique()  # get grouping values\n    # total number of datapoints in the subset used for additional distribution\n    length_total = len(df_sub)\n\n    for value in hue_values:\n        # select part and coordinates\n        df_part = df_sub.loc[df_sub[hue] == value, col]\n\n        # get raw count per bins (histogram)\n        count, bin_edges = np.histogram(df_part, bin_edges)\n        # get normalized count (pdf)\n        distribution, _ = np.histogram(df_part, bin_edges, density=True)\n\n        if per_commonnorm:\n            # re-normalize so that the sum of areas of all sub-parts is 1\n            length_part = len(df_part)  # number of datapoints in that hemisphere\n            distribution *= length_part / length_total\n\n        # get bin centers rather than edges to plot them\n        bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2\n\n        # make a DataFrame out of that\n        df_distribution.append(\n            pd.DataFrame(\n                {\n                    \"bins\": bin_centers,\n                    \"distribution\": distribution,\n                    \"count\": count,\n                    hue: value,\n                    \"channel\" if hue == \"hemisphere\" else \"hemisphere\": hue_filter,\n                    \"axis\": col,  # keep track of what col. was used\n                }\n            )\n        )\n\n    return pd.concat(df_distribution)\n
"},{"location":"api-compute.html#cuisto.compute.get_regions_metrics","title":"get_regions_metrics(df_annotations, object_type, channel_names, meas_base_name, metrics_names)","text":"

Get a new DataFrame with cumulated axons segments length in each brain regions.

This is the quantification per brain regions for fibers-like objects, eg. axons. The returned DataFrame has columns \"cum. length \u00b5m\", \"cum. length mm\", \"density \u00b5m^-1\", \"density mm^-1\", \"coverage index\".

Parameters:

Name Type Description Default df_annotations DataFrame

DataFrame with an entry for each brain regions, with columns \"Area \u00b5m^2\", \"Name\", \"hemisphere\", and \"{object_type: channel} Length \u00b5m\".

required object_type str

Object type (primary classification).

required channel_names dict

Map between original channel names to something else.

required meas_base_name str required metrics_names dict required

Returns:

Name Type Description df_regions DataFrame

DataFrame with brain regions name, area and metrics.

Source code in cuisto/compute.py
def get_regions_metrics(\n    df_annotations: pd.DataFrame,\n    object_type: str,\n    channel_names: dict,\n    meas_base_name: str,\n    metrics_names: dict,\n) -> pd.DataFrame:\n    \"\"\"\n    Get a new DataFrame with cumulated axons segments length in each brain regions.\n\n    This is the quantification per brain regions for fibers-like objects, eg. axons. The\n    returned DataFrame has columns \"cum. length \u00b5m\", \"cum. length mm\", \"density \u00b5m^-1\",\n    \"density mm^-1\", \"coverage index\".\n\n    Parameters\n    ----------\n    df_annotations : pandas.DataFrame\n        DataFrame with an entry for each brain regions, with columns \"Area \u00b5m^2\",\n        \"Name\", \"hemisphere\", and \"{object_type: channel} Length \u00b5m\".\n    object_type : str\n        Object type (primary classification).\n    channel_names : dict\n        Map between original channel names to something else.\n    meas_base_name : str\n    metrics_names : dict\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        DataFrame with brain regions name, area and metrics.\n\n    \"\"\"\n    # get columns names\n    cols = df_annotations.columns\n    # get columns with fibers lengths\n    cols_colors = cols[\n        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)\n    ]\n    # select relevant data\n    cols_to_select = pd.Index([\"Name\", \"hemisphere\", \"Area \u00b5m^2\"]).append(cols_colors)\n    # sum lengths and areas of each brain regions\n    df_regions = (\n        df_annotations[cols_to_select]\n        .groupby([\"Name\", \"hemisphere\"])\n        .sum()\n        .reset_index()\n    )\n\n    # get measurement for both hemispheres (sum)\n    df_both = df_annotations[cols_to_select].groupby([\"Name\"]).sum().reset_index()\n    df_both[\"hemisphere\"] = \"both\"\n    df_regions = (\n        pd.concat([df_regions, df_both], ignore_index=True)\n        .sort_values(by=\"Name\")\n        .reset_index()\n        .drop(columns=\"index\")\n    )\n\n    # rename measurement columns to lower case\n    df_regions = df_regions.rename(\n        columns={\n            k: k.replace(meas_base_name, meas_base_name.lower()) for k in cols_colors\n        }\n    )\n\n    # update names\n    meas_base_name = meas_base_name.lower()\n    cols = df_regions.columns\n    cols_colors = cols[\n        cols.str.startswith(object_type) & cols.str.endswith(meas_base_name)\n    ]\n\n    # convert area in mm^2\n    df_regions[\"Area mm^2\"] = df_regions[\"Area \u00b5m^2\"] / 1e6\n\n    # prepare metrics\n    if \"\u00b5m\" in meas_base_name:\n        # fibers : convert to mm\n        cols_to_convert = pd.Index([col for col in cols_colors if \"\u00b5m\" in col])\n        df_regions[cols_to_convert.str.replace(\"\u00b5m\", \"mm\")] = (\n            df_regions[cols_to_convert] / 1000\n        )\n        metrics = [meas_base_name, meas_base_name.replace(\"\u00b5m\", \"mm\")]\n    else:\n        # objects : count\n        metrics = [meas_base_name]\n\n    # density = measurement / area\n    metric = metrics_names[\"density \u00b5m^-2\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[\n        cols_colors\n    ].divide(df_regions[\"Area \u00b5m^2\"], axis=0)\n    metrics.append(metric)\n    metric = metrics_names[\"density mm^-2\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = df_regions[\n        cols_colors\n    ].divide(df_regions[\"Area mm^2\"], axis=0)\n    metrics.append(metric)\n\n    # coverage index = measurement\u00b2 / area\n    metric = metrics_names[\"coverage index\"]\n    df_regions[cols_colors.str.replace(meas_base_name, metric)] = (\n        df_regions[cols_colors].pow(2).divide(df_regions[\"Area \u00b5m^2\"], axis=0)\n    )\n    metrics.append(metric)\n\n    # prepare relative metrics columns\n    metric = metrics_names[\"relative measurement\"]\n    cols_rel_meas = cols_colors.str.replace(meas_base_name, metric)\n    df_regions[cols_rel_meas] = np.nan\n    metrics.append(metric)\n    metric = metrics_names[\"relative density\"]\n    cols_dens = cols_colors.str.replace(meas_base_name, metrics_names[\"density mm^-2\"])\n    cols_rel_dens = cols_colors.str.replace(meas_base_name, metric)\n    df_regions[cols_rel_dens] = np.nan\n    metrics.append(metric)\n    # relative metrics should be defined within each hemispheres (left, right, both)\n    for hemisphere in df_regions[\"hemisphere\"].unique():\n        row_indexer = df_regions[\"hemisphere\"] == hemisphere\n\n        # relative measurement = measurement / total measurement\n        df_regions.loc[row_indexer, cols_rel_meas] = (\n            df_regions.loc[row_indexer, cols_colors]\n            .divide(df_regions.loc[row_indexer, cols_colors].sum())\n            .to_numpy()\n        )\n\n        # relative density = density / total density\n        df_regions.loc[row_indexer, cols_rel_dens] = (\n            df_regions.loc[\n                row_indexer,\n                cols_dens,\n            ]\n            .divide(df_regions.loc[row_indexer, cols_dens].sum())\n            .to_numpy()\n        )\n\n    # collect channel names\n    channels = (\n        cols_colors.str.replace(object_type + \": \", \"\")\n        .str.replace(\" \" + meas_base_name, \"\")\n        .values.tolist()\n    )\n    # collect measurements columns names\n    cols_metrics = df_regions.columns.difference(\n        pd.Index([\"Name\", \"hemisphere\", \"Area \u00b5m^2\", \"Area mm^2\"])\n    )\n    for metric in metrics:\n        cols_to_cat = [f\"{object_type}: {cn} {metric}\" for cn in channels]\n        # make sure it's part of available metrics\n        if not set(cols_to_cat) <= set(cols_metrics):\n            raise ValueError(f\"{cols_to_cat} not in DataFrame.\")\n        # group all colors in the same colors\n        df_regions[metric] = df_regions[cols_to_cat].values.tolist()\n        # remove original data\n        df_regions = df_regions.drop(columns=cols_to_cat)\n\n    # add a color tag, given their names in the configuration file\n    df_regions[\"channel\"] = len(df_regions) * [[channel_names[k] for k in channels]]\n    metrics.append(\"channel\")\n\n    # explode the dataframe so that each color has an entry\n    df_regions = df_regions.explode(metrics)\n\n    return df_regions\n
"},{"location":"api-compute.html#cuisto.compute.normalize_starter_cells","title":"normalize_starter_cells(df, cols, animal, info_file, channel_names)","text":"

Normalize data by the number of starter cells.

Parameters:

Name Type Description Default df DataFrame

Contains the data to be normalized.

required cols list - like

Columns to divide by the number of starter cells.

required animal str

Animal ID to parse the number of starter cells.

required info_file str

Full path to the TOML file with informations.

required channel_names dict

Map between original channel names to something else.

required

Returns:

Type Description DataFrame

Same df with normalized count.

Source code in cuisto/compute.py
def normalize_starter_cells(\n    df: pd.DataFrame, cols: list[str], animal: str, info_file: str, channel_names: dict\n) -> pd.DataFrame:\n    \"\"\"\n    Normalize data by the number of starter cells.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        Contains the data to be normalized.\n    cols : list-like\n        Columns to divide by the number of starter cells.\n    animal : str\n        Animal ID to parse the number of starter cells.\n    info_file : str\n        Full path to the TOML file with informations.\n    channel_names : dict\n        Map between original channel names to something else.\n\n    Returns\n    -------\n    pd.DataFrame\n        Same `df` with normalized count.\n\n    \"\"\"\n    for channel in df[\"channel\"].unique():\n        # inverse mapping channel colors : names\n        reverse_channels = {v: k for k, v in channel_names.items()}\n        nstarters = get_starter_cells(animal, reverse_channels[channel], info_file)\n\n        for col in cols:\n            df.loc[df[\"channel\"] == channel, col] = (\n                df.loc[df[\"channel\"] == channel, col] / nstarters\n            )\n\n    return df\n
"},{"location":"api-config-config.html","title":"Api config config","text":"

object_type : name of QuPath base classification (eg. without the \": subclass\" part) segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

atlas

Information related to the atlas used

name : brainglobe-atlasapi atlas name type : \"brain\" or \"cord\" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps. midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates. outline_structures : structures to show an outline of in heatmaps

channels

Information related to imaging channels

names

Must contain all classifications derived from \"object_type\" you want to process. In the form subclassification name = name to display on the plots

\"marker+\" : classification name = name to display \"marker-\" : add any number of sub-classification

colors

Must have same keys as \"names\" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

\"marker+\" : classification name = matplotlib color \"marker-\" : must have the same entries as \"names\".

hemispheres

Information related to hemispheres, same structure as channels

names

Left : Left = name to display Right : Right = name to display

colors

Must have same keys as names' keys

Left : ff516e\" # Left = matplotlib color (either #hex, color name or RGB list) Right : 960010\" # Right = matplotlib color

distributions

Spatial distributions parameters

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3) ap_lim : bins limits for anterio-posterior in mm ap_nbins : number of bins for anterio-posterior dv_lim : bins limits for dorso-ventral in mm dv_nbins : number of bins for dorso-ventral ml_lim : bins limits for medio-lateral in mm ml_nbins : number of bins for medio-lateral hue : color curves with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

display

Display parameters

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up cmap : matplotlib color map for 2D heatmaps cmap_nbins : number of bins for 2D heatmaps cmap_lim : color limits for 2D heatmaps

regions

Distributions per regions parameters

base_measurement : the name of the measurement in QuPath to derive others from. Usually \"Count\" or \"Length \u00b5m\" hue : color bars with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter=\"both\", plots the two hemisphere in mirror. normalize_starter_cells : normalize non-relative metrics by the number of starter cells

metrics

Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

\"density \u00b5m^-2\" : relevant name \"density mm^-2\" : relevant name \"coverage index\" : relevant name \"relative measurement\" : relevant name \"relative density\" : relevant name

display

nregions : number of regions to display (sorted by max.) orientation : orientation of the bars (\"h\" or \"v\") order : order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order dodge : enforce the bar not being stacked log_scale : use log. scale for metrics

metrics

name of metrics to display

\"count\" : real_name = display_name, with real_name the \"values\" in [regions.metrics] \"density mm^-2\"

files

Full path to information TOML files and atlas outlines for 2D heatmaps.

blacklist fusion outlines infos

"},{"location":"api-config.html","title":"cuisto.config","text":"

config module, part of cuisto.

Contains the Config class.

"},{"location":"api-config.html#cuisto.config.Config","title":"Config(config_file)","text":"

The configuration class.

Reads input configuration file and provides its constant.

Parameters:

Name Type Description Default config_file str

Full path to the configuration file to load.

required

Returns:

Name Type Description cfg Config object.

Constructor.

Source code in cuisto/config.py
def __init__(self, config_file):\n    \"\"\"Constructor.\"\"\"\n    with open(config_file, \"rb\") as fid:\n        cfg = tomllib.load(fid)\n\n        for key in cfg:\n            setattr(self, key, cfg[key])\n\n    self.config_file = config_file\n    self.bg_atlas = BrainGlobeAtlas(self.atlas[\"name\"], check_latest=False)\n    self.get_blacklist()\n    self.get_leaves_list()\n
"},{"location":"api-config.html#cuisto.config.Config.get_blacklist","title":"get_blacklist()","text":"

Wraps cuisto.utils.get_blacklist.

Source code in cuisto/config.py
def get_blacklist(self):\n    \"\"\"Wraps cuisto.utils.get_blacklist.\"\"\"\n\n    self.atlas[\"blacklist\"] = utils.get_blacklist(\n        self.files[\"blacklist\"], self.bg_atlas\n    )\n
"},{"location":"api-config.html#cuisto.config.Config.get_hue_palette","title":"get_hue_palette(mode)","text":"

Get color palette given hue.

Maps hue to colors in channels or hemispheres.

Parameters:

Name Type Description Default mode (hemisphere, channel) \"hemisphere\"

Returns:

Name Type Description palette dict

Maps a hue level to a color, usable in seaborn.

Source code in cuisto/config.py
def get_hue_palette(self, mode: str) -> dict:\n    \"\"\"\n    Get color palette given hue.\n\n    Maps hue to colors in channels or hemispheres.\n\n    Parameters\n    ----------\n    mode : {\"hemisphere\", \"channel\"}\n\n    Returns\n    -------\n    palette : dict\n        Maps a hue level to a color, usable in seaborn.\n\n    \"\"\"\n    params = getattr(self, mode)\n\n    if params[\"hue\"] == \"channel\":\n        # replace channels by their new names\n        palette = {\n            self.channels[\"names\"][k]: v for k, v in self.channels[\"colors\"].items()\n        }\n    elif params[\"hue\"] == \"hemisphere\":\n        # replace hemispheres by their new names\n        palette = {\n            self.hemispheres[\"names\"][k]: v\n            for k, v in self.hemispheres[\"colors\"].items()\n        }\n    else:\n        palette = None\n        warnings.warn(f\"hue={self.regions[\"display\"][\"hue\"]} not supported.\")\n\n    return palette\n
"},{"location":"api-config.html#cuisto.config.Config.get_injection_sites","title":"get_injection_sites(animals)","text":"

Get list of injection sites coordinates for each animals, for each channels.

Parameters:

Name Type Description Default animals list of str

List of animals.

required

Returns:

Name Type Description injection_sites dict

{\"x\": {channel0: [x]}, \"y\": {channel1: [y]}}

Source code in cuisto/config.py
def get_injection_sites(self, animals: list[str]) -> dict:\n    \"\"\"\n    Get list of injection sites coordinates for each animals, for each channels.\n\n    Parameters\n    ----------\n    animals : list of str\n        List of animals.\n\n    Returns\n    -------\n    injection_sites : dict\n        {\"x\": {channel0: [x]}, \"y\": {channel1: [y]}}\n\n    \"\"\"\n    injection_sites = {\n        axis: {channel: [] for channel in self.channels[\"names\"].keys()}\n        for axis in [\"x\", \"y\", \"z\"]\n    }\n\n    for animal in animals:\n        for channel in self.channels[\"names\"].keys():\n            injx, injy, injz = utils.get_injection_site(\n                animal,\n                self.files[\"infos\"],\n                channel,\n                stereo=self.distributions[\"stereo\"],\n            )\n            if injx is not None:\n                injection_sites[\"x\"][channel].append(injx)\n            if injy is not None:\n                injection_sites[\"y\"][channel].append(injy)\n            if injz is not None:\n                injection_sites[\"z\"][channel].append(injz)\n\n    return injection_sites\n
"},{"location":"api-config.html#cuisto.config.Config.get_leaves_list","title":"get_leaves_list()","text":"

Wraps utils.get_leaves_list.

Source code in cuisto/config.py
def get_leaves_list(self):\n    \"\"\"Wraps utils.get_leaves_list.\"\"\"\n\n    self.atlas[\"leaveslist\"] = utils.get_leaves_list(self.bg_atlas)\n
"},{"location":"api-display.html","title":"cuisto.display","text":"

display module, part of cuisto.

Contains display functions, essentially wrapping matplotlib and seaborn functions.

"},{"location":"api-display.html#cuisto.display.add_data_coverage","title":"add_data_coverage(df, ax, colors=None, **kwargs)","text":"

Add lines below the plot to represent data coverage.

Parameters:

Name Type Description Default df DataFrame

DataFrame with X_min and X_max on rows for each animals (on columns).

required ax Axes

Handle to axes where to add the patch.

required colors list or str or None

Colors for the patches, as a RGB list or hex list. Should be the same size as the number of patches to plot, eg. the number of columns in df. If None, default seaborn colors are used. If only one element, used for each animal.

None **kwargs passed to patches.Rectangle() {}

Returns:

Name Type Description ax Axes

Handle to updated axes.

Source code in cuisto/display.py
def add_data_coverage(\n    df: pd.DataFrame, ax: plt.Axes, colors: list | str | None = None, **kwargs\n) -> plt.Axes:\n    \"\"\"\n    Add lines below the plot to represent data coverage.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n        DataFrame with `X_min` and `X_max` on rows for each animals (on columns).\n    ax : Axes\n        Handle to axes where to add the patch.\n    colors : list or str or None, optional\n        Colors for the patches, as a RGB list or hex list. Should be the same size as\n        the number of patches to plot, eg. the number of columns in `df`. If None,\n        default seaborn colors are used. If only one element, used for each animal.\n    **kwargs : passed to patches.Rectangle()\n\n    Returns\n    -------\n    ax : Axes\n        Handle to updated axes.\n\n    \"\"\"\n    # get colors\n    ncolumns = len(df.columns)\n    if not colors:\n        colors = sns.color_palette(n_colors=ncolumns)\n    elif isinstance(colors, str) or (isinstance(colors, list) & (len(colors) == 3)):\n        colors = [colors] * ncolumns\n    elif len(colors) != ncolumns:\n        warnings.warn(f\"Wrong number of colors ({len(colors)}), using default colors.\")\n        colors = sns.color_palette(n_colors=ncolumns)\n\n    # get patch height depending on current axis limits\n    ymin, ymax = ax.get_ylim()\n    height = (ymax - ymin) * 0.02\n\n    for animal, color in zip(df.columns, colors):\n        # get patch coordinates\n        ymin, ymax = ax.get_ylim()\n        ylength = ymax - ymin\n        ybottom = ymin - 0.02 * ylength\n        xleft = df.loc[\"X_min\", animal]\n        xright = df.loc[\"X_max\", animal]\n\n        # plot patch\n        ax.add_patch(\n            patches.Rectangle(\n                (xleft, ybottom),\n                xright - xleft,\n                height,\n                label=animal,\n                color=color,\n                **kwargs,\n            )\n        )\n\n        ax.autoscale(tight=True)  # set new axes limits\n\n    ax.autoscale()  # reset scale\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.add_injection_patch","title":"add_injection_patch(X, ax, **kwargs)","text":"

Add a patch representing the injection sites.

The patch will span from the minimal coordinate to the maximal. If plotted in stereotaxic coordinates, coordinates should be converted beforehand.

Parameters:

Name Type Description Default X list

Coordinates in mm for each animals. Can be empty to not plot anything.

required ax Axes

Handle to axes where to add the patch.

required **kwargs passed to Axes.axvspan {}

Returns:

Name Type Description ax Axes

Handle to updated Axes.

Source code in cuisto/display.py
def add_injection_patch(X: list, ax: plt.Axes, **kwargs) -> plt.Axes:\n    \"\"\"\n    Add a patch representing the injection sites.\n\n    The patch will span from the minimal coordinate to the maximal.\n    If plotted in stereotaxic coordinates, coordinates should be converted beforehand.\n\n    Parameters\n    ----------\n    X : list\n        Coordinates in mm for each animals. Can be empty to not plot anything.\n    ax : Axes\n        Handle to axes where to add the patch.\n    **kwargs : passed to Axes.axvspan\n\n    Returns\n    -------\n    ax : Axes\n        Handle to updated Axes.\n\n    \"\"\"\n    # plot patch\n    if len(X) > 0:\n        ax.axvspan(min(X), max(X), **kwargs)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.draw_structure_outline","title":"draw_structure_outline(view='sagittal', structures=['root'], outline_file='', ax=None, microns=False, **kwargs)","text":"

Plot brain regions outlines in given projection.

This requires a file containing the structures outlines.

Parameters:

Name Type Description Default view str

Projection, \"sagittal\", \"coronal\" or \"top\". Default is \"sagittal\".

'sagittal' structures list[str]

List of structures acronyms whose outlines will be drawn. Default is [\"root\"].

['root'] outline_file str

Full path the outlines HDF5 file.

'' ax Axes or None

Axes where to plot the outlines. If None, get current axes (the default).

None microns bool

If False (default), converts the coordinates in mm.

False **kwargs passed to pyplot.plot() {}

Returns:

Name Type Description ax Axes Source code in cuisto/display.py
def draw_structure_outline(\n    view: str = \"sagittal\",\n    structures: list[str] = [\"root\"],\n    outline_file: str = \"\",\n    ax: plt.Axes | None = None,\n    microns: bool = False,\n    **kwargs,\n) -> plt.Axes:\n    \"\"\"\n    Plot brain regions outlines in given projection.\n\n    This requires a file containing the structures outlines.\n\n    Parameters\n    ----------\n    view : str\n        Projection, \"sagittal\", \"coronal\" or \"top\". Default is \"sagittal\".\n    structures : list[str]\n        List of structures acronyms whose outlines will be drawn. Default is [\"root\"].\n    outline_file : str\n        Full path the outlines HDF5 file.\n    ax : plt.Axes or None, optional\n        Axes where to plot the outlines. If None, get current axes (the default).\n    microns : bool, optional\n        If False (default), converts the coordinates in mm.\n    **kwargs : passed to pyplot.plot()\n\n    Returns\n    -------\n    ax : plt.Axes\n\n    \"\"\"\n    # get axes\n    if not ax:\n        ax = plt.gca()\n\n    # get units\n    if microns:\n        conv = 1\n    else:\n        conv = 1 / 1000\n\n    with h5py.File(outline_file) as f:\n        if view == \"sagittal\":\n            for structure in structures:\n                dsets = f[\"sagittal\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n        if view == \"coronal\":\n            for structure in structures:\n                dsets = f[\"coronal\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n        if view == \"top\":\n            for structure in structures:\n                dsets = f[\"top\"][structure]\n\n                for dset in dsets.values():\n                    ax.plot(dset[:, 0] * conv, dset[:, 1] * conv, **kwargs)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.nice_bar_plot","title":"nice_bar_plot(df, x='', y=[''], hue='', ylabel=[''], orient='h', nx=None, ordering=None, names_list=None, hue_mirror=False, log_scale=False, bar_kws={}, pts_kws={})","text":"

Nice bar plot of per-region objects distribution.

This is used for objects distribution across brain regions. Shows the y metric (count, aeral density, cumulated length...) in each x categories (brain regions). orient controls wether the bars are shown horizontally (default) or vertically. Input df must have an additional \"hemisphere\" column. All y are plotted in the same figure as different subplots. nx controls the number of displayed regions.

Parameters:

Name Type Description Default df DataFrame required x str

Key in df.

'' y str

Key in df.

'' hue str

Key in df.

'' ylabel list of str

Y axis labels.

[''] orient h or v

\"h\" for horizontal bars (default) or \"v\" for vertical bars.

'h' nx None or int

Number of x to show in the plot. Default is None (no limit).

None ordering None or list[str] or max

Sorted list of acronyms. Data will be sorted follwowing this order, if \"max\", sorted by descending values, if None, not sorted (default).

None names_list list or None

List of names to display. If None (default), takes the most prominent overall ones.

None hue_mirror bool

If there are 2 groups, plot in mirror. Default is False.

False log_scale bool

Set the metrics in log scale. Default is False.

False bar_kws dict

Passed to seaborn.barplot().

{} pts_kws dict

Passed to seaborn.stripplot().

{}

Returns:

Name Type Description figs list

List of figures.

Source code in cuisto/display.py
def nice_bar_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: list[str] = [\"\"],\n    hue: str = \"\",\n    ylabel: list[str] = [\"\"],\n    orient=\"h\",\n    nx: None | int = None,\n    ordering: None | list[str] | str = None,\n    names_list: None | list = None,\n    hue_mirror: bool = False,\n    log_scale: bool = False,\n    bar_kws: dict = {},\n    pts_kws: dict = {},\n) -> list[plt.Axes]:\n    \"\"\"\n    Nice bar plot of per-region objects distribution.\n\n    This is used for objects distribution across brain regions. Shows the `y` metric\n    (count, aeral density, cumulated length...) in each `x` categories (brain regions).\n    `orient` controls wether the bars are shown horizontally (default) or vertically.\n    Input `df` must have an additional \"hemisphere\" column. All `y` are plotted in the\n    same figure as different subplots. `nx` controls the number of displayed regions.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y, hue : str\n        Key in `df`.\n    ylabel : list of str\n        Y axis labels.\n    orient : \"h\" or \"v\", optional\n        \"h\" for horizontal bars (default) or \"v\" for vertical bars.\n    nx : None or int, optional\n        Number of `x` to show in the plot. Default is None (no limit).\n    ordering : None or list[str] or \"max\", optional\n        Sorted list of acronyms. Data will be sorted follwowing this order, if \"max\",\n        sorted by descending values, if None, not sorted (default).\n    names_list : list or None, optional\n        List of names to display. If None (default), takes the most prominent overall\n        ones.\n    hue_mirror : bool, optional\n        If there are 2 groups, plot in mirror. Default is False.\n    log_scale : bool, optional\n        Set the metrics in log scale. Default is False.\n    bar_kws : dict\n        Passed to seaborn.barplot().\n    pts_kws : dict\n        Passed to seaborn.stripplot().\n\n    Returns\n    -------\n    figs : list\n        List of figures.\n\n    \"\"\"\n    figs = []\n    # loop for each features\n    for yi, ylabeli in zip(y, ylabel):\n        # prepare data\n        # get nx first most prominent regions\n        if not names_list:\n            names_list_plt = (\n                df.groupby([\"Name\"])[yi].mean().sort_values(ascending=False).index[0:nx]\n            )\n        else:\n            names_list_plt = names_list\n        dfplt = df[df[\"Name\"].isin(names_list_plt)]  # limit to those regions\n        # limit hierarchy list if provided\n        if isinstance(ordering, list):\n            order = [el for el in ordering if el in names_list_plt]\n        elif ordering == \"max\":\n            order = names_list_plt\n        else:\n            order = None\n\n        # reorder keys depending on orientation and create axes\n        if orient == \"h\":\n            xp = yi\n            yp = x\n            if hue_mirror:\n                nrows = 1\n                ncols = 2\n                sharex = None\n                sharey = \"all\"\n            else:\n                nrows = 1\n                ncols = 1\n                sharex = None\n                sharey = None\n        elif orient == \"v\":\n            xp = x\n            yp = yi\n            if hue_mirror:\n                nrows = 2\n                ncols = 1\n                sharex = \"all\"\n                sharey = None\n            else:\n                nrows = 1\n                ncols = 1\n                sharex = None\n                sharey = None\n        fig, axs = plt.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey)\n\n        if hue_mirror:\n            # two graphs\n            ax1, ax2 = axs\n            # determine what will be mirrored\n            if hue == \"channel\":\n                hue_filter = \"hemisphere\"\n            elif hue == \"hemisphere\":\n                hue_filter = \"channel\"\n            # select the two types (should be left/right or two channels)\n            hue_filters = dfplt[hue_filter].unique()[0:2]\n            hue_filters.sort()  # make sure it will be always in the same order\n\n            # plot\n            for filt, ax in zip(hue_filters, [ax1, ax2]):\n                dfplt2 = dfplt[dfplt[hue_filter] == filt]\n                ax = sns.barplot(\n                    dfplt2,\n                    x=xp,\n                    y=yp,\n                    hue=hue,\n                    estimator=\"mean\",\n                    errorbar=\"se\",\n                    orient=orient,\n                    order=order,\n                    ax=ax,\n                    **bar_kws,\n                )\n                # add points\n                ax = sns.stripplot(\n                    dfplt2, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws\n                )\n\n                # cosmetics\n                if orient == \"h\":\n                    ax.set_title(f\"{hue_filter}: {filt}\")\n                    ax.set_ylabel(None)\n                    ax.set_ylim((nx + 0.5, -0.5))\n                    if log_scale:\n                        ax.set_xscale(\"log\")\n\n                elif orient == \"v\":\n                    if ax == ax1:\n                        # top title\n                        ax1.set_title(f\"{hue_filter}: {filt}\")\n                        ax.set_xlabel(None)\n                    elif ax == ax2:\n                        # use xlabel as bottom title\n                        ax2.set_xlabel(\n                            f\"{hue_filter}: {filt}\", fontsize=ax1.title.get_fontsize()\n                        )\n                    ax.set_xlim((-0.5, nx + 0.5))\n                    if log_scale:\n                        ax.set_yscale(\"log\")\n\n                    for label in ax.get_xticklabels():\n                        label.set_verticalalignment(\"center\")\n                        label.set_horizontalalignment(\"center\")\n\n            # tune axes cosmetics\n            if orient == \"h\":\n                ax1.set_xlabel(ylabeli)\n                ax2.set_xlabel(ylabeli)\n                ax1.set_xlim(\n                    ax1.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))\n                )\n                ax2.set_xlim(\n                    ax2.get_xlim()[0], max((ax1.get_xlim()[1], ax2.get_xlim()[1]))\n                )\n                ax1.invert_xaxis()\n                sns.despine(ax=ax1, left=True, top=True, right=False, bottom=False)\n                sns.despine(ax=ax2, left=False, top=True, right=True, bottom=False)\n                ax1.yaxis.tick_right()\n                ax1.tick_params(axis=\"y\", pad=20)\n                for label in ax1.get_yticklabels():\n                    label.set_verticalalignment(\"center\")\n                    label.set_horizontalalignment(\"center\")\n            elif orient == \"v\":\n                ax2.set_ylabel(ylabeli)\n                ax1.set_ylim(\n                    ax1.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))\n                )\n                ax2.set_ylim(\n                    ax2.get_ylim()[0], max((ax1.get_ylim()[1], ax2.get_ylim()[1]))\n                )\n                ax2.invert_yaxis()\n                sns.despine(ax=ax1, left=False, top=True, right=True, bottom=False)\n                sns.despine(ax=ax2, left=False, top=False, right=True, bottom=True)\n                for label in ax2.get_xticklabels():\n                    label.set_verticalalignment(\"center\")\n                    label.set_horizontalalignment(\"center\")\n                ax2.tick_params(axis=\"x\", labelrotation=90, pad=20)\n\n        else:\n            # one graph\n            ax = axs\n            # plot\n            ax = sns.barplot(\n                dfplt,\n                x=xp,\n                y=yp,\n                hue=hue,\n                estimator=\"mean\",\n                errorbar=\"se\",\n                orient=orient,\n                order=order,\n                ax=ax,\n                **bar_kws,\n            )\n            # add points\n            ax = sns.stripplot(\n                dfplt, x=xp, y=yp, hue=hue, legend=False, ax=ax, **pts_kws\n            )\n\n            # cosmetics\n            if orient == \"h\":\n                ax.set_xlabel(ylabeli)\n                ax.set_ylabel(None)\n                ax.set_ylim((nx + 0.5, -0.5))\n                if log_scale:\n                    ax.set_xscale(\"log\")\n            elif orient == \"v\":\n                ax.set_xlabel(None)\n                ax.set_ylabel(ylabeli)\n                ax.set_xlim((-0.5, nx + 0.5))\n                if log_scale:\n                    ax.set_yscale(\"log\")\n\n        fig.tight_layout(pad=0)\n        figs.append(fig)\n\n    return figs\n
"},{"location":"api-display.html#cuisto.display.nice_distribution_plot","title":"nice_distribution_plot(df, x='', y='', hue=None, xlabel='', ylabel='', injections_sites={}, channel_colors={}, channel_names={}, ax=None, **kwargs)","text":"

Nice plot of 1D distribution of objects.

Parameters:

Name Type Description Default df DataFrame required x str

Keys in df.

'' y str

Keys in df.

'' hue str or None

Key in df. If None, no hue is used.

None xlabel str

X and Y axes labels.

'' ylabel str

X and Y axes labels.

'' injections_sites dict

List of injection sites 1D coordinates in a dict with the channel name as key. If empty, injection site is not plotted (default).

{} channel_colors dict

Required if injections_sites is not empty, dict mapping channel names to a color.

{} channel_names dict

Required if injections_sites is not empty, dict mapping channel names to a display name.

{} ax Axes or None

Axes in which to plot the figure, if None, a new figure is created (default).

None **kwargs passed to seaborn.lineplot() {}

Returns:

Name Type Description ax matplotlib axes

Handle to axes.

Source code in cuisto/display.py
def nice_distribution_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: str = \"\",\n    hue: str | None = None,\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    injections_sites: dict = {},\n    channel_colors: dict = {},\n    channel_names: dict = {},\n    ax: plt.Axes | None = None,\n    **kwargs,\n) -> plt.Axes:\n    \"\"\"\n    Nice plot of 1D distribution of objects.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y : str\n        Keys in `df`.\n    hue : str or None, optional\n        Key in `df`. If None, no hue is used.\n    xlabel, ylabel : str\n        X and Y axes labels.\n    injections_sites : dict, optional\n        List of injection sites 1D coordinates in a dict with the channel name as key.\n        If empty, injection site is not plotted (default).\n    channel_colors : dict, optional\n        Required if injections_sites is not empty, dict mapping channel names to a\n        color.\n    channel_names : dict, optional\n        Required if injections_sites is not empty, dict mapping channel names to a\n        display name.\n    ax : Axes or None, optional\n        Axes in which to plot the figure, if None, a new figure is created (default).\n    **kwargs : passed to seaborn.lineplot()\n\n    Returns\n    -------\n    ax : matplotlib axes\n        Handle to axes.\n\n    \"\"\"\n    if not ax:\n        # create figure\n        _, ax = plt.subplots(figsize=(10, 6))\n\n    ax = sns.lineplot(\n        df,\n        x=x,\n        y=y,\n        hue=hue,\n        estimator=\"mean\",\n        errorbar=\"se\",\n        ax=ax,\n        **kwargs,\n    )\n\n    for channel in injections_sites.keys():\n        ax = add_injection_patch(\n            injections_sites[channel],\n            ax,\n            color=channel_colors[channel],\n            edgecolor=None,\n            alpha=0.25,\n            label=channel_names[channel] + \": inj. site\",\n        )\n\n    ax.legend()\n    ax.set_xlabel(xlabel)\n    ax.set_ylabel(ylabel)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.nice_heatmap","title":"nice_heatmap(df, animals, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, **kwargs)","text":"

Nice plots of 2D distribution of boutons as a heatmap per animal.

Parameters:

Name Type Description Default df DataFrame required animals list-like of str

List of animals.

required x str

Keys in df.

'' y str

Keys in df.

'' xlabel str

Labels of x and y axes.

'' ylabel str

Labels of x and y axes.

'' invertx bool

Wether to inverse the x or y axes. Default is False.

False inverty bool

Wether to inverse the x or y axes. Default is False.

False **kwargs passed to seaborn.histplot() {}

Returns:

Name Type Description ax Axes or list of Axes

Handle to axes.

Source code in cuisto/display.py
def nice_heatmap(\n    df: pd.DataFrame,\n    animals: tuple[str] | list[str],\n    x: str = \"\",\n    y: str = \"\",\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    invertx: bool = False,\n    inverty: bool = False,\n    **kwargs,\n) -> list[plt.Axes] | plt.Axes:\n    \"\"\"\n    Nice plots of 2D distribution of boutons as a heatmap per animal.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    animals : list-like of str\n        List of animals.\n    x, y : str\n        Keys in `df`.\n    xlabel, ylabel : str\n        Labels of x and y axes.\n    invertx, inverty : bool, optional\n        Wether to inverse the x or y axes. Default is False.\n    **kwargs : passed to seaborn.histplot()\n\n    Returns\n    -------\n    ax : Axes or list of Axes\n        Handle to axes.\n\n    \"\"\"\n\n    # 2D distribution, per animal\n    _, axs = plt.subplots(len(animals), 1, sharex=\"all\")\n\n    for animal, ax in zip(animals, axs):\n        ax = sns.histplot(\n            df[df[\"animal\"] == animal],\n            x=x,\n            y=y,\n            ax=ax,\n            **kwargs,\n        )\n        ax.set_xlabel(xlabel)\n        ax.set_ylabel(ylabel)\n        ax.set_title(animal)\n\n        if inverty:\n            ax.invert_yaxis()\n\n    if invertx:\n        axs[-1].invert_xaxis()  # only once since all x axes are shared\n\n    return axs\n
"},{"location":"api-display.html#cuisto.display.nice_joint_plot","title":"nice_joint_plot(df, x='', y='', xlabel='', ylabel='', invertx=False, inverty=False, outline_kws={}, ax=None, **kwargs)","text":"

Joint distribution.

Used to display a 2D heatmap of objects. This is more qualitative than quantitative, for display purposes.

Parameters:

Name Type Description Default df DataFrame required x str

Keys in df.

'' y str

Keys in df.

'' xlabel str

Label of x and y axes.

'' ylabel str

Label of x and y axes.

'' invertx bool

Whether to inverse the x or y axes. Default is False for both.

False inverty bool

Whether to inverse the x or y axes. Default is False for both.

False outline_kws dict

Passed to draw_structure_outline().

{} ax Axes or None

Axes to plot in. If None, draws in current axes (default).

None **kwargs

Passed to seaborn.histplot.

{}

Returns:

Name Type Description ax Axes Source code in cuisto/display.py
def nice_joint_plot(\n    df: pd.DataFrame,\n    x: str = \"\",\n    y: str = \"\",\n    xlabel: str = \"\",\n    ylabel: str = \"\",\n    invertx: bool = False,\n    inverty: bool = False,\n    outline_kws: dict = {},\n    ax: plt.Axes | None = None,\n    **kwargs,\n) -> plt.Figure:\n    \"\"\"\n    Joint distribution.\n\n    Used to display a 2D heatmap of objects. This is more qualitative than quantitative,\n    for display purposes.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    x, y : str\n        Keys in `df`.\n    xlabel, ylabel : str\n        Label of x and y axes.\n    invertx, inverty : bool, optional\n        Whether to inverse the x or y axes. Default is False for both.\n    outline_kws : dict\n        Passed to draw_structure_outline().\n    ax : plt.Axes or None, optional\n        Axes to plot in. If None, draws in current axes (default).\n    **kwargs\n        Passed to seaborn.histplot.\n\n    Returns\n    -------\n    ax : plt.Axes\n\n    \"\"\"\n    if not ax:\n        ax = plt.gca()\n\n    # plot outline\n    draw_structure_outline(ax=ax, **outline_kws)\n\n    # plot joint distribution\n    sns.histplot(\n        df,\n        x=x,\n        y=y,\n        ax=ax,\n        **kwargs,\n    )\n\n    # adjust axes\n    if invertx:\n        ax.invert_xaxis()\n    if inverty:\n        ax.invert_yaxis()\n\n    # labels\n    ax.set_xlabel(xlabel)\n    ax.set_ylabel(ylabel)\n\n    return ax\n
"},{"location":"api-display.html#cuisto.display.plot_1D_distributions","title":"plot_1D_distributions(dfs_distributions, cfg, df_coordinates=None)","text":"

Wraps nice_distribution_plot().

Source code in cuisto/display.py
def plot_1D_distributions(\n    dfs_distributions: list[pd.DataFrame],\n    cfg,\n    df_coordinates: pd.DataFrame = None,\n):\n    \"\"\"\n    Wraps nice_distribution_plot().\n    \"\"\"\n    # prepare figures\n    fig, axs_dist = plt.subplots(1, 3, sharey=True, figsize=(13, 6))\n    xlabels = [\n        \"Rostro-caudal position (mm)\",\n        \"Dorso-ventral position (mm)\",\n        \"Medio-lateral position (mm)\",\n    ]\n\n    # get animals\n    animals = []\n    for df in dfs_distributions:\n        animals.extend(df[\"animal\"].unique())\n    animals = set(animals)\n\n    # get injection sites\n    if cfg.distributions[\"display\"][\"show_injection\"]:\n        injection_sites = cfg.get_injection_sites(animals)\n    else:\n        injection_sites = {k: {} for k in range(3)}\n\n    # get color palette based on hue\n    hue = cfg.distributions[\"hue\"]\n    palette = cfg.get_hue_palette(\"distributions\")\n\n    # loop through each axis\n    for df_dist, ax_dist, xlabel, inj_sites in zip(\n        dfs_distributions, axs_dist, xlabels, injection_sites.values()\n    ):\n        # select data\n        if cfg.distributions[\"hue\"] == \"hemisphere\":\n            dfplt = df_dist[df_dist[\"hemisphere\"] != \"both\"]\n        elif cfg.distributions[\"hue\"] == \"channel\":\n            dfplt = df_dist[df_dist[\"channel\"] != \"all\"]\n\n        # plot\n        ax_dist = nice_distribution_plot(\n            dfplt,\n            x=\"bins\",\n            y=\"distribution\",\n            hue=hue,\n            xlabel=xlabel,\n            ylabel=\"normalized distribution\",\n            injections_sites=inj_sites,\n            channel_colors=cfg.channels[\"colors\"],\n            channel_names=cfg.channels[\"names\"],\n            linewidth=2,\n            palette=palette,\n            ax=ax_dist,\n        )\n\n        # add data coverage\n        if (\"Atlas_AP\" in df_dist[\"axis\"].unique()) & (df_coordinates is not None):\n            df_coverage = utils.get_data_coverage(df_coordinates)\n            ax_dist = add_data_coverage(df_coverage, ax_dist, edgecolor=None, alpha=0.5)\n            ax_dist.legend()\n        else:\n            ax_dist.legend().remove()\n\n    # - Distributions, per animal\n    if len(animals) > 1:\n        _, axs_dist = plt.subplots(1, 3, sharey=True)\n\n        # loop through each axis\n        for df_dist, ax_dist, xlabel, inj_sites in zip(\n            dfs_distributions, axs_dist, xlabels, injection_sites.values()\n        ):\n            # select data\n            df_dist_plot = df_dist[df_dist[\"hemisphere\"] == \"both\"]\n\n            # plot\n            ax_dist = nice_distribution_plot(\n                df_dist_plot,\n                x=\"bins\",\n                y=\"distribution\",\n                hue=\"animal\",\n                xlabel=xlabel,\n                ylabel=\"normalized distribution\",\n                injections_sites=inj_sites,\n                channel_colors=cfg.channels[\"colors\"],\n                channel_names=cfg.channels[\"names\"],\n                linewidth=2,\n                ax=ax_dist,\n            )\n\n    return fig\n
"},{"location":"api-display.html#cuisto.display.plot_2D_distributions","title":"plot_2D_distributions(df, cfg)","text":"

Wraps nice_joint_plot().

Source code in cuisto/display.py
def plot_2D_distributions(df: pd.DataFrame, cfg):\n    \"\"\"\n    Wraps nice_joint_plot().\n    \"\"\"\n    # -- 2D heatmap, all animals pooled\n    # prepare figure\n    fig_heatmap = plt.figure(figsize=(12, 9))\n\n    ax_sag = fig_heatmap.add_subplot(2, 2, 1)\n    ax_cor = fig_heatmap.add_subplot(2, 2, 2, sharey=ax_sag)\n    ax_top = fig_heatmap.add_subplot(2, 2, 3, sharex=ax_sag)\n    ax_cbar = fig_heatmap.add_subplot(2, 2, 4, box_aspect=15)\n\n    # prepare options\n    map_options = dict(\n        bins=cfg.distributions[\"display\"][\"cmap_nbins\"],\n        cmap=cfg.distributions[\"display\"][\"cmap\"],\n        rasterized=True,\n        thresh=10,\n        stat=\"count\",\n        vmin=cfg.distributions[\"display\"][\"cmap_lim\"][0],\n        vmax=cfg.distributions[\"display\"][\"cmap_lim\"][1],\n    )\n    outline_kws = dict(\n        structures=cfg.atlas[\"outline_structures\"],\n        outline_file=cfg.files[\"outlines\"],\n        linewidth=1.5,\n        color=\"k\",\n    )\n    cbar_kws = dict(label=\"count\")\n\n    # determine which axes are going to be inverted\n    if cfg.atlas[\"type\"] == \"brain\":\n        cor_invertx = True\n        cor_inverty = False\n        top_invertx = True\n        top_inverty = False\n    elif cfg.atlas[\"type\"] == \"cord\":\n        cor_invertx = False\n        cor_inverty = False\n        top_invertx = True\n        top_inverty = True\n\n    # - sagittal\n    # no need to invert axes because they are shared with the two other views\n    outline_kws[\"view\"] = \"sagittal\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_X\",\n        y=\"Atlas_Y\",\n        xlabel=\"Rostro-caudal (mm)\",\n        ylabel=\"Dorso-ventral (mm)\",\n        outline_kws=outline_kws,\n        ax=ax_sag,\n        **map_options,\n    )\n\n    # - coronal\n    outline_kws[\"view\"] = \"coronal\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_Z\",\n        y=\"Atlas_Y\",\n        xlabel=\"Medio-lateral (mm)\",\n        ylabel=\"Dorso-ventral (mm)\",\n        invertx=cor_invertx,\n        inverty=cor_inverty,\n        outline_kws=outline_kws,\n        ax=ax_cor,\n        **map_options,\n    )\n    ax_cor.invert_yaxis()\n\n    # - top\n    outline_kws[\"view\"] = \"top\"\n    nice_joint_plot(\n        df,\n        x=\"Atlas_X\",\n        y=\"Atlas_Z\",\n        xlabel=\"Rostro-caudal (mm)\",\n        ylabel=\"Medio-lateral (mm)\",\n        invertx=top_invertx,\n        inverty=top_inverty,\n        outline_kws=outline_kws,\n        ax=ax_top,\n        cbar=True,\n        cbar_ax=ax_cbar,\n        cbar_kws=cbar_kws,\n        **map_options,\n    )\n    fig_heatmap.suptitle(\"sagittal, coronal and top-view projections\")\n\n    # -- 2D heatmap per animals\n    # get animals\n    animals = df[\"animal\"].unique()\n    if len(animals) > 1:\n        # Rostro-caudal, dorso-ventral (sagittal)\n        _ = nice_heatmap(\n            df,\n            animals,\n            x=\"Atlas_X\",\n            y=\"Atlas_Y\",\n            xlabel=\"Rostro-caudal (mm)\",\n            ylabel=\"Dorso-ventral (mm)\",\n            invertx=True,\n            inverty=True,\n            cmap=\"OrRd\",\n            rasterized=True,\n            cbar=True,\n        )\n\n        # Medio-lateral, dorso-ventral (coronal)\n        _ = nice_heatmap(\n            df,\n            animals,\n            x=\"Atlas_Z\",\n            y=\"Atlas_Y\",\n            xlabel=\"Medio-lateral (mm)\",\n            ylabel=\"Dorso-ventral (mm)\",\n            inverty=True,\n            invertx=True,\n            cmap=\"OrRd\",\n            rasterized=True,\n        )\n\n    return fig_heatmap\n
"},{"location":"api-display.html#cuisto.display.plot_regions","title":"plot_regions(df, cfg, **kwargs)","text":"

Wraps nice_bar_plot().

Source code in cuisto/display.py
def plot_regions(df: pd.DataFrame, cfg, **kwargs):\n    \"\"\"\n    Wraps nice_bar_plot().\n    \"\"\"\n    # get regions order\n    if cfg.regions[\"display\"][\"order\"] == \"ontology\":\n        regions_order = [d[\"acronym\"] for d in cfg.bg_atlas.structures_list]\n    elif cfg.regions[\"display\"][\"order\"] == \"max\":\n        regions_order = \"max\"\n    else:\n        regions_order = None\n\n    # determine metrics to be plotted and color palette based on hue\n    metrics = [*cfg.regions[\"display\"][\"metrics\"].keys()]\n    hue = cfg.regions[\"hue\"]\n    palette = cfg.get_hue_palette(\"regions\")\n\n    # select data\n    dfplt = utils.select_hemisphere_channel(\n        df, hue, cfg.regions[\"hue_filter\"], cfg.regions[\"hue_mirror\"]\n    )\n\n    # prepare options\n    bar_kws = dict(\n        err_kws={\"linewidth\": 1.5},\n        dodge=cfg.regions[\"display\"][\"dodge\"],\n        palette=palette,\n    )\n    pts_kws = dict(\n        size=4,\n        edgecolor=\"auto\",\n        linewidth=0.75,\n        dodge=cfg.regions[\"display\"][\"dodge\"],\n        palette=palette,\n    )\n    # draw\n    figs = nice_bar_plot(\n        dfplt,\n        x=\"Name\",\n        y=metrics,\n        hue=hue,\n        ylabel=[*cfg.regions[\"display\"][\"metrics\"].values()],\n        orient=cfg.regions[\"display\"][\"orientation\"],\n        nx=cfg.regions[\"display\"][\"nregions\"],\n        ordering=regions_order,\n        hue_mirror=cfg.regions[\"hue_mirror\"],\n        log_scale=cfg.regions[\"display\"][\"log_scale\"],\n        bar_kws=bar_kws,\n        pts_kws=pts_kws,\n        **kwargs,\n    )\n\n    return figs\n
"},{"location":"api-io.html","title":"cuisto.io","text":"

io module, part of cuisto.

Contains loading and saving functions.

"},{"location":"api-io.html#cuisto.io.cat_csv_dir","title":"cat_csv_dir(directory, **kwargs)","text":"

Scans a directory for csv files and concatenate them into a single DataFrame.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required **kwargs passed to pandas.read_csv() {}

Returns:

Name Type Description df DataFrame

All CSV files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_csv_dir(directory, **kwargs) -> pd.DataFrame:\n    \"\"\"\n    Scans a directory for csv files and concatenate them into a single DataFrame.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    **kwargs : passed to pandas.read_csv()\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        All CSV files concatenated in a single DataFrame.\n\n    \"\"\"\n    return pd.concat(\n        pd.read_csv(\n            os.path.join(directory, filename),\n            **kwargs,\n        )\n        for filename in os.listdir(directory)\n        if (filename.endswith(\".csv\"))\n        and not check_empty_file(os.path.join(directory, filename), threshold=1)\n    )\n
"},{"location":"api-io.html#cuisto.io.cat_data_dir","title":"cat_data_dir(directory, segtype, **kwargs)","text":"

Wraps either cat_csv_dir() or cat_json_dir() depending on segtype.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required segtype str

\"synaptophysin\" or \"fibers\".

required **kwargs passed to cat_csv_dir() or cat_json_dir(). {}

Returns:

Name Type Description df DataFrame

All files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_data_dir(directory: str, segtype: str, **kwargs) -> pd.DataFrame:\n    \"\"\"\n    Wraps either cat_csv_dir() or cat_json_dir() depending on `segtype`.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    segtype : str\n        \"synaptophysin\" or \"fibers\".\n    **kwargs : passed to cat_csv_dir() or cat_json_dir().\n\n    Returns\n    -------\n    df : pd.DataFrame\n        All files concatenated in a single DataFrame.\n\n    \"\"\"\n    if segtype in CSV_KW:\n        # remove kwargs for json\n        kwargs.pop(\"hemisphere_names\", None)\n        kwargs.pop(\"atlas\", None)\n        return cat_csv_dir(directory, **kwargs)\n    elif segtype in JSON_KW:\n        kwargs = {k: kwargs[k] for k in [\"hemisphere_names\", \"atlas\"] if k in kwargs}\n        return cat_json_dir(directory, **kwargs)\n    else:\n        raise ValueError(\n            f\"'{segtype}' not supported, unable to determine if CSV or JSON.\"\n        )\n
"},{"location":"api-io.html#cuisto.io.cat_json_dir","title":"cat_json_dir(directory, hemisphere_names, atlas)","text":"

Scans a directory for json files and concatenate them in a single DataFrame.

The json files must be generated with 'workflow_import_export.groovy\" from a QuPath project.

Parameters:

Name Type Description Default directory str

Path to the directory to scan.

required hemisphere_names dict

Maps between hemisphere names in the json files (\"Right\" and \"Left\") to something else (eg. \"Ipsi.\" and \"Contra.\").

required atlas BrainGlobeAtlas

Atlas to read regions from.

required

Returns:

Name Type Description df DataFrame

All JSON files concatenated in a single DataFrame.

Source code in cuisto/io.py
def cat_json_dir(\n    directory: str, hemisphere_names: dict, atlas: BrainGlobeAtlas\n) -> pd.DataFrame:\n    \"\"\"\n    Scans a directory for json files and concatenate them in a single DataFrame.\n\n    The json files must be generated with 'workflow_import_export.groovy\" from a QuPath\n    project.\n\n    Parameters\n    ----------\n    directory : str\n        Path to the directory to scan.\n    hemisphere_names : dict\n        Maps between hemisphere names in the json files (\"Right\" and \"Left\") to\n        something else (eg. \"Ipsi.\" and \"Contra.\").\n    atlas : BrainGlobeAtlas\n        Atlas to read regions from.\n\n    Returns\n    -------\n    df : pd.DataFrame\n        All JSON files concatenated in a single DataFrame.\n\n    \"\"\"\n    # list files\n    files_list = [\n        os.path.join(directory, filename)\n        for filename in os.listdir(directory)\n        if (filename.endswith(\".json\"))\n    ]\n\n    data = []  # prepare list of DataFrame\n    for filename in files_list:\n        with open(filename, \"rb\") as fid:\n            df = pd.DataFrame.from_dict(\n                orjson.loads(fid.read())[\"paths\"], orient=\"index\"\n            )\n            df[\"Image\"] = os.path.basename(filename).split(\"_detections\")[0]\n            data.append(df)\n\n    df = (\n        pd.concat(data)\n        .explode(\n            [\"x\", \"y\", \"z\", \"hemisphere\"]\n        )  # get an entry for each point of segments\n        .reset_index()\n        .rename(\n            columns=dict(\n                x=\"Atlas_X\",\n                y=\"Atlas_Y\",\n                z=\"Atlas_Z\",\n                index=\"Object ID\",\n                classification=\"Classification\",\n            )\n        )\n        .set_index(\"Object ID\")\n    )\n\n    # change hemisphere names\n    df[\"hemisphere\"] = df[\"hemisphere\"].map(hemisphere_names)\n\n    # add object type\n    df[\"Object type\"] = \"Detection\"\n\n    # add brain regions\n    df = utils.add_brain_region(df, atlas, col=\"Parent\")\n\n    return df\n
"},{"location":"api-io.html#cuisto.io.check_empty_file","title":"check_empty_file(filename, threshold=1)","text":"

Checks if a file is empty.

Empty is defined as a file whose number of lines is lower than or equal to threshold (to allow for headers).

Parameters:

Name Type Description Default filename str

Full path to the file to check.

required threshold int

If number of lines is lower than or equal to this value, it is considered as empty. Default is 1.

1

Returns:

Name Type Description empty bool

True if the file is empty as defined above.

Source code in cuisto/io.py
def check_empty_file(filename: str, threshold: int = 1) -> bool:\n    \"\"\"\n    Checks if a file is empty.\n\n    Empty is defined as a file whose number of lines is lower than or equal to\n    `threshold` (to allow for headers).\n\n    Parameters\n    ----------\n    filename : str\n        Full path to the file to check.\n    threshold : int, optional\n        If number of lines is lower than or equal to this value, it is considered as\n        empty. Default is 1.\n\n    Returns\n    -------\n    empty : bool\n        True if the file is empty as defined above.\n\n    \"\"\"\n    with open(filename, \"rb\") as fid:\n        nlines = sum(1 for _ in fid)\n\n    if nlines <= threshold:\n        return True\n    else:\n        return False\n
"},{"location":"api-io.html#cuisto.io.get_measurements_directory","title":"get_measurements_directory(wdir, animal, kind, segtype)","text":"

Get the directory with detections or annotations measurements for given animal ID.

Parameters:

Name Type Description Default wdir str

Base working directory.

required animal str

Animal ID.

required kind str

\"annotation\" or \"detection\".

required segtype str

Type of segmentation, eg. \"synaptophysin\".

required

Returns:

Name Type Description directory str

Path to detections or annotations directory.

Source code in cuisto/io.py
def get_measurements_directory(wdir, animal: str, kind: str, segtype: str) -> str:\n    \"\"\"\n    Get the directory with detections or annotations measurements for given animal ID.\n\n    Parameters\n    ----------\n    wdir : str\n        Base working directory.\n    animal : str\n        Animal ID.\n    kind : str\n        \"annotation\" or \"detection\".\n    segtype : str\n        Type of segmentation, eg. \"synaptophysin\".\n\n    Returns\n    -------\n    directory : str\n        Path to detections or annotations directory.\n\n    \"\"\"\n    bdir = os.path.join(wdir, animal, animal.lower() + \"_segmentation\", segtype)\n\n    if (kind == \"detection\") or (kind == \"detections\"):\n        return os.path.join(bdir, \"detections\")\n    elif (kind == \"annotation\") or (kind == \"annotations\"):\n        return os.path.join(bdir, \"annotations\")\n    else:\n        raise ValueError(\n            f\"kind = '{kind}' not supported. Choose 'detection' or 'annotation'.\"\n        )\n
"},{"location":"api-io.html#cuisto.io.load_dfs","title":"load_dfs(filepath, fmt, identifiers=['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml'])","text":"

Load DataFrames from file.

If fmt is \"h5\" (\"xslx\"), identifiers are interpreted as h5 group identifier (sheet name, respectively). If fmt is \"pickle\", \"csv\" or \"tsv\", identifiers are appended to filename. Path to the file can't have a dot (\".\") in it.

Parameters:

Name Type Description Default filepath str

Full path to the file(s), without extension.

required fmt (h5, csv, pickle, xlsx)

File(s) format.

\"h5\" identifiers list of str

List of identifiers to load from files. Defaults to the ones saved in cuisto.process.process_animals().

['df_regions', 'df_coordinates', 'df_distribution_ap', 'df_distribution_dv', 'df_distribution_ml']

Returns:

Type Description All requested DataFrames. Source code in cuisto/io.py
def load_dfs(\n    filepath: str,\n    fmt: str,\n    identifiers: list[str] = [\n        \"df_regions\",\n        \"df_coordinates\",\n        \"df_distribution_ap\",\n        \"df_distribution_dv\",\n        \"df_distribution_ml\",\n    ],\n):\n    \"\"\"\n    Load DataFrames from file.\n\n    If `fmt` is \"h5\" (\"xslx\"), identifiers are interpreted as h5 group identifier (sheet\n    name, respectively).\n    If `fmt` is \"pickle\", \"csv\" or \"tsv\", identifiers are appended to `filename`.\n    Path to the file can't have a dot (\".\") in it.\n\n    Parameters\n    ----------\n    filepath : str\n        Full path to the file(s), without extension.\n    fmt : {\"h5\", \"csv\", \"pickle\", \"xlsx\"}\n        File(s) format.\n    identifiers : list of str, optional\n        List of identifiers to load from files. Defaults to the ones saved in\n        cuisto.process.process_animals().\n\n    Returns\n    -------\n    All requested DataFrames.\n\n    \"\"\"\n    # ensure filename without extension\n    base_path = os.path.splitext(filepath)[0]\n    full_path = base_path + \".\" + fmt\n\n    res = []\n    if (fmt == \"h5\") or (fmt == \"hdf\") or (fmt == \"hdf5\"):\n        for identifier in identifiers:\n            res.append(pd.read_hdf(full_path, identifier))\n    elif fmt == \"xlsx\":\n        for identifier in identifiers:\n            res.append(pd.read_excel(full_path, sheet_name=identifier))\n    else:\n        for identifier in identifiers:\n            id_path = f\"{base_path}_{identifier}.{fmt}\"\n            if (fmt == \"pickle\") or (fmt == \"pkl\"):\n                res.append(pd.read_pickle(id_path))\n            elif fmt == \"csv\":\n                res.append(pd.read_csv(id_path))\n            elif fmt == \"tsv\":\n                res.append(pd.read_csv(id_path, sep=\"\\t\"))\n            else:\n                raise ValueError(f\"{fmt} is not supported.\")\n\n    return res\n
"},{"location":"api-io.html#cuisto.io.save_dfs","title":"save_dfs(out_dir, filename, dfs)","text":"

Save DataFrames to file.

File format is inferred from file name extension.

Parameters:

Name Type Description Default out_dir str

Output directory.

required filename _type_

File name.

required dfs dict

DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in the same file, otherwise identifier is appended to the file name.

required Source code in cuisto/io.py
def save_dfs(out_dir: str, filename, dfs: dict):\n    \"\"\"\n    Save DataFrames to file.\n\n    File format is inferred from file name extension.\n\n    Parameters\n    ----------\n    out_dir : str\n        Output directory.\n    filename : _type_\n        File name.\n    dfs : dict\n        DataFrames to save, as {identifier: df}. If HDF5 or xlsx, all df are saved in\n        the same file, otherwise identifier is appended to the file name.\n\n    \"\"\"\n    if not os.path.isdir(out_dir):\n        os.makedirs(out_dir)\n\n    basename, ext = os.path.splitext(filename)\n    if ext in [\".h5\", \".hdf\", \".hdf5\"]:\n        path = os.path.join(out_dir, filename)\n        for identifier, df in dfs.items():\n            df.to_hdf(path, key=identifier)\n    elif ext == \".xlsx\":\n        for identifier, df in dfs.items():\n            df.to_excel(path, sheet_name=identifier)\n    else:\n        for identifier, df in dfs.items():\n            path = os.path.join(out_dir, f\"{basename}_{identifier}{ext}\")\n            if ext in [\".pickle\", \".pkl\"]:\n                df.to_pickle(path)\n            elif ext == \".csv\":\n                df.to_csv(path)\n            elif ext == \".tsv\":\n                df.to_csv(path, sep=\"\\t\")\n            else:\n                raise ValueError(f\"{filename} has an unsupported extension.\")\n
"},{"location":"api-process.html","title":"cuisto.process","text":"

process module, part of cuisto.

Wraps other functions for a click&play behaviour. Relies on the configuration file.

"},{"location":"api-process.html#cuisto.process.process_animal","title":"process_animal(animal, df_annotations, df_detections, cfg, compute_distributions=True)","text":"

Quantify objects for one animal.

Fetch required files and compute objects' distributions in brain regions, spatial distributions and gather Atlas coordinates.

Parameters:

Name Type Description Default animal str

Animal ID.

required df_annotations DataFrame

DataFrames of QuPath Annotations and Detections.

required df_detections DataFrame

DataFrames of QuPath Annotations and Detections.

required cfg Config

The configuration loaded from TOML configuration file.

required compute_distributions bool

If False, do not compute the 1D distributions and return an empty list.Default is True.

True

Returns:

Name Type Description df_regions DataFrame

Metrics in brain regions. One entry for each hemisphere of each brain regions.

df_distribution list of pandas.DataFrame

Rostro-caudal distribution, as raw count and probability density function, in each axis.

df_coordinates DataFrame

Atlas coordinates of each points.

Source code in cuisto/process.py
def process_animal(\n    animal: str,\n    df_annotations: pd.DataFrame,\n    df_detections: pd.DataFrame,\n    cfg,\n    compute_distributions: bool = True,\n) -> tuple[pd.DataFrame, list[pd.DataFrame], pd.DataFrame]:\n    \"\"\"\n    Quantify objects for one animal.\n\n    Fetch required files and compute objects' distributions in brain regions, spatial\n    distributions and gather Atlas coordinates.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    df_annotations, df_detections : pd.DataFrame\n        DataFrames of QuPath Annotations and Detections.\n    cfg : cuisto.Config\n        The configuration loaded from TOML configuration file.\n    compute_distributions : bool, optional\n        If False, do not compute the 1D distributions and return an empty list.Default\n        is True.\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        Metrics in brain regions. One entry for each hemisphere of each brain regions.\n    df_distribution : list of pandas.DataFrame\n        Rostro-caudal distribution, as raw count and probability density function, in\n        each axis.\n    df_coordinates : pandas.DataFrame\n        Atlas coordinates of each points.\n\n    \"\"\"\n    # - Annotations data cleanup\n    # filter regions\n    df_annotations = utils.filter_df_regions(\n        df_annotations, [\"Root\", \"root\"], mode=\"remove\", col=\"Name\"\n    )\n    df_annotations = utils.filter_df_regions(\n        df_annotations, cfg.atlas[\"blacklist\"], mode=\"remove\", col=\"Name\"\n    )\n    # add hemisphere\n    df_annotations = utils.add_hemisphere(df_annotations, cfg.hemispheres[\"names\"])\n    # remove objects in non-leaf regions\n    df_annotations = utils.filter_df_regions(\n        df_annotations, cfg.atlas[\"leaveslist\"], mode=\"keep\", col=\"Name\"\n    )\n    # merge regions\n    df_annotations = utils.merge_regions(\n        df_annotations, col=\"Name\", fusion_file=cfg.files[\"fusion\"]\n    )\n    if compute_distributions:\n        # - Detections data cleanup\n        # remove objects not in selected classifications\n        df_detections = utils.filter_df_classifications(\n            df_detections, cfg.object_type, mode=\"keep\", col=\"Classification\"\n        )\n        # remove objects from blacklisted regions and \"Root\"\n        df_detections = utils.filter_df_regions(\n            df_detections, cfg.atlas[\"blacklist\"], mode=\"remove\", col=\"Parent\"\n        )\n        # add hemisphere\n        df_detections = utils.add_hemisphere(\n            df_detections,\n            cfg.hemispheres[\"names\"],\n            cfg.atlas[\"midline\"],\n            col=\"Atlas_Z\",\n            atlas_type=cfg.atlas[\"type\"],\n        )\n        # add detection channel\n        df_detections = utils.add_channel(\n            df_detections, cfg.object_type, cfg.channels[\"names\"]\n        )\n        # convert coordinates to mm\n        df_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[\n            [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]\n        ].divide(1000)\n        # convert to sterotaxic coordinates\n        if cfg.distributions[\"stereo\"]:\n            (\n                df_detections[\"Atlas_AP\"],\n                df_detections[\"Atlas_DV\"],\n                df_detections[\"Atlas_ML\"],\n            ) = utils.ccf_to_stereo(\n                df_detections[\"Atlas_X\"],\n                df_detections[\"Atlas_Y\"],\n                df_detections[\"Atlas_Z\"],\n            )\n        else:\n            (\n                df_detections[\"Atlas_AP\"],\n                df_detections[\"Atlas_DV\"],\n                df_detections[\"Atlas_ML\"],\n            ) = (\n                df_detections[\"Atlas_X\"],\n                df_detections[\"Atlas_Y\"],\n                df_detections[\"Atlas_Z\"],\n            )\n\n    # - Computations\n    # get regions distributions\n    df_regions = compute.get_regions_metrics(\n        df_annotations,\n        cfg.object_type,\n        cfg.channels[\"names\"],\n        cfg.regions[\"base_measurement\"],\n        cfg.regions[\"metrics\"],\n    )\n    colstonorm = [v for v in cfg.regions[\"metrics\"].values() if \"relative\" not in v]\n\n    # normalize by starter cells\n    if cfg.regions[\"normalize_starter_cells\"]:\n        df_regions = compute.normalize_starter_cells(\n            df_regions, colstonorm, animal, cfg.files[\"infos\"], cfg.channels[\"names\"]\n        )\n\n    # get AP, DV, ML distributions in stereotaxic coordinates\n    if compute_distributions:\n        dfs_distributions = [\n            compute.get_distribution(\n                df_detections,\n                axis,\n                cfg.distributions[\"hue\"],\n                cfg.distributions[\"hue_filter\"],\n                cfg.distributions[\"common_norm\"],\n                stereo_lim,\n                nbins=nbins,\n            )\n            for axis, stereo_lim, nbins in zip(\n                [\"Atlas_AP\", \"Atlas_DV\", \"Atlas_ML\"],\n                [\n                    cfg.distributions[\"ap_lim\"],\n                    cfg.distributions[\"dv_lim\"],\n                    cfg.distributions[\"ml_lim\"],\n                ],\n                [\n                    cfg.distributions[\"ap_nbins\"],\n                    cfg.distributions[\"dv_nbins\"],\n                    cfg.distributions[\"dv_nbins\"],\n                ],\n            )\n        ]\n    else:\n        dfs_distributions = []\n\n    # add animal tag to each DataFrame\n    df_detections[\"animal\"] = animal\n    df_regions[\"animal\"] = animal\n    for df in dfs_distributions:\n        df[\"animal\"] = animal\n\n    return df_regions, dfs_distributions, df_detections\n
"},{"location":"api-process.html#cuisto.process.process_animals","title":"process_animals(wdir, animals, cfg, out_fmt=None, compute_distributions=True)","text":"

Get data from all animals and plot.

Parameters:

Name Type Description Default wdir str

Base working directory, containing animals folders.

required animals list-like of str

List of animals ID.

required cfg

Configuration object.

required out_fmt (None, h5, csv, tsv, xslx, pickle)

Output file(s) format, if None, nothing is saved (default).

None compute_distributions bool

If False, do not compute the 1D distributions and return an empty list.Default is True.

True

Returns:

Name Type Description df_regions DataFrame

Metrics in brain regions. One entry for each hemisphere of each brain regions.

df_distribution list of pandas.DataFrame

Rostro-caudal distribution, as raw count and probability density function, in each axis.

df_coordinates DataFrame

Atlas coordinates of each points.

Source code in cuisto/process.py
def process_animals(\n    wdir: str,\n    animals: list[str] | tuple[str],\n    cfg,\n    out_fmt: str | None = None,\n    compute_distributions: bool = True,\n) -> tuple[pd.DataFrame]:\n    \"\"\"\n    Get data from all animals and plot.\n\n    Parameters\n    ----------\n    wdir : str\n        Base working directory, containing `animals` folders.\n    animals : list-like of str\n        List of animals ID.\n    cfg: cuisto.Config\n        Configuration object.\n    out_fmt : {None, \"h5\", \"csv\", \"tsv\", \"xslx\", \"pickle\"}\n        Output file(s) format, if None, nothing is saved (default).\n    compute_distributions : bool, optional\n        If False, do not compute the 1D distributions and return an empty list.Default\n        is True.\n\n\n    Returns\n    -------\n    df_regions : pandas.DataFrame\n        Metrics in brain regions. One entry for each hemisphere of each brain regions.\n    df_distribution : list of pandas.DataFrame\n        Rostro-caudal distribution, as raw count and probability density function, in\n        each axis.\n    df_coordinates : pandas.DataFrame\n        Atlas coordinates of each points.\n\n    \"\"\"\n\n    # -- Preparation\n    df_regions = []\n    dfs_distributions = []\n    df_coordinates = []\n\n    # -- Processing\n    pbar = tqdm(animals)\n\n    for animal in pbar:\n        pbar.set_description(f\"Processing {animal}\")\n\n        # combine all detections and annotations from this animal\n        df_annotations = io.cat_csv_dir(\n            io.get_measurements_directory(\n                wdir, animal, \"annotation\", cfg.segmentation_tag\n            ),\n            index_col=\"Object ID\",\n            sep=\"\\t\",\n        )\n        if compute_distributions:\n            df_detections = io.cat_data_dir(\n                io.get_measurements_directory(\n                    wdir, animal, \"detection\", cfg.segmentation_tag\n                ),\n                cfg.segmentation_tag,\n                index_col=\"Object ID\",\n                sep=\"\\t\",\n                hemisphere_names=cfg.hemispheres[\"names\"],\n                atlas=cfg.bg_atlas,\n            )\n        else:\n            df_detections = pd.DataFrame()\n\n        # get results\n        df_reg, dfs_dis, df_coo = process_animal(\n            animal,\n            df_annotations,\n            df_detections,\n            cfg,\n            compute_distributions=compute_distributions,\n        )\n\n        # collect results\n        df_regions.append(df_reg)\n        dfs_distributions.append(dfs_dis)\n        df_coordinates.append(df_coo)\n\n    # concatenate all results\n    df_regions = pd.concat(df_regions, ignore_index=True)\n    dfs_distributions = [\n        pd.concat(dfs_list, ignore_index=True) for dfs_list in zip(*dfs_distributions)\n    ]\n    df_coordinates = pd.concat(df_coordinates, ignore_index=True)\n\n    # -- Saving\n    if out_fmt:\n        outdir = os.path.join(wdir, \"quantification\")\n        outfile = f\"{cfg.object_type.lower()}_{cfg.atlas[\"type\"]}_{'-'.join(animals)}.{out_fmt}\"\n        dfs = dict(\n            df_regions=df_regions,\n            df_coordinates=df_coordinates,\n            df_distribution_ap=dfs_distributions[0],\n            df_distribution_dv=dfs_distributions[1],\n            df_distribution_ml=dfs_distributions[2],\n        )\n        io.save_dfs(outdir, outfile, dfs)\n\n    return df_regions, dfs_distributions, df_coordinates\n
"},{"location":"api-script-qupath-script-runner.html","title":"qupath_script_runner","text":"

Template to show how to run groovy script with QuPath, multi-threaded.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.EXCLUDE_LIST","title":"EXCLUDE_LIST = [] module-attribute","text":"

Images names to NOT run the script on.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.NTHREADS","title":"NTHREADS = 5 module-attribute","text":"

Number of threads to use.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QPROJ_PATH","title":"QPROJ_PATH = '/path/to/qupath/project.qproj' module-attribute","text":"

Full path to the QuPath project.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QUIET","title":"QUIET = True module-attribute","text":"

Use QuPath in quiet mode, eg. with minimal verbosity.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.QUPATH_EXE","title":"QUPATH_EXE = '/path/to/the/qupath/QuPath-0.5.1 (console).exe' module-attribute","text":"

Path to the QuPath executable (console mode).

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.SAVE","title":"SAVE = True module-attribute","text":"

Whether to save the project after the script ran on an image.

"},{"location":"api-script-qupath-script-runner.html#scripts.qupath_script_template.SCRIPT_PATH","title":"SCRIPT_PATH = '/path/to/the/script.groovy' module-attribute","text":"

Path to the groovy script.

"},{"location":"api-script-segment.html","title":"segment_images","text":"

Script to segment objects from images.

For fiber-like objects, binarize and skeletonize the image, then use skan to extract branches coordinates. For polygon-like objects, binarize the image and detect objects and extract contours coordinates. For points, treat that as polygons then extract the centroids instead of contours. Finally, export the coordinates as collections in geojson files, importable in QuPath. Supports any number of channel of interest within the same image. One file output file per channel will be created.

This script uses cuisto.seg. It is designed to work on probability maps generated from a pixel classifier in QuPath, but might work on raw images.

Usage : fill-in the Parameters section of the script and run it. A \"geojson\" folder will be created in the parent directory of IMAGES_DIR. To exclude objects near the edges of an ROI, specify the path to masks stored as images with the same names as probabilities images (without their suffix).

author : Guillaume Le Goc (g.legoc@posteo.org) @ NeuroPSI version : 2024.12.10

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.CHANNELS_PARAMS","title":"CHANNELS_PARAMS = [{'name': 'cy5', 'target_channel': 0, 'proba_threshold': 0.85, 'qp_class': 'Fibers: Cy5', 'qp_color': [164, 250, 120]}, {'name': 'dsred', 'target_channel': 1, 'proba_threshold': 0.65, 'qp_class': 'Fibers: DsRed', 'qp_color': [224, 153, 18]}, {'name': 'egfp', 'target_channel': 2, 'proba_threshold': 0.85, 'qp_class': 'Fibers: EGFP', 'qp_color': [135, 11, 191]}] module-attribute","text":"

This should be a list of dictionary (one per channel) with keys :

  • name: str, used as suffix for output geojson files, not used if only one channel
  • target_channel: int, index of the segmented channel of the image, 0-based
  • proba_threshold: float < 1, probability cut-off for that channel
  • qp_class: str, name of QuPath classification
  • qp_color: list of RGB values, associated color
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.EDGE_DIST","title":"EDGE_DIST = 0 module-attribute","text":"

Distance to brain edge to ignore, in \u00b5m. 0 to disable.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.FILTERS","title":"FILTERS = {'length_low': 1.5, 'area_low': 10, 'area_high': 1000, 'ecc_low': 0.0, 'ecc_high': 0.9, 'dist_thresh': 30} module-attribute","text":"

Dictionary with keys :

  • length_low: minimal length in microns - for lines
  • area_low: minimal area in \u00b5m\u00b2 - for polygons and points
  • area_high: maximal area in \u00b5m\u00b2 - for polygons and points
  • ecc_low: minimal eccentricity - for polygons and points (0 = circle)
  • ecc_high: maximal eccentricity - for polygons and points (1 = line)
  • dist_thresh: maximal inter-point distance in \u00b5m - for points
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.IMAGES_DIR","title":"IMAGES_DIR = '/path/to/images' module-attribute","text":"

Full path to the images to segment.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.IMG_SUFFIX","title":"IMG_SUFFIX = '_Probabilities.tiff' module-attribute","text":"

Images suffix, including extension. Masks must be the same name without the suffix.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MASKS_DIR","title":"MASKS_DIR = 'path/to/corresponding/masks' module-attribute","text":"

Full path to the masks, to exclude objects near the brain edges (set to None or empty string to disable this feature).

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MASKS_EXT","title":"MASKS_EXT = 'tiff' module-attribute","text":"

Masks files extension.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.MAX_PIX_VALUE","title":"MAX_PIX_VALUE = 255 module-attribute","text":"

Maximum pixel possible value to adjust proba_threshold.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.ORIGINAL_PIXELSIZE","title":"ORIGINAL_PIXELSIZE = 0.45 module-attribute","text":"

Original images pixel size in microns. This is in case the pixel classifier uses a lower resolution, yielding smaller probability maps, so output objects coordinates need to be rescaled to the full size images. The pixel size is written in the \"Image\" tab in QuPath.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.QUPATH_TYPE","title":"QUPATH_TYPE = 'detection' module-attribute","text":"

QuPath object type.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.SEGTYPE","title":"SEGTYPE = 'boutons' module-attribute","text":"

Type of segmentation.

"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_geojson_dir","title":"get_geojson_dir(images_dir)","text":"

Get the directory of geojson files, which will be in the parent directory of images_dir.

If the directory does not exist, create it.

Parameters:

Name Type Description Default images_dir str required

Returns:

Name Type Description geojson_dir str Source code in scripts/segmentation/segment_images.py
def get_geojson_dir(images_dir: str):\n    \"\"\"\n    Get the directory of geojson files, which will be in the parent directory\n    of `images_dir`.\n\n    If the directory does not exist, create it.\n\n    Parameters\n    ----------\n    images_dir : str\n\n    Returns\n    -------\n    geojson_dir : str\n\n    \"\"\"\n\n    geojson_dir = os.path.join(Path(images_dir).parent, \"geojson\")\n\n    if not os.path.isdir(geojson_dir):\n        os.mkdir(geojson_dir)\n\n    return geojson_dir\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_geojson_properties","title":"get_geojson_properties(name, color, objtype='detection')","text":"

Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.

Parameters:

Name Type Description Default name str

Classification name.

required color tuple or list

Classification color in RGB (3-elements vector).

required objtype str

Object type (\"detection\" or \"annotation\"). Default is \"detection\".

'detection'

Returns:

Name Type Description props dict Source code in scripts/segmentation/segment_images.py
def get_geojson_properties(name: str, color: tuple | list, objtype: str = \"detection\"):\n    \"\"\"\n    Return geojson objects properties as a dictionnary, ready to be used in geojson.Feature.\n\n    Parameters\n    ----------\n    name : str\n        Classification name.\n    color : tuple or list\n        Classification color in RGB (3-elements vector).\n    objtype : str, optional\n        Object type (\"detection\" or \"annotation\"). Default is \"detection\".\n\n    Returns\n    -------\n    props : dict\n\n    \"\"\"\n\n    return {\n        \"objectType\": objtype,\n        \"classification\": {\"name\": name, \"color\": color},\n        \"isLocked\": \"true\",\n    }\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.get_seg_method","title":"get_seg_method(segtype)","text":"

Determine what kind of segmentation is performed.

Segmentation kind are, for now, lines, polygons or points. We detect that based on hardcoded keywords.

Parameters:

Name Type Description Default segtype str required

Returns:

Name Type Description seg_method str Source code in scripts/segmentation/segment_images.py
def get_seg_method(segtype: str):\n    \"\"\"\n    Determine what kind of segmentation is performed.\n\n    Segmentation kind are, for now, lines, polygons or points. We detect that based on\n    hardcoded keywords.\n\n    Parameters\n    ----------\n    segtype : str\n\n    Returns\n    -------\n    seg_method : str\n\n    \"\"\"\n\n    line_list = [\"fibers\", \"axons\", \"fiber\", \"axon\"]\n    point_list = [\"synapto\", \"synaptophysin\", \"syngfp\", \"boutons\", \"points\"]\n    polygon_list = [\"cells\", \"polygon\", \"polygons\", \"polygon\", \"cell\"]\n\n    if segtype in line_list:\n        seg_method = \"lines\"\n    elif segtype in polygon_list:\n        seg_method = \"polygons\"\n    elif segtype in point_list:\n        seg_method = \"points\"\n    else:\n        raise ValueError(\n            f\"Could not determine method to use based on segtype : {segtype}.\"\n        )\n\n    return seg_method\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.parameters_as_dict","title":"parameters_as_dict(images_dir, masks_dir, segtype, name, proba_threshold, edge_dist)","text":"

Get information as a dictionnary.

Parameters:

Name Type Description Default images_dir str

Path to images to be segmented.

required masks_dir str

Path to images masks.

required segtype str

Segmentation type (eg. \"fibers\").

required name str

Name of the segmentation (eg. \"green\").

required proba_threshold float < 1

Probability threshold.

required edge_dist float

Distance in \u00b5m to the brain edge that is ignored.

required

Returns:

Name Type Description params dict Source code in scripts/segmentation/segment_images.py
def parameters_as_dict(\n    images_dir: str,\n    masks_dir: str,\n    segtype: str,\n    name: str,\n    proba_threshold: float,\n    edge_dist: float,\n):\n    \"\"\"\n    Get information as a dictionnary.\n\n    Parameters\n    ----------\n    images_dir : str\n        Path to images to be segmented.\n    masks_dir : str\n        Path to images masks.\n    segtype : str\n        Segmentation type (eg. \"fibers\").\n    name : str\n        Name of the segmentation (eg. \"green\").\n    proba_threshold : float < 1\n        Probability threshold.\n    edge_dist : float\n        Distance in \u00b5m to the brain edge that is ignored.\n\n    Returns\n    -------\n    params : dict\n\n    \"\"\"\n\n    return {\n        \"images_location\": images_dir,\n        \"masks_location\": masks_dir,\n        \"type\": segtype,\n        \"probability threshold\": proba_threshold,\n        \"name\": name,\n        \"edge distance\": edge_dist,\n    }\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.process_directory","title":"process_directory(images_dir, img_suffix='', segtype='', original_pixelsize=1.0, target_channel=0, proba_threshold=0.0, qupath_class='Object', qupath_color=[0, 0, 0], channel_suffix='', edge_dist=0.0, filters={}, masks_dir='', masks_ext='')","text":"

Main function, processes the .ome.tiff files in the input directory.

Parameters:

Name Type Description Default images_dir str

Animal ID to process.

required img_suffix str

Images suffix, including extension.

'' segtype str

Segmentation type.

'' original_pixelsize float

Original images pixel size in microns.

1.0 target_channel int

Index of the channel containning the objects of interest (eg. not the background), in the probability map (not the original images channels).

0 proba_threshold float < 1

Probability below this value will be discarded (multiplied by MAX_PIXEL_VALUE)

0.0 qupath_class str

Name of the QuPath classification.

'Object' qupath_color list of three elements

Color associated to that classification in RGB.

[0, 0, 0] channel_suffix str

Channel name, will be used as a suffix in output geojson files.

'' edge_dist float

Distance to the edge of the brain masks that will be ignored, in microns. Set to 0 to disable this feature.

0.0 filters dict

Filters values to include or excludes objects. See the top of the script.

{} masks_dir str

Path to images masks, to exclude objects found near the edges. The masks must be with the same name as the corresponding image to be segmented, without its suffix. Default is \"\", which disables this feature.

'' masks_ext str

Masks files extension, without leading \".\". Default is \"\"

'' Source code in scripts/segmentation/segment_images.py
def process_directory(\n    images_dir: str,\n    img_suffix: str = \"\",\n    segtype: str = \"\",\n    original_pixelsize: float = 1.0,\n    target_channel: int = 0,\n    proba_threshold: float = 0.0,\n    qupath_class: str = \"Object\",\n    qupath_color: list = [0, 0, 0],\n    channel_suffix: str = \"\",\n    edge_dist: float = 0.0,\n    filters: dict = {},\n    masks_dir: str = \"\",\n    masks_ext: str = \"\",\n):\n    \"\"\"\n    Main function, processes the .ome.tiff files in the input directory.\n\n    Parameters\n    ----------\n    images_dir : str\n        Animal ID to process.\n    img_suffix : str\n        Images suffix, including extension.\n    segtype : str\n        Segmentation type.\n    original_pixelsize : float\n        Original images pixel size in microns.\n    target_channel : int\n        Index of the channel containning the objects of interest (eg. not the\n        background), in the probability map (*not* the original images channels).\n    proba_threshold : float < 1\n        Probability below this value will be discarded (multiplied by `MAX_PIXEL_VALUE`)\n    qupath_class : str\n        Name of the QuPath classification.\n    qupath_color : list of three elements\n        Color associated to that classification in RGB.\n    channel_suffix : str\n        Channel name, will be used as a suffix in output geojson files.\n    edge_dist : float\n        Distance to the edge of the brain masks that will be ignored, in microns. Set to\n        0 to disable this feature.\n    filters : dict\n        Filters values to include or excludes objects. See the top of the script.\n    masks_dir : str, optional\n        Path to images masks, to exclude objects found near the edges. The masks must be\n        with the same name as the corresponding image to be segmented, without its\n        suffix. Default is \"\", which disables this feature.\n    masks_ext : str, optional\n        Masks files extension, without leading \".\". Default is \"\"\n\n    \"\"\"\n\n    # -- Preparation\n    # get segmentation type\n    seg_method = get_seg_method(segtype)\n\n    # get output directory path\n    geojson_dir = get_geojson_dir(images_dir)\n\n    # get images list\n    images_list = [\n        os.path.join(images_dir, filename)\n        for filename in os.listdir(images_dir)\n        if filename.endswith(img_suffix)\n    ]\n\n    # write parameters\n    parameters = parameters_as_dict(\n        images_dir, masks_dir, segtype, channel_suffix, proba_threshold, edge_dist\n    )\n    param_file = os.path.join(geojson_dir, \"parameters\" + channel_suffix + \".txt\")\n    if os.path.isfile(param_file):\n        raise FileExistsError(\"Parameters file already exists.\")\n    else:\n        write_parameters(param_file, parameters, filters, original_pixelsize)\n\n    # convert parameters to pixels in probability map\n    pixelsize = hq.seg.get_pixelsize(images_list[0])  # get pixel size\n    edge_dist = int(edge_dist / pixelsize)\n    filters = hq.seg.convert_to_pixels(filters, pixelsize)\n\n    # get rescaling factor\n    rescale_factor = pixelsize / original_pixelsize\n\n    # get GeoJSON properties\n    geojson_props = get_geojson_properties(\n        qupath_class, qupath_color, objtype=QUPATH_TYPE\n    )\n\n    # -- Processing\n    pbar = tqdm(images_list)\n    for imgpath in pbar:\n        # build file names\n        imgname = os.path.basename(imgpath)\n        geoname = imgname.replace(img_suffix, \"\")\n        geojson_file = os.path.join(\n            geojson_dir, geoname + \"_segmentation\" + channel_suffix + \".geojson\"\n        )\n\n        # checks if output file already exists\n        if os.path.isfile(geojson_file):\n            continue\n\n        # read images\n        pbar.set_description(f\"{geoname}: Loading...\")\n        img = tifffile.imread(imgpath, key=target_channel)\n        if (edge_dist > 0) & (len(masks_dir) != 0):\n            mask = tifffile.imread(os.path.join(masks_dir, geoname + \".\" + masks_ext))\n            mask = hq.seg.pad_image(mask, img.shape)  # resize mask\n            # apply mask, eroding from the edges\n            img = img * hq.seg.erode_mask(mask, edge_dist)\n\n        # image processing\n        pbar.set_description(f\"{geoname}: IP...\")\n\n        # threshold probability and binarization\n        img = img >= proba_threshold * MAX_PIX_VALUE\n\n        # segmentation\n        pbar.set_description(f\"{geoname}: Segmenting...\")\n\n        if seg_method == \"lines\":\n            collection = hq.seg.segment_lines(\n                img,\n                geojson_props,\n                minsize=filters[\"length_low\"],\n                rescale_factor=rescale_factor,\n            )\n\n        elif seg_method == \"polygons\":\n            collection = hq.seg.segment_polygons(\n                img,\n                geojson_props,\n                area_min=filters[\"area_low\"],\n                area_max=filters[\"area_high\"],\n                ecc_min=filters[\"ecc_low\"],\n                ecc_max=filters[\"ecc_high\"],\n                rescale_factor=rescale_factor,\n            )\n\n        elif seg_method == \"points\":\n            collection = hq.seg.segment_points(\n                img,\n                geojson_props,\n                area_min=filters[\"area_low\"],\n                area_max=filters[\"area_high\"],\n                ecc_min=filters[\"ecc_low\"],\n                ecc_max=filters[\"ecc_high\"],\n                dist_thresh=filters[\"dist_thresh\"],\n                rescale_factor=rescale_factor,\n            )\n        else:\n            # we already printed an error message\n            return\n\n        # save geojson\n        pbar.set_description(f\"{geoname}: Saving...\")\n        with open(geojson_file, \"w\") as fid:\n            fid.write(geojson.dumps(collection))\n
"},{"location":"api-script-segment.html#scripts.segmentation.segment_images.write_parameters","title":"write_parameters(outfile, parameters, filters, original_pixelsize)","text":"

Write parameters to outfile.

A timestamp will be added. Parameters are written as key = value, and a [filters] is added before filters parameters.

Parameters:

Name Type Description Default outfile str

Full path to the output file.

required parameters dict

General parameters.

required filters dict

Filters parameters.

required original_pixelsize float

Size of pixels in original image.

required Source code in scripts/segmentation/segment_images.py
def write_parameters(\n    outfile: str, parameters: dict, filters: dict, original_pixelsize: float\n):\n    \"\"\"\n    Write parameters to `outfile`.\n\n    A timestamp will be added. Parameters are written as key = value,\n    and a [filters] is added before filters parameters.\n\n    Parameters\n    ----------\n    outfile : str\n        Full path to the output file.\n    parameters : dict\n        General parameters.\n    filters : dict\n        Filters parameters.\n    original_pixelsize : float\n        Size of pixels in original image.\n\n    \"\"\"\n\n    with open(outfile, \"w\") as fid:\n        fid.writelines(f\"date = {datetime.now().strftime('%d-%B-%Y %H:%M:%S')}\\n\")\n\n        fid.writelines(f\"original_pixelsize = {original_pixelsize}\\n\")\n\n        for key, value in parameters.items():\n            fid.writelines(f\"{key} = {value}\\n\")\n\n        fid.writelines(\"[filters]\\n\")\n\n        for key, value in filters.items():\n            fid.writelines(f\"{key} = {value}\\n\")\n
"},{"location":"api-seg.html","title":"cuisto.seg","text":"

seg module, part of cuisto.

Functions for segmentating probability map stored as an image.

"},{"location":"api-seg.html#cuisto.seg.convert_to_pixels","title":"convert_to_pixels(filters, pixelsize)","text":"

Convert some values in filters in pixels.

Parameters:

Name Type Description Default filters dict

Must contain the keys used below.

required pixelsize float

Pixel size in microns.

required

Returns:

Name Type Description filters dict

Same as input, with values in pixels.

Source code in cuisto/seg.py
def convert_to_pixels(filters, pixelsize):\n    \"\"\"\n    Convert some values in `filters` in pixels.\n\n    Parameters\n    ----------\n    filters : dict\n        Must contain the keys used below.\n    pixelsize : float\n        Pixel size in microns.\n\n    Returns\n    -------\n    filters : dict\n        Same as input, with values in pixels.\n\n    \"\"\"\n\n    filters[\"area_low\"] = filters[\"area_low\"] / pixelsize**2\n    filters[\"area_high\"] = filters[\"area_high\"] / pixelsize**2\n    filters[\"length_low\"] = filters[\"length_low\"] / pixelsize\n    filters[\"dist_thresh\"] = int(filters[\"dist_thresh\"] / pixelsize)\n\n    return filters\n
"},{"location":"api-seg.html#cuisto.seg.erode_mask","title":"erode_mask(mask, edge_dist)","text":"

Erode the mask outline so that is is edge_dist smaller from the border.

This allows discarding the edges.

Parameters:

Name Type Description Default mask ndarray required edge_dist float

Distance to edges, in pixels.

required

Returns:

Name Type Description eroded_mask ndarray of bool Source code in cuisto/seg.py
def erode_mask(mask: np.ndarray, edge_dist: float) -> np.ndarray:\n    \"\"\"\n    Erode the mask outline so that is is `edge_dist` smaller from the border.\n\n    This allows discarding the edges.\n\n    Parameters\n    ----------\n    mask : ndarray\n    edge_dist : float\n        Distance to edges, in pixels.\n\n    Returns\n    -------\n    eroded_mask : ndarray of bool\n\n    \"\"\"\n\n    if edge_dist % 2 == 0:\n        edge_dist += 1  # decomposition requires even number\n\n    footprint = morphology.square(edge_dist, decomposition=\"sequence\")\n\n    return mask * morphology.binary_erosion(mask, footprint=footprint)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_points","title":"get_collection_from_points(coords, properties, rescale_factor=1.0, offset=0.5)","text":"

Gather coordinates from coords and put them in GeoJSON format.

An entry in coords are pairs of (x, y) coordinates defining the point. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default coords list required properties dict required rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection Source code in cuisto/seg.py
def get_collection_from_points(\n    coords: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Gather coordinates from `coords` and put them in GeoJSON format.\n\n    An entry in `coords` are pairs of (x, y) coordinates defining the point.\n    `properties` is a dictionnary with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    coords : list\n    properties : dict\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n\n    \"\"\"\n\n    collection = [\n        geojson.Feature(\n            geometry=shapely.Point(\n                np.flip((coord + offset) * rescale_factor)\n            ),  # shape object\n            properties=properties,  # object properties\n            id=str(uuid.uuid4()),  # object uuid\n        )\n        for coord in coords\n    ]\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_poly","title":"get_collection_from_poly(contours, properties, rescale_factor=1.0, offset=0.5)","text":"

Gather coordinates in the list and put them in GeoJSON format as Polygons.

An entry in contours must define a closed polygon. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default contours list required properties dict

QuPatj objects' properties.

required rescale_factor float

Rescale output coordinates by this factor.

1.0 offset float

Shift coordinates by this amount, typically to get pixel centers or edges. Default is 0.5.

0.5

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def get_collection_from_poly(\n    contours: list, properties: dict, rescale_factor: float = 1.0, offset: float = 0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Gather coordinates in the list and put them in GeoJSON format as Polygons.\n\n    An entry in `contours` must define a closed polygon. `properties` is a dictionnary\n    with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    contours : list\n    properties : dict\n        QuPatj objects' properties.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n    offset : float\n        Shift coordinates by this amount, typically to get pixel centers or edges.\n        Default is 0.5.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n    collection = [\n        geojson.Feature(\n            geometry=shapely.Polygon(\n                np.fliplr((contour + offset) * rescale_factor)\n            ),  # shape object\n            properties=properties,  # object properties\n            id=str(uuid.uuid4()),  # object uuid\n        )\n        for contour in contours\n    ]\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_collection_from_skel","title":"get_collection_from_skel(skeleton, properties, rescale_factor=1.0, offset=0.5)","text":"

Get the coordinates of each skeleton path as a GeoJSON Features in a FeatureCollection. properties is a dictionnary with QuPath properties of each detections.

Parameters:

Name Type Description Default skeleton Skeleton required properties dict

QuPatj objects' properties.

required rescale_factor float

Rescale output coordinates by this factor.

1.0 offset float

Shift coordinates by this amount, typically to get pixel centers or edges. Default is 0.5.

0.5

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def get_collection_from_skel(\n    skeleton: Skeleton, properties: dict, rescale_factor: float = 1.0, offset=0.5\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Get the coordinates of each skeleton path as a GeoJSON Features in a\n    FeatureCollection.\n    `properties` is a dictionnary with QuPath properties of each detections.\n\n    Parameters\n    ----------\n    skeleton : skan.Skeleton\n    properties : dict\n        QuPatj objects' properties.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n    offset : float\n        Shift coordinates by this amount, typically to get pixel centers or edges.\n        Default is 0.5.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    branch_data = summarize(skeleton, separator=\"_\")\n\n    collection = []\n    for ind in range(skeleton.n_paths):\n        prop = properties.copy()\n        prop[\"measurements\"] = {\"skeleton_id\": int(branch_data.loc[ind, \"skeleton_id\"])}\n        collection.append(\n            geojson.Feature(\n                geometry=shapely.LineString(\n                    (skeleton.path_coordinates(ind)[:, ::-1] + offset) * rescale_factor\n                ),  # shape object\n                properties=prop,  # object properties\n                id=str(uuid.uuid4()),  # object uuid\n            )\n        )\n\n    return geojson.FeatureCollection(collection)\n
"},{"location":"api-seg.html#cuisto.seg.get_image_skeleton","title":"get_image_skeleton(img, minsize=0)","text":"

Get the image skeleton.

Computes the image skeleton and removes objects smaller than minsize.

Parameters:

Name Type Description Default img ndarray of bool required minsize number

Min. size the object can have, as a number of pixels. Default is 0.

0

Returns:

Name Type Description skel ndarray of bool

Binary image with 1-pixel wide skeleton.

Source code in cuisto/seg.py
def get_image_skeleton(img: np.ndarray, minsize=0) -> np.ndarray:\n    \"\"\"\n    Get the image skeleton.\n\n    Computes the image skeleton and removes objects smaller than `minsize`.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n    minsize : number, optional\n        Min. size the object can have, as a number of pixels. Default is 0.\n\n    Returns\n    -------\n    skel : ndarray of bool\n        Binary image with 1-pixel wide skeleton.\n\n    \"\"\"\n\n    skel = morphology.skeletonize(img)\n\n    return morphology.remove_small_objects(skel, min_size=minsize, connectivity=2)\n
"},{"location":"api-seg.html#cuisto.seg.get_pixelsize","title":"get_pixelsize(image_name)","text":"

Get pixel size recorded in image_name TIFF metadata.

Parameters:

Name Type Description Default image_name str

Full path to image.

required

Returns:

Name Type Description pixelsize float

Pixel size in microns.

Source code in cuisto/seg.py
def get_pixelsize(image_name: str) -> float:\n    \"\"\"\n    Get pixel size recorded in `image_name` TIFF metadata.\n\n    Parameters\n    ----------\n    image_name : str\n        Full path to image.\n\n    Returns\n    -------\n    pixelsize : float\n        Pixel size in microns.\n\n    \"\"\"\n\n    with tifffile.TiffFile(image_name) as tif:\n        # XResolution is a tuple, numerator, denomitor. The inverse is the pixel size\n        return (\n            tif.pages[0].tags[\"XResolution\"].value[1]\n            / tif.pages[0].tags[\"XResolution\"].value[0]\n        )\n
"},{"location":"api-seg.html#cuisto.seg.pad_image","title":"pad_image(img, finalsize)","text":"

Pad image with zeroes to match expected final size.

Parameters:

Name Type Description Default img ndarray required finalsize tuple or list

nrows, ncolumns

required

Returns:

Name Type Description imgpad ndarray

img with black borders.

Source code in cuisto/seg.py
def pad_image(img: np.ndarray, finalsize: tuple | list) -> np.ndarray:\n    \"\"\"\n    Pad image with zeroes to match expected final size.\n\n    Parameters\n    ----------\n    img : ndarray\n    finalsize : tuple or list\n        nrows, ncolumns\n\n    Returns\n    -------\n    imgpad : ndarray\n        img with black borders.\n\n    \"\"\"\n\n    final_h = finalsize[0]  # requested number of rows (height)\n    final_w = finalsize[1]  # requested number of columns (width)\n    original_h = img.shape[0]  # input number of rows\n    original_w = img.shape[1]  # input number of columns\n\n    a = (final_h - original_h) // 2  # vertical padding before\n    aa = final_h - a - original_h  # vertical padding after\n    b = (final_w - original_w) // 2  # horizontal padding before\n    bb = final_w - b - original_w  # horizontal padding after\n\n    return np.pad(img, pad_width=((a, aa), (b, bb)), mode=\"constant\")\n
"},{"location":"api-seg.html#cuisto.seg.segment_lines","title":"segment_lines(img, geojson_props, minsize=0.0, rescale_factor=1.0)","text":"

Wraps skeleton analysis to get paths coordinates.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as lines.

required geojson_props dict

GeoJSON properties of objects.

required minsize float

Minimum size in pixels for an object.

0.0 rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_lines(\n    img: np.ndarray, geojson_props: dict, minsize=0.0, rescale_factor=1.0\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Wraps skeleton analysis to get paths coordinates.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as lines.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    minsize : float\n        Minimum size in pixels for an object.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    skel = get_image_skeleton(img, minsize=minsize)\n\n    # get paths coordinates as FeatureCollection\n    skeleton = Skeleton(skel, keep_images=False)\n    return get_collection_from_skel(\n        skeleton, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-seg.html#cuisto.seg.segment_points","title":"segment_points(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0, ecc_max=1, dist_thresh=0, rescale_factor=1)","text":"

Point segmentation.

First, segment polygons to apply shape filters, then extract their centroids, and remove isolated points as defined by dist_thresh.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as points.

required geojson_props dict

GeoJSON properties of objects.

required area_min float

Minimum and maximum area in pixels for an object.

0.0 area_max float

Minimum and maximum area in pixels for an object.

0.0 ecc_min float

Minimum and maximum eccentricity for an object.

0 ecc_max float

Minimum and maximum eccentricity for an object.

0 dist_thresh float

Maximal distance in pixels between objects before considering them as isolated and remove them. 0 disables it.

0 rescale_factor float

Rescale output coordinates by this factor.

1

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_points(\n    img: np.ndarray,\n    geojson_props: dict,\n    area_min: float = 0.0,\n    area_max: float = np.inf,\n    ecc_min: float = 0,\n    ecc_max: float = 1,\n    dist_thresh: float = 0,\n    rescale_factor: float = 1,\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Point segmentation.\n\n    First, segment polygons to apply shape filters, then extract their centroids,\n    and remove isolated points as defined by `dist_thresh`.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as points.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    area_min, area_max : float\n        Minimum and maximum area in pixels for an object.\n    ecc_min, ecc_max : float\n        Minimum and maximum eccentricity for an object.\n    dist_thresh : float\n        Maximal distance in pixels between objects before considering them as isolated and remove them.\n        0 disables it.\n    rescale_factor : float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    # get objects properties\n    stats = pd.DataFrame(\n        measure.regionprops_table(\n            measure.label(img), properties=(\"label\", \"area\", \"eccentricity\", \"centroid\")\n        )\n    )\n\n    # keep objects matching filters\n    stats = stats[\n        (stats[\"area\"] >= area_min)\n        & (stats[\"area\"] <= area_max)\n        & (stats[\"eccentricity\"] >= ecc_min)\n        & (stats[\"eccentricity\"] <= ecc_max)\n    ]\n\n    # create an image from centroids only\n    stats[\"centroid-0\"] = stats[\"centroid-0\"].astype(int)\n    stats[\"centroid-1\"] = stats[\"centroid-1\"].astype(int)\n    bw = np.zeros(img.shape, dtype=bool)\n    bw[stats[\"centroid-0\"], stats[\"centroid-1\"]] = True\n\n    # filter isolated objects\n    if dist_thresh:\n        # dilation of points\n        if dist_thresh % 2 == 0:\n            dist_thresh += 1  # decomposition requires even number\n\n        footprint = morphology.square(int(dist_thresh), decomposition=\"sequence\")\n        dilated = measure.label(morphology.binary_dilation(bw, footprint=footprint))\n        stats = pd.DataFrame(\n            measure.regionprops_table(dilated, properties=(\"label\", \"area\"))\n        )\n\n        # objects that did not merge are alone\n        toremove = stats[(stats[\"area\"] <= dist_thresh**2)]\n        dilated[np.isin(dilated, toremove[\"label\"])] = 0  # remove them\n\n        # apply mask\n        bw = bw * dilated\n\n    # get points coordinates\n    coords = np.argwhere(bw)\n\n    return get_collection_from_points(\n        coords, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-seg.html#cuisto.seg.segment_polygons","title":"segment_polygons(img, geojson_props, area_min=0.0, area_max=np.inf, ecc_min=0.0, ecc_max=1.0, rescale_factor=1.0)","text":"

Polygon segmentation.

Parameters:

Name Type Description Default img ndarray of bool

Binary image to segment as polygons.

required geojson_props dict

GeoJSON properties of objects.

required area_min float

Minimum and maximum area in pixels for an object.

0.0 area_max float

Minimum and maximum area in pixels for an object.

0.0 ecc_min float

Minimum and maximum eccentricity for an object.

0.0 ecc_max float

Minimum and maximum eccentricity for an object.

0.0 rescale_factor float

Rescale output coordinates by this factor.

1.0

Returns:

Name Type Description collection FeatureCollection

A FeatureCollection ready to be written as geojson.

Source code in cuisto/seg.py
def segment_polygons(\n    img: np.ndarray,\n    geojson_props: dict,\n    area_min: float = 0.0,\n    area_max: float = np.inf,\n    ecc_min: float = 0.0,\n    ecc_max: float = 1.0,\n    rescale_factor: float = 1.0,\n) -> geojson.FeatureCollection:\n    \"\"\"\n    Polygon segmentation.\n\n    Parameters\n    ----------\n    img : ndarray of bool\n        Binary image to segment as polygons.\n    geojson_props : dict\n        GeoJSON properties of objects.\n    area_min, area_max : float\n        Minimum and maximum area in pixels for an object.\n    ecc_min, ecc_max : float\n        Minimum and maximum eccentricity for an object.\n    rescale_factor: float\n        Rescale output coordinates by this factor.\n\n    Returns\n    -------\n    collection : geojson.FeatureCollection\n        A FeatureCollection ready to be written as geojson.\n\n    \"\"\"\n\n    label_image = measure.label(img)\n\n    # get objects properties\n    stats = pd.DataFrame(\n        measure.regionprops_table(\n            label_image, properties=(\"label\", \"area\", \"eccentricity\")\n        )\n    )\n\n    # remove objects not matching filters\n    toremove = stats[\n        (stats[\"area\"] < area_min)\n        | (stats[\"area\"] > area_max)\n        | (stats[\"eccentricity\"] < ecc_min)\n        | (stats[\"eccentricity\"] > ecc_max)\n    ]\n\n    label_image[np.isin(label_image, toremove[\"label\"])] = 0\n\n    # find objects countours\n    label_image = label_image > 0\n    contours = measure.find_contours(label_image)\n\n    return get_collection_from_poly(\n        contours, geojson_props, rescale_factor=rescale_factor\n    )\n
"},{"location":"api-utils.html","title":"cuisto.utils","text":"

utils module, part of cuisto.

Contains utilities functions.

"},{"location":"api-utils.html#cuisto.utils.add_brain_region","title":"add_brain_region(df, atlas, col='Parent')","text":"

Add brain region to a DataFrame with Atlas_X, Atlas_Y and Atlas_Z columns.

This uses Brainglobe Atlas API to query the atlas. It does not use the structure_from_coords() method, instead it manually converts the coordinates in stack indices, then get the corresponding annotation id and query the corresponding acronym -- because brainglobe-atlasapi is not vectorized at all.

Parameters:

Name Type Description Default df DataFrame

DataFrame with atlas coordinates in microns.

required atlas BrainGlobeAtlas required col str

Column in which to put the regions acronyms. Default is \"Parent\".

'Parent'

Returns:

Name Type Description df DataFrame

Same DataFrame with a new \"Parent\" column.

Source code in cuisto/utils.py
def add_brain_region(\n    df: pd.DataFrame, atlas: BrainGlobeAtlas, col=\"Parent\"\n) -> pd.DataFrame:\n    \"\"\"\n    Add brain region to a DataFrame with `Atlas_X`, `Atlas_Y` and `Atlas_Z` columns.\n\n    This uses Brainglobe Atlas API to query the atlas. It does not use the\n    structure_from_coords() method, instead it manually converts the coordinates in\n    stack indices, then get the corresponding annotation id and query the corresponding\n    acronym -- because brainglobe-atlasapi is not vectorized at all.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame with atlas coordinates in microns.\n    atlas : BrainGlobeAtlas\n    col : str, optional\n        Column in which to put the regions acronyms. Default is \"Parent\".\n\n    Returns\n    -------\n    df : pd.DataFrame\n        Same DataFrame with a new \"Parent\" column.\n\n    \"\"\"\n    df_in = df.copy()\n\n    res = atlas.resolution  # microns <-> pixels conversion\n    lims = atlas.shape_um  # out of brain\n\n    # set out-of-brain objects at 0 so we get \"root\" as their parent\n    df_in.loc[(df_in[\"Atlas_X\"] >= lims[0]) | (df_in[\"Atlas_X\"] < 0), \"Atlas_X\"] = 0\n    df_in.loc[(df_in[\"Atlas_Y\"] >= lims[1]) | (df_in[\"Atlas_Y\"] < 0), \"Atlas_Y\"] = 0\n    df_in.loc[(df_in[\"Atlas_Z\"] >= lims[2]) | (df_in[\"Atlas_Z\"] < 0), \"Atlas_Z\"] = 0\n\n    # build the multi index, in pixels and integers\n    ixyz = (\n        df_in[\"Atlas_X\"].divide(res[0]).astype(int),\n        df_in[\"Atlas_Y\"].divide(res[1]).astype(int),\n        df_in[\"Atlas_Z\"].divide(res[2]).astype(int),\n    )\n    # convert i, j, k indices in raveled indices\n    linear_indices = np.ravel_multi_index(ixyz, dims=atlas.annotation.shape)\n    # get the structure id from the annotation stack\n    idlist = atlas.annotation.ravel()[linear_indices]\n    # replace 0 which does not exist to 997 (root)\n    idlist[idlist == 0] = 997\n\n    # query the corresponding acronyms\n    lookup = atlas.lookup_df.set_index(\"id\")\n    df.loc[:, col] = lookup.loc[idlist, \"acronym\"].values\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.add_channel","title":"add_channel(df, object_type, channel_names)","text":"

Add channel as a measurement for detections DataFrame.

The channel is read from the Classification column, the latter having to be formatted as \"object_type: channel\".

Parameters:

Name Type Description Default df DataFrame

DataFrame with detections measurements.

required object_type str

Object type (primary classification).

required channel_names dict

Map between original channel names to something else.

required

Returns:

Type Description DataFrame

Same DataFrame with a \"channel\" column.

Source code in cuisto/utils.py
def add_channel(\n    df: pd.DataFrame, object_type: str, channel_names: dict\n) -> pd.DataFrame:\n    \"\"\"\n    Add channel as a measurement for detections DataFrame.\n\n    The channel is read from the Classification column, the latter having to be\n    formatted as \"object_type: channel\".\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame with detections measurements.\n    object_type : str\n        Object type (primary classification).\n    channel_names : dict\n        Map between original channel names to something else.\n\n    Returns\n    -------\n    pd.DataFrame\n        Same DataFrame with a \"channel\" column.\n\n    \"\"\"\n    # check if there is something to do\n    if \"channel\" in df.columns:\n        return df\n\n    kind = get_df_kind(df)\n    if kind == \"annotation\":\n        warnings.warn(\"Annotation DataFrame not supported.\")\n        return df\n\n    # add channel, from {class_name: channel} classification\n    df[\"channel\"] = (\n        df[\"Classification\"].str.replace(object_type + \": \", \"\").map(channel_names)\n    )\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.add_hemisphere","title":"add_hemisphere(df, hemisphere_names, midline=5700, col='Atlas_Z', atlas_type='brain')","text":"

Add hemisphere (left/right) as a measurement for detections or annotations.

The hemisphere is read in the \"Classification\" column for annotations. The latter needs to be in the form \"Right: Name\" or \"Left: Name\". For detections, the input col of df is compared to midline to assess if the object belong to the left or right hemispheres.

Parameters:

Name Type Description Default df DataFrame

DataFrame with detections or annotations measurements.

required hemisphere_names dict

Map between \"Left\" and \"Right\" to something else.

required midline float

Used only for \"detections\" df. Corresponds to the brain midline in microns, should be 5700 for CCFv3 and 1610 for spinal cord.

5700 col str

Name of the column containing the Z coordinate (medio-lateral) in microns. Default is \"Atlas_Z\".

'Atlas_Z' atlas_type (brain, cord)

Type of atlas used for registration. Required because the brain atlas is swapped between left and right while the spinal cord atlas is not. Default is \"brain\".

\"brain\"

Returns:

Name Type Description df DataFrame

The same DataFrame with a new \"hemisphere\" column

Source code in cuisto/utils.py
def add_hemisphere(\n    df: pd.DataFrame,\n    hemisphere_names: dict,\n    midline: float = 5700,\n    col: str = \"Atlas_Z\",\n    atlas_type: str = \"brain\",\n) -> pd.DataFrame:\n    \"\"\"\n    Add hemisphere (left/right) as a measurement for detections or annotations.\n\n    The hemisphere is read in the \"Classification\" column for annotations. The latter\n    needs to be in the form \"Right: Name\" or \"Left: Name\". For detections, the input\n    `col` of `df` is compared to `midline` to assess if the object belong to the left or\n    right hemispheres.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n        DataFrame with detections or annotations measurements.\n    hemisphere_names : dict\n        Map between \"Left\" and \"Right\" to something else.\n    midline : float\n        Used only for \"detections\" `df`. Corresponds to the brain midline in microns,\n        should be 5700 for CCFv3 and 1610 for spinal cord.\n    col : str, optional\n        Name of the column containing the Z coordinate (medio-lateral) in microns.\n        Default is \"Atlas_Z\".\n    atlas_type : {\"brain\", \"cord\"}, optional\n        Type of atlas used for registration. Required because the brain atlas is swapped\n        between left and right while the spinal cord atlas is not. Default is \"brain\".\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        The same DataFrame with a new \"hemisphere\" column\n\n    \"\"\"\n    # check if there is something to do\n    if \"hemisphere\" in df.columns:\n        return df\n\n    # get kind of DataFrame\n    kind = get_df_kind(df)\n\n    if kind == \"detection\":\n        # use midline\n        if atlas_type == \"brain\":\n            # brain atlas : beyond midline, it's left\n            df.loc[df[col] >= midline, \"hemisphere\"] = hemisphere_names[\"Left\"]\n            df.loc[df[col] < midline, \"hemisphere\"] = hemisphere_names[\"Right\"]\n        elif atlas_type == \"cord\":\n            # cord atlas : below midline, it's left\n            df.loc[df[col] <= midline, \"hemisphere\"] = hemisphere_names[\"Left\"]\n            df.loc[df[col] > midline, \"hemisphere\"] = hemisphere_names[\"Right\"]\n\n    elif kind == \"annotation\":\n        # use Classification name -- this does not depend on atlas type\n        df[\"hemisphere\"] = [name.split(\":\")[0] for name in df[\"Classification\"]]\n        df[\"hemisphere\"] = df[\"hemisphere\"].map(hemisphere_names)\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.ccf_to_stereo","title":"ccf_to_stereo(x_ccf, y_ccf, z_ccf=0)","text":"

Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in Paxinos-Franklin atlas).

Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be in mm. x_ccf corresponds to the anterio-posterior (rostro-caudal) axis. y_ccf corresponds to the dorso-ventral axis. z_ccf corresponds to the medio-lateral axis (left-right) axis.

Warning : it is a rough estimation.

(1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858

Parameters:

Name Type Description Default x_ccf floats or ndarray

Coordinates in CCFv3 space in mm.

required y_ccf floats or ndarray

Coordinates in CCFv3 space in mm.

required z_ccf float or ndarray

Coordinate in CCFv3 space in mm. Default is 0.

0

Returns:

Type Description ap, dv, ml : floats or np.ndarray

Stereotaxic coordinates in mm.

Source code in cuisto/utils.py
def ccf_to_stereo(\n    x_ccf: float | np.ndarray, y_ccf: float | np.ndarray, z_ccf: float | np.ndarray = 0\n) -> tuple:\n    \"\"\"\n    Convert X, Y, Z coordinates in CCFv3 to stereotaxis coordinates (as in\n    Paxinos-Franklin atlas).\n\n    Coordinates are shifted, rotated and squeezed, see (1) for more info. Input must be\n    in mm.\n    `x_ccf` corresponds to the anterio-posterior (rostro-caudal) axis.\n    `y_ccf` corresponds to the dorso-ventral axis.\n    `z_ccf` corresponds to the medio-lateral axis (left-right) axis.\n\n    Warning : it is a rough estimation.\n\n    (1) https://community.brain-map.org/t/how-to-transform-ccf-x-y-z-coordinates-into-stereotactic-coordinates/1858\n\n    Parameters\n    ----------\n    x_ccf, y_ccf : floats or np.ndarray\n        Coordinates in CCFv3 space in mm.\n    z_ccf : float or np.ndarray, optional\n        Coordinate in CCFv3 space in mm. Default is 0.\n\n    Returns\n    -------\n    ap, dv, ml : floats or np.ndarray\n        Stereotaxic coordinates in mm.\n\n    \"\"\"\n    # Center CCF on Bregma\n    xstereo = -(x_ccf - 5.40)  # anterio-posterior coordinate (rostro-caudal)\n    ystereo = y_ccf - 0.44  # dorso-ventral coordinate\n    ml = z_ccf - 5.70  # medio-lateral coordinate (left-right)\n\n    # Rotate CCF of 5\u00b0\n    angle = np.deg2rad(5)\n    ap = xstereo * np.cos(angle) - ystereo * np.sin(angle)\n    dv = xstereo * np.sin(angle) + ystereo * np.cos(angle)\n\n    # Squeeze the dorso-ventral axis by 94.34%\n    dv *= 0.9434\n\n    return ap, dv, ml\n
"},{"location":"api-utils.html#cuisto.utils.filter_df_classifications","title":"filter_df_classifications(df, filter_list, mode='keep', col='Classification')","text":"

Filter a DataFrame whether specified col column entries contain elements in filter_list. Case insensitive.

If mode is \"keep\", keep entries only if their col in is in the list (default). If mode is \"remove\", remove entries if their col is in the list.

Parameters:

Name Type Description Default df DataFrame required filter_list list | tuple | str

List of words that should be present to trigger the filter.

required mode keep or remove

Keep or remove entries from the list. Default is \"keep\".

'keep' col str

Key in df. Default is \"Classification\".

'Classification'

Returns:

Type Description DataFrame

Filtered DataFrame.

Source code in cuisto/utils.py
def filter_df_classifications(\n    df: pd.DataFrame, filter_list: list | tuple | str, mode=\"keep\", col=\"Classification\"\n) -> pd.DataFrame:\n    \"\"\"\n    Filter a DataFrame whether specified `col` column entries contain elements in\n    `filter_list`. Case insensitive.\n\n    If `mode` is \"keep\", keep entries only if their `col` in is in the list (default).\n    If `mode` is \"remove\", remove entries if their `col` is in the list.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    filter_list : list | tuple | str\n        List of words that should be present to trigger the filter.\n    mode : \"keep\" or \"remove\", optional\n        Keep or remove entries from the list. Default is \"keep\".\n    col : str, optional\n        Key in `df`. Default is \"Classification\".\n\n    Returns\n    -------\n    pd.DataFrame\n        Filtered DataFrame.\n\n    \"\"\"\n    # check input\n    if isinstance(filter_list, str):\n        filter_list = [filter_list]  # make sure it is a list\n\n    if col not in df.columns:\n        # might be because of 'Classification' instead of 'classification'\n        col = col.capitalize()\n        if col not in df.columns:\n            raise KeyError(f\"{col} not in DataFrame.\")\n\n    pattern = \"|\".join(f\".*{s}.*\" for s in filter_list)\n\n    if mode == \"keep\":\n        df_return = df[df[col].str.contains(pattern, case=False, regex=True)]\n    elif mode == \"remove\":\n        df_return = df[~df[col].str.contains(pattern, case=False, regex=True)]\n\n    # check\n    if len(df_return) == 0:\n        raise ValueError(\n            (\n                f\"Filtering '{col}' with {filter_list} resulted in an\"\n                + \" empty DataFrame, check your config file.\"\n            )\n        )\n    return df_return\n
"},{"location":"api-utils.html#cuisto.utils.filter_df_regions","title":"filter_df_regions(df, filter_list, mode='keep', col='Parent')","text":"

Filters entries in df based on wether their col is in filter_list or not.

If mode is \"keep\", keep entries only if their col in is in the list (default). If mode is \"remove\", remove entries if their col is in the list.

Parameters:

Name Type Description Default df DataFrame required filter_list list - like

List of regions to keep or remove from the DataFrame.

required mode keep or remove

Keep or remove entries from the list. Default is \"keep\".

'keep' col str

Key in df. Default is \"Parent\".

'Parent'

Returns:

Name Type Description df DataFrame

Filtered DataFrame.

Source code in cuisto/utils.py
def filter_df_regions(\n    df: pd.DataFrame, filter_list: list | tuple, mode=\"keep\", col=\"Parent\"\n) -> pd.DataFrame:\n    \"\"\"\n    Filters entries in `df` based on wether their `col` is in `filter_list` or not.\n\n    If `mode` is \"keep\", keep entries only if their `col` in is in the list (default).\n    If `mode` is \"remove\", remove entries if their `col` is in the list.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    filter_list : list-like\n        List of regions to keep or remove from the DataFrame.\n    mode : \"keep\" or \"remove\", optional\n        Keep or remove entries from the list. Default is \"keep\".\n    col : str, optional\n        Key in `df`. Default is \"Parent\".\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        Filtered DataFrame.\n\n    \"\"\"\n\n    if mode == \"keep\":\n        return df[df[col].isin(filter_list)]\n    if mode == \"remove\":\n        return df[~df[col].isin(filter_list)]\n
"},{"location":"api-utils.html#cuisto.utils.get_blacklist","title":"get_blacklist(file, atlas)","text":"

Build a list of regions to exclude from file.

File must be a TOML with [WITH_CHILDS] and [EXACT] sections.

Parameters:

Name Type Description Default file str

Full path the atlas_blacklist.toml file.

required atlas BrainGlobeAtlas

Atlas to extract regions from.

required

Returns:

Name Type Description black_list list

Full list of acronyms to discard.

Source code in cuisto/utils.py
def get_blacklist(file: str, atlas: BrainGlobeAtlas) -> list:\n    \"\"\"\n    Build a list of regions to exclude from file.\n\n    File must be a TOML with [WITH_CHILDS] and [EXACT] sections.\n\n    Parameters\n    ----------\n    file : str\n        Full path the atlas_blacklist.toml file.\n    atlas : BrainGlobeAtlas\n        Atlas to extract regions from.\n\n    Returns\n    -------\n    black_list : list\n        Full list of acronyms to discard.\n\n    \"\"\"\n    with open(file, \"rb\") as fid:\n        content = tomllib.load(fid)\n\n    blacklist = []  # init. the list\n\n    # add regions and their descendants\n    for region in content[\"WITH_CHILDS\"][\"members\"]:\n        blacklist.extend(\n            [\n                atlas.structures[id][\"acronym\"]\n                for id in atlas.structures.tree.expand_tree(\n                    atlas.structures[region][\"id\"]\n                )\n            ]\n        )\n\n    # add regions specified exactly (no descendants)\n    blacklist.extend(content[\"EXACT\"][\"members\"])\n\n    return blacklist\n
"},{"location":"api-utils.html#cuisto.utils.get_data_coverage","title":"get_data_coverage(df, col='Atlas_AP', by='animal')","text":"

Get min and max in col for each by.

Used to get data coverage for each animal to plot in distributions.

Parameters:

Name Type Description Default df DataFrame

description

required col str

Key in df, default is \"Atlas_X\".

'Atlas_AP' by str

Key in df , default is \"animal\".

'animal'

Returns:

Type Description DataFrame

min and max of col for each by, named \"X_min\", and \"X_max\".

Source code in cuisto/utils.py
def get_data_coverage(df: pd.DataFrame, col=\"Atlas_AP\", by=\"animal\") -> pd.DataFrame:\n    \"\"\"\n    Get min and max in `col` for each `by`.\n\n    Used to get data coverage for each animal to plot in distributions.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        _description_\n    col : str, optional\n        Key in `df`, default is \"Atlas_X\".\n    by : str, optional\n        Key in `df` , default is \"animal\".\n\n    Returns\n    -------\n    pd.DataFrame\n        min and max of `col` for each `by`, named \"X_min\", and \"X_max\".\n\n    \"\"\"\n    df_group = df.groupby([by])\n    return pd.DataFrame(\n        [\n            df_group[col].min(),\n            df_group[col].max(),\n        ],\n        index=[\"X_min\", \"X_max\"],\n    )\n
"},{"location":"api-utils.html#cuisto.utils.get_df_kind","title":"get_df_kind(df)","text":"

Get DataFrame kind, eg. Annotations or Detections.

It is based on reading the Object Type of the first entry, so the DataFrame must have only one kind of object.

Parameters:

Name Type Description Default df DataFrame required

Returns:

Name Type Description kind str

\"detection\" or \"annotation\".

Source code in cuisto/utils.py
def get_df_kind(df: pd.DataFrame) -> str:\n    \"\"\"\n    Get DataFrame kind, eg. Annotations or Detections.\n\n    It is based on reading the Object Type of the first entry, so the DataFrame must\n    have only one kind of object.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n\n    Returns\n    -------\n    kind : str\n        \"detection\" or \"annotation\".\n\n    \"\"\"\n    return df[\"Object type\"].iloc[0].lower()\n
"},{"location":"api-utils.html#cuisto.utils.get_injection_site","title":"get_injection_site(animal, info_file, channel, stereo=False)","text":"

Get the injection site coordinates associated with animal.

Parameters:

Name Type Description Default animal str

Animal ID.

required info_file str

Path to TOML info file.

required channel str

Channel ID as in the TOML file.

required stereo bool

Wether to convert coordinates in stereotaxis coordinates. Default is False.

False

Returns:

Type Description x, y, z : floats

Injection site coordinates.

Source code in cuisto/utils.py
def get_injection_site(\n    animal: str, info_file: str, channel: str, stereo: bool = False\n) -> tuple:\n    \"\"\"\n    Get the injection site coordinates associated with animal.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    info_file : str\n        Path to TOML info file.\n    channel : str\n        Channel ID as in the TOML file.\n    stereo : bool, optional\n        Wether to convert coordinates in stereotaxis coordinates. Default is False.\n\n    Returns\n    -------\n    x, y, z : floats\n        Injection site coordinates.\n\n    \"\"\"\n    with open(info_file, \"rb\") as fid:\n        info = tomllib.load(fid)\n\n    if channel in info[animal]:\n        x, y, z = info[animal][channel][\"injection_site\"]\n        if stereo:\n            x, y, z = ccf_to_stereo(x, y, z)\n    else:\n        x, y, z = None, None, None\n\n    return x, y, z\n
"},{"location":"api-utils.html#cuisto.utils.get_leaves_list","title":"get_leaves_list(atlas)","text":"

Get the list of leaf brain regions.

Leaf brain regions are defined as regions without childs, eg. regions that are at the bottom of the hiearchy.

Parameters:

Name Type Description Default atlas BrainGlobeAtlas

Atlas to extract regions from.

required

Returns:

Name Type Description leaves_list list

Acronyms of leaf brain regions.

Source code in cuisto/utils.py
def get_leaves_list(atlas: BrainGlobeAtlas) -> list:\n    \"\"\"\n    Get the list of leaf brain regions.\n\n    Leaf brain regions are defined as regions without childs, eg. regions that are at\n    the bottom of the hiearchy.\n\n    Parameters\n    ----------\n    atlas : BrainGlobeAtlas\n        Atlas to extract regions from.\n\n    Returns\n    -------\n    leaves_list : list\n        Acronyms of leaf brain regions.\n\n    \"\"\"\n    leaves_list = []\n    for region in atlas.structures_list:\n        if atlas.structures.tree[region[\"id\"]].is_leaf():\n            leaves_list.append(region[\"acronym\"])\n\n    return leaves_list\n
"},{"location":"api-utils.html#cuisto.utils.get_mapping_fusion","title":"get_mapping_fusion(fusion_file)","text":"

Get mapping dictionnary between input brain regions and new regions defined in atlas_fusion.toml file.

The returned dictionnary can be used in DataFrame.replace().

Parameters:

Name Type Description Default fusion_file str

Path to the TOML file with the merging rules.

required

Returns:

Name Type Description m dict

Mapping as {old: new}.

Source code in cuisto/utils.py
def get_mapping_fusion(fusion_file: str) -> dict:\n    \"\"\"\n    Get mapping dictionnary between input brain regions and new regions defined in\n    `atlas_fusion.toml` file.\n\n    The returned dictionnary can be used in DataFrame.replace().\n\n    Parameters\n    ----------\n    fusion_file : str\n        Path to the TOML file with the merging rules.\n\n    Returns\n    -------\n    m : dict\n        Mapping as {old: new}.\n\n    \"\"\"\n    with open(fusion_file, \"rb\") as fid:\n        df = pd.DataFrame.from_dict(tomllib.load(fid), orient=\"index\").set_index(\n            \"acronym\"\n        )\n\n    return (\n        df.drop(columns=\"name\")[\"members\"]\n        .explode()\n        .reset_index()\n        .set_index(\"members\")\n        .to_dict()[\"acronym\"]\n    )\n
"},{"location":"api-utils.html#cuisto.utils.get_starter_cells","title":"get_starter_cells(animal, channel, info_file)","text":"

Get the number of starter cells associated with animal.

Parameters:

Name Type Description Default animal str

Animal ID.

required channel str

Channel ID.

required info_file str

Path to TOML info file.

required

Returns:

Name Type Description n_starters int

Number of starter cells.

Source code in cuisto/utils.py
def get_starter_cells(animal: str, channel: str, info_file: str) -> int:\n    \"\"\"\n    Get the number of starter cells associated with animal.\n\n    Parameters\n    ----------\n    animal : str\n        Animal ID.\n    channel : str\n        Channel ID.\n    info_file : str\n        Path to TOML info file.\n\n    Returns\n    -------\n    n_starters : int\n        Number of starter cells.\n\n    \"\"\"\n    with open(info_file, \"rb\") as fid:\n        info = tomllib.load(fid)\n\n    return info[animal][channel][\"starter_cells\"]\n
"},{"location":"api-utils.html#cuisto.utils.merge_regions","title":"merge_regions(df, col, fusion_file)","text":"

Merge brain regions following rules in the fusion_file.toml file.

Apply this merging on col of the input DataFrame. col whose value is found in the members sections in the file will be changed to the new acronym.

Parameters:

Name Type Description Default df DataFrame required col str

Column of df on which to apply the mapping.

required fusion_file str

Path to the toml file with the merging rules.

required

Returns:

Name Type Description df DataFrame

Same DataFrame with regions renamed.

Source code in cuisto/utils.py
def merge_regions(df: pd.DataFrame, col: str, fusion_file: str) -> pd.DataFrame:\n    \"\"\"\n    Merge brain regions following rules in the `fusion_file.toml` file.\n\n    Apply this merging on `col` of the input DataFrame. `col` whose value is found in\n    the `members` sections in the file will be changed to the new acronym.\n\n    Parameters\n    ----------\n    df : pandas.DataFrame\n    col : str\n        Column of `df` on which to apply the mapping.\n    fusion_file : str\n        Path to the toml file with the merging rules.\n\n    Returns\n    -------\n    df : pandas.DataFrame\n        Same DataFrame with regions renamed.\n\n    \"\"\"\n    df[col] = df[col].replace(get_mapping_fusion(fusion_file))\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.renormalize_per_key","title":"renormalize_per_key(df, by, on)","text":"

Renormalize on column by its sum for each by.

Use case : relative density is computed for both hemispheres, so if one wants to plot only one hemisphere, the sum of the bars corresponding to one channel (by) should be 1. So :

df = df[df[\"hemisphere\"] == \"Ipsi.\"] df = renormalize_per_key(df, \"channel\", \"relative density\") Then, the sum of \"relative density\" for each \"channel\" equals 1.

Parameters:

Name Type Description Default df DataFrame required by str

Key in df. df is normalized for each by.

required on str

Key in df. Measurement to be normalized.

required

Returns:

Name Type Description df DataFrame

Same DataFrame with normalized on column.

Source code in cuisto/utils.py
def renormalize_per_key(df: pd.DataFrame, by: str, on: str):\n    \"\"\"\n    Renormalize `on` column by its sum for each `by`.\n\n    Use case : relative density is computed for both hemispheres, so if one wants to\n    plot only one hemisphere, the sum of the bars corresponding to one channel (`by`)\n    should be 1. So :\n    >>> df = df[df[\"hemisphere\"] == \"Ipsi.\"]\n    >>> df = renormalize_per_key(df, \"channel\", \"relative density\")\n    Then, the sum of \"relative density\" for each \"channel\" equals 1.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    by : str\n        Key in `df`. `df` is normalized for each `by`.\n    on : str\n        Key in `df`. Measurement to be normalized.\n\n    Returns\n    -------\n    df : pd.DataFrame\n        Same DataFrame with normalized `on` column.\n\n    \"\"\"\n    norm = df.groupby(by)[on].sum()\n    bys = df[by].unique()\n    for key in bys:\n        df.loc[df[by] == key, on] = df.loc[df[by] == key, on].divide(norm[key])\n\n    return df\n
"},{"location":"api-utils.html#cuisto.utils.select_hemisphere_channel","title":"select_hemisphere_channel(df, hue, hue_filter, hue_mirror)","text":"

Select relevant data given hue and filters.

Returns the DataFrame with only things to be used.

Parameters:

Name Type Description Default df DataFrame

DataFrame to filter.

required hue (hemisphere, channel)

hue that will be used in seaborn plots.

\"hemisphere\" hue_filter str

Selected data.

required hue_mirror bool

Instead of keeping only hue_filter values, they will be plotted in mirror.

required

Returns:

Name Type Description dfplt DataFrame

DataFrame to be used in plots.

Source code in cuisto/utils.py
def select_hemisphere_channel(\n    df: pd.DataFrame, hue: str, hue_filter: str, hue_mirror: bool\n) -> pd.DataFrame:\n    \"\"\"\n    Select relevant data given hue and filters.\n\n    Returns the DataFrame with only things to be used.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        DataFrame to filter.\n    hue : {\"hemisphere\", \"channel\"}\n        hue that will be used in seaborn plots.\n    hue_filter : str\n        Selected data.\n    hue_mirror : bool\n        Instead of keeping only hue_filter values, they will be plotted in mirror.\n\n    Returns\n    -------\n    dfplt : pd.DataFrame\n        DataFrame to be used in plots.\n\n    \"\"\"\n    dfplt = df.copy()\n\n    if hue == \"hemisphere\":\n        # hue_filter is used to select channels\n        # keep only left and right hemispheres, not \"both\"\n        dfplt = dfplt[dfplt[\"hemisphere\"] != \"both\"]\n        if hue_filter == \"all\":\n            hue_filter = dfplt[\"channel\"].unique()\n        elif not isinstance(hue_filter, (list, tuple)):\n            # it is allowed to select several channels so handle lists\n            hue_filter = [hue_filter]\n        dfplt = dfplt[dfplt[\"channel\"].isin(hue_filter)]\n    elif hue == \"channel\":\n        # hue_filter is used to select hemispheres\n        # it can only be left, right, both or empty\n        if hue_filter == \"both\":\n            # handle if it's a coordinates DataFrame which doesn't have \"both\"\n            if \"both\" not in dfplt[\"hemisphere\"].unique():\n                # keep both hemispheres, don't do anything\n                pass\n            else:\n                if hue_mirror:\n                    # we need to keep both hemispheres to plot them in mirror\n                    dfplt = dfplt[dfplt[\"hemisphere\"] != \"both\"]\n                else:\n                    # we keep the metrics computed in both hemispheres\n                    dfplt = dfplt[dfplt[\"hemisphere\"] == \"both\"]\n        else:\n            # hue_filter should correspond to an hemisphere name\n            dfplt = dfplt[dfplt[\"hemisphere\"] == hue_filter]\n    else:\n        # not handled. Just return the DataFrame without filtering, maybe it'll make\n        # sense.\n        warnings.warn(f\"{hue} should be 'channel' or 'hemisphere'.\")\n\n    # check result\n    if len(dfplt) == 0:\n        warnings.warn(\n            f\"hue={hue} and hue_filter={hue_filter} resulted in an empty subset.\"\n        )\n\n    return dfplt\n
"},{"location":"guide-create-pyramids.html","title":"Create pyramidal OME-TIFF","text":"

This page will guide you to use the pyramid-creator package, in the event the CZI file does not work directly in QuPath. The script will generate pyramids from OME-TIFF files exported from ZEN.

Tip

pyramid-creator can also pyramidalize images using Python only with the --no-use-qupath option.

This Python script uses QuPath under the hood, via a companion script called createPyramids.groovy. It will find the OME-TIFF files and make QuPath run the groovy script on it, in console mode (without graphical user interface).

This script is standalone, eg. it does not rely on the cuisto package. But installing the later makes sure all dependencies are installed (namely typer and tqdm with the QuPath backend and quite a few more for the Python backend).

pyramid-creator moved to a standalone package that you can find here with installation and usage instructions.

"},{"location":"guide-create-pyramids.html#installation","title":"Installation","text":"

You will find instructions on the dedicated project page over at Github.

For reference :

You will need conda, follow those instructions to install it.

Then, create a virtual environment if you didn't already (pyramid-creator can be installed in the environment for cuisto) and install the pyramid-creator package.

conda create -c conda-forge -n cuisto-env python=3.12  # not required if you already create an environment\nconda activate cuisto-env\npip install pyramid-creator\n
To use the Python backend (with tifffile), replace the last line with :
pip install pyramid-creator[python-backend]\n
To use the QuPath backend, a working QuPath installation is required, and the pyramid-creator command needs to be aware of its location.

To do so, first, install QuPath. By default, it will install in ~\\AppData\\QuPath-0.X.Y. In any case, note down the installation location.

Then, you have several options : - Create a file in your user directory called \"QUPATH_PATH\" (without extension), containing the full path to the QuPath console executable. In my case, it reads : C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe. Then, the pyramid-creator script will read this file to find the QuPath executable. - Specify the QuPath path as an option when calling the command line interface (see the Usage section) :

pyramid-creator /path/to/your/images --qupath-path \"C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe\"\n
- Specify the QuPath path as an option when using the package in a Python script (see the Usage section) :
from pyramid_creator import pyramidalize_directory\npyramidalize_directory(\"/path/to/your/images/\", qupath_path=\"C:\\Users\\glegoc\\AppData\\Local\\QuPath-0.5.1\\QuPath-0.5.1 (console).exe\")\n
- If you're using Windows, using QuPath v0.6.0, v0.5.1 or v0.5.0 and chose the default installation location, pyramid-creator should find it automatically and write it down in the \"QUPATH_PATH\" file by itself.

"},{"location":"guide-create-pyramids.html#export-czi-to-ome-tiff","title":"Export CZI to OME-TIFF","text":"

OME-TIFF is a specification of the TIFF image format. It specifies how the metadata should be written to the file to be interoperable between softwares. ZEN can export to OME-TIFF so you don't need to pay attention to metadata. Therefore, you won't need to specify pixel size and channels names and colors as it will be read directly from the OME-TIFF files.

  1. Open your CZI file in ZEN.
  2. Open the \"Processing tab\" on the left panel.
  3. Under method, choose Export/Import > OME TIFF-Export.
  4. In Parameters, make sure to tick the \"Show all\" tiny box on the right.
  5. The following parameters should be used (checked), the other should be unchecked :
    • Use Tiles
    • Original data \"Convert to 8 Bit\" should be UNCHECKED
    • OME-XML Scheme : 2016-06
    • Use full set of dimensions (unless you want to select slices and/or channels)
  6. In Input, choose your file
  7. Go back to Parameters to choose the output directory and file prefix. \"_s1\", \"_s2\"... will be appended to the prefix.
  8. Back on the top, click the \"Apply\" button.

The OME-TIFF files should be ready to be pyramidalized with the create_pyramids.py script.

"},{"location":"guide-create-pyramids.html#usage","title":"Usage","text":"

See the instructions on the dedicated project page over at Github.

"},{"location":"guide-install-abba.html","title":"Install ABBA","text":"

You can head to the ABBA documentation for installation instructions. You'll see that a Windows installer is available. While it might be working great, I prefer to do it manually step-by-step to make sure everything is going well.

You will find below installation instructions for the regular ABBA Fiji plugin, which proposes only the mouse and rat brain atlases. To be able to use the Brainglobe atlases, you will need the Python version. The two can be installed alongside each other.

"},{"location":"guide-install-abba.html#abba-fiji","title":"ABBA Fiji","text":""},{"location":"guide-install-abba.html#install-fiji","title":"Install Fiji","text":"

Install the \"batteries-included\" distribution of ImageJ, Fiji, from the official website.

Warning

Extract Fiji somewhere you have write access, otherwise Fiji will not be able to download and install plugins. In other words, put the folder in your User directory and not in C:\\, C:\\Program Files and the like.

  1. Download the zip archive and extract it somewhere relevant.
  2. Launch ImageJ.exe.
"},{"location":"guide-install-abba.html#install-the-abba-plugin","title":"Install the ABBA plugin","text":"

We need to add the PTBIOP update site, managed by the bio-imaging and optics facility at EPFL, that contains the ABBA plugin.

  1. In Fiji, head to Help > Update...
  2. In the ImageJ updater window, click on Manage Update Sites. Look up PTBIOP, and click on the check box. Apply and Close, and Apply Changes. This will download and install the required plugins. Restart ImageJ as suggested.
  3. In Fiji, head to Plugins > BIOP > Atlas > ABBA - ABBA start, or simply type abba start in the search box. Choose the \"Adult Mouse Brain - Allen Brain Atlas V3p1\". It will download this atlas and might take a while, depending on your Internet connection.
"},{"location":"guide-install-abba.html#install-the-automatic-registration-tools","title":"Install the automatic registration tools","text":"

ABBA can leverage the elastix toolbox for automatic 2D in-plane registration.

  1. You need to download it here, which will redirect you to the Github releases page (5.2.0 should work).
  2. Download the zip archive and extract it somewhere relevant.
  3. In Fiji, in the search box, type \"set and check\" and launch the \"Set and Check Wrappers\" command. Set the paths to \"elastix.exe\" and \"transformix.exe\" you just downloaded.

ABBA should be installed and functional ! You can check the official documentation for usage instructions and some tips here.

"},{"location":"guide-install-abba.html#abba-python","title":"ABBA Python","text":"

Brainglobe is an initiative aiming at providing interoperable, model-agnostic Python-based tools for neuroanatomy. They package various published volumetric anatomical atlases of different species (check the list), including the Allen Mouse brain atlas (CCFv3, ref.) and a 3D version of the Allen mouse spinal cord atlas (ref).

To be able to leverage those atlases, we need to make ImageJ and Python be able to talk to each other. This is the purpose of abba_python, that will install ImageJ and its ABBA plugins inside a python environment, with bindings between the two worlds.

"},{"location":"guide-install-abba.html#install-conda","title":"Install conda","text":"

If not done already, follow those instructions to install conda.

"},{"location":"guide-install-abba.html#install-abba_python-in-a-virtual-environment","title":"Install abba_python in a virtual environment","text":"
  1. Open a terminal (PowerShell).
  2. Create a virtual environment with Python 3.10, OpenJDK and PyImageJ :
    conda create -c conda-forge -n abba_python python=3.10 openjdk=11 maven pyimagej notebook\n
  3. Install the latest functional version of abba_python with pip :
    pip install abba-python==0.9.6.dev0\n
  4. Restart the terminal and activate the new environment :
    conda activate abba_python\n
  5. Download the Brainglobe atlas you want (eg. Allen mouse spinal cord) :
    brainglobe install -a allen_cord_20um\n
  6. Launch an interactive Python shell :
    ipython\n
    You should see the IPython prompt, that looks like this :
    In [1]:\n
  7. Import abba_python and launch ImageJ from Python :
    from abba_python import abba\nabba.start_imagej()\n
    The first launch needs to initialize ImageJ and install all required plugins, which takes a while (>5min).
  8. Use ABBA as the regular Fiji version ! The main difference is that the dropdown menu to select which atlas to use is populated with the Brainglobe atlases.

Tip

Afterwards, to launch ImageJ from Python and do some registration work, you just need to launch a terminal (PowerShell), and do steps 4., 6., and 7.

"},{"location":"guide-install-abba.html#install-the-automatic-registration-tools_1","title":"Install the automatic registration tools","text":"

You can follow the same instructions as the regular Fiji version. You can do it from either the \"normal\" Fiji or the ImageJ instance launched from Python, they share the same configuration files. Therefore, if you already did it in regular Fiji, elastix should already be set up and ready to use in ImageJ from Python.

"},{"location":"guide-install-abba.html#troubleshooting","title":"Troubleshooting","text":""},{"location":"guide-install-abba.html#java_home-errors","title":"JAVA_HOME errors","text":"

Unfortunately on some computers, Python does not find the Java virtual machine even though it should have been installed when installing OpenJDK with conda. This will result in an error mentionning \"java.dll\" and suggesting to check the JAVA_HOME environment variable.

The only fix I could find is to install Java system-wide. You can grab a (free) installer on Adoptium, choosing JRE 17.X for your platform. During the installation :

  • choose to install \"just for you\",
  • enable \"Modify PATH variable\" as well as \"Set or override JAVA_HOME\" variable.

Restart the terminal and try again. Now, ImageJ should use the system-wide Java and it should work.

"},{"location":"guide-install-abba.html#abba-qupath-extension","title":"ABBA QuPath extension","text":"

To import registered regions in your QuPath project and be able to convert objects' coordinates in atlas space, the ABBA QuPath extension is required.

  1. In QuPath, head to Edit > Preferences. In the Extension tab, set your QuPath user directory to a local directory (usually C:\\Users\\USERNAME\\QuPath\\v0.X.Y).
  2. Create a folder named extensions in your QuPath user directory.
  3. Download the latest ABBA extension for QuPath from GitHub (choose the file qupath-extension-abba-x.y.z.zip).
  4. Uncompress the archive and copy all .jar files into the extensions folder in your QuPath user directory.
  5. Restart QuPath. Now, in Extensions, you should have an ABBA entry.
"},{"location":"guide-pipeline.html","title":"Pipeline","text":"

While you can use QuPath and cuisto functionalities as you see fit, there exists a pipeline version of those. It requires a specific structure to store files (so that the different scripts know where to look for data). It also requires that you have detections stored as geojson files, which can be achieved using a pixel classifier and further segmentation (see here) for example.

"},{"location":"guide-pipeline.html#purpose","title":"Purpose","text":"

This is especially useful to perform quantification for several animals at once, where you'll only need to specify the root directory and the animals identifiers that should be pooled together, instead of having to manually specify each detections and annotations files.

Three main scripts and function are used within the pipeline :

  • exportPixelClassifierProbabilities.groovy to create prediction maps of objects of interest
  • segment_image.py to segment those maps and create geojson files to be imported back to QuPath as detections
  • pipelineImportExport.groovy to :
    • clear all objects
    • import ABBA regions
    • mirror regions names
    • import geojson detections (from $folderPrefix$segmentation/$segTag$/geojson)
    • add measurements to detections
    • add atlas coordinates to detections
    • add hemisphere to detections' parents
    • add regions measurements
      • count for punctal objects
      • cumulated length for lines objects
    • export detections measurements
      • as CSV for punctual objects
      • as JSON for lines
    • export annotations as CSV
"},{"location":"guide-pipeline.html#directory-structure","title":"Directory structure","text":"

Following a specific directory structure ensures subsequent scripts and functions can find required files. The good news is that this structure will mostly be created automatically using the segmentation scripts (from QuPath and Python), as long as you stay consistent filling the parameters of each script. The structure expected by the groovy all-in-one script and cuisto batch-process function is the following :

some_directory/\n    \u251c\u2500\u2500AnimalID0/  \n    \u2502   \u251c\u2500\u2500 animalid0_qupath/\n    \u2502   \u2514\u2500\u2500 animalid0_segmentation/  \n    \u2502       \u2514\u2500\u2500 segtag/  \n    \u2502           \u251c\u2500\u2500 annotations/  \n    \u2502           \u251c\u2500\u2500 detections/  \n    \u2502           \u251c\u2500\u2500 geojson/  \n    \u2502           \u2514\u2500\u2500 probabilities/  \n    \u251c\u2500\u2500AnimalID1/  \n    \u2502   \u251c\u2500\u2500 animalid1_qupath/\n    \u2502   \u2514\u2500\u2500 animalid1_segmentation/  \n    \u2502       \u2514\u2500\u2500 segtag/  \n    \u2502           \u251c\u2500\u2500 annotations/  \n    \u2502           \u251c\u2500\u2500 detections/  \n    \u2502           \u251c\u2500\u2500 geojson/  \n    \u2502           \u2514\u2500\u2500 probabilities/  \n

Info

Except the root directory and the QuPath project, the rest is automatically created based on the parameters provided in the different scripts. Here's the description of the structure and the requirements :

  • animalid0 should be a convenient animal identifier.
  • The hierarchy must be followed.
  • The experiment root directory, AnimalID0, can be anything but should correspond to one and only one animal.
  • Subsequent animalid0 should be lower case.
  • animalid0_qupath can be named as you wish in practice, but should be the QuPath project.
  • animalid0_segmentation should be called exactly like this -- replacing animalid0 with the actual animal ID. It will be created automatically with the exportPixelClassifierProbabilities.groovy script.
  • segtag corresponds to the type of segmentation (cells, fibers...). It is specified in the exportPixelClassifierProbabilities script. It could be anything, but to recognize if the objects are polygons (and should be counted per regions) or polylines (and the cumulated length should be measured), there are some hardcoded keywords in the segment_images.py and pipelineImportExport.groovy scripts :
    • Cells-like when you need measurements related to its shape (area, circularity...) : cells, cell, polygons, polygon
    • Cells-like when you consider them as punctual : synapto, synaptophysin, syngfp, boutons, points
    • Fibers-like (polylines) : fibers, fiber, axons, axon
  • annotations contains the atlas regions measurements as TSV files.
  • detections contains the objects atlas coordinates and measurements as CSV files (for punctal objects) or JSON (for polylines objects).
  • geojson contains objects stored as geojson files. They could be generated with the pixel classifier prediction map segmentation.
  • probabilities contains the prediction maps to be segmented by the segment_images.py script.

Tip

You can see an example minimal directory structure with only annotations stored in resources/multi.

"},{"location":"guide-pipeline.html#usage","title":"Usage","text":"

Tip

Remember that this is merely an example pipeline, you can shortcut it at any points, as long as you end up with TSV files following the requirements for cuisto.

  1. Create a QuPath project.
  2. Register your images on an atlas with ABBA and export the registration back to QuPath.
  3. Use a pixel classifier and export the prediction maps with the exportPixelClassifierProbabilities.groovy script. You need to get a pixel classifier or create one.
  4. Segment those maps with the segment_images.py script to generate the geojson files containing the objects of interest.
  5. Run the pipelineImportExport.groovy script on your QuPath project.
  6. Set up your configuration files.
  7. Then, analysing your data with any number of animals should be as easy as executing those lines in Python (either from IPython directly or in a script to easily run it later) :
import cuisto\n\n# Parameters\nwdir = \"/path/to/some_directory\"\nanimals = [\"AnimalID0\", \"AnimalID1\"]\nconfig_file = \"/path/to/your/config.toml\"\noutput_format = \"h5\"  # to save the quantification values as hdf5 file\n\n# Processing\ncfg = cuisto.Config(config_file)\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animals(\n    wdir, animals, cfg, out_fmt=output_format\n)\n\n# Display\ncuisto.display.plot_regions(df_regions, cfg)\ncuisto.display.plot_1D_distributions(dfs_distributions, cfg, df_coordinates=df_coordinates)\ncuisto.display.plot_2D_distributions(df_coordinates, cfg)\n

Tip

You can see a live example in this demo notebook.

"},{"location":"guide-prepare-qupath.html","title":"Prepare QuPath data","text":"

cuisto uses some QuPath classifications concepts, make sure to be familiar with them with the official documentation. Notably, we use the concept of primary classification and derived classification : an object classfied as First: second is of classification First and of derived classification second.

"},{"location":"guide-prepare-qupath.html#qupath-requirements","title":"QuPath requirements","text":"

cuisto assumes a specific way of storing regions and objects information in the TSV files exported from QuPath. Note that only one primary classification is supported, but you can have any number of derived classifications.

"},{"location":"guide-prepare-qupath.html#detections","title":"Detections","text":"

Detections are the objects of interest. Their information must respect the following :

  • Atlas coordinates should be in millimetres (mm) and stored as Atlas_X, Atlas_Y, Atlas_Z. They correspond, respectively, to the anterio-posterior (rostro-caudal) axis, the inferio-superior (dorso-ventral) axis and the left-right (medio-lateral) axis.
  • They must have a derived classification, in the form Primary: second. Primary would be an object type (cells, fibers, ...), the second one would be a biological marker or a detection channel (fluorescence channel name), for instance : Cells: some marker, or Fibers: EGFP.
  • The classification must match exactly the corresponding measurement in the annotations (see below).
"},{"location":"guide-prepare-qupath.html#annotations","title":"Annotations","text":"

Annotations correspond to the atlas regions. Their information must respect the following :

  • They should be imported with the ABBA extension as acronyms and splitting left/right. Therefore, the annotation name should be the region acronym and its classification should be formatted as Hemisphere: acronym (for ex. Left: PAG).
  • Measurements names should be formatted as : Primary classification: derived classification measurement name. For instance :
    • if one has cells with some marker and count them in each atlas regions, the measurement name would be : Cells: some marker Count.
    • if one segments fibers revealed in the EGFP channel and measures the cumulated length in \u00b5m in each atlas regions, the measurement name would be : Fibers: EGFP Length \u00b5m.
  • Any number of markers or channels are supported.
"},{"location":"guide-prepare-qupath.html#measurements","title":"Measurements","text":""},{"location":"guide-prepare-qupath.html#metrics-supported-by-cuisto","title":"Metrics supported by cuisto","text":"

While you're free to add any measurements as long as they follow the requirements, keep in mind that for atlas regions quantification, cuisto will only compute, pool and average the following metrics :

  • the base measurement itself
    • if \"\u00b5m\" is contained in the measurement name, it will also be converted to mm (\\(\\div\\)1000)
  • the base measurement divided by the region area in \u00b5m\u00b2 (density in something/\u00b5m\u00b2)
  • the base measurement divided by the region area in mm\u00b2 (density in something/mm\u00b2)
  • the squared base measurement divided by the region area in \u00b5m\u00b2 (could be an index, in weird units...)
  • the relative base measurement : the base measurement divided by the total base measurement across all regions in each hemisphere
  • the relative density : density divided by total density across all regions in each hemisphere

It is then up to you to select which metrics among those to compute and display and name them, via the configuration file.

For punctal detections (eg. objects whose only the centroid is considered), only the atlas coordinates are used, to compute and display spatial distributions of objects across the brain (using their classifications to give each distributions different hues). For fibers-like objects, it requires to export the lines detections atlas coordinates as JSON files, with the exportFibersAtlasCoordinates.groovy script (this is done automatically when using the pipeline).

"},{"location":"guide-prepare-qupath.html#adding-measurements","title":"Adding measurements","text":""},{"location":"guide-prepare-qupath.html#count-for-cell-like-objects","title":"Count for cell-like objects","text":"

The groovy script under scripts/qupath-utils/measurements/addRegionsCount.groovy will add a properly formatted count of objects of selected classifications in all atlas regions. This is used for punctual objects (polygons or points), for example objects created in QuPath or with the segmentation script.

"},{"location":"guide-prepare-qupath.html#cumulated-length-for-fibers-like-objects","title":"Cumulated length for fibers-like objects","text":"

The groovy script under scripts/qupath-utils/measurements/addRegionsLength.groovy will add the properly formatted cumulated lenghth in microns of fibers-like objects in all atlas regions. This is used for polylines objects, for example generated with the segmentation script.

"},{"location":"guide-prepare-qupath.html#custom-measurements","title":"Custom measurements","text":"

Keeping in mind cuisto limitations, you can add any measurements you'd like.

For example, you can run a pixel classifier in all annotations (eg. atlas regions). Using the Measure button, it will add a measurement of the area covered by classified pixels. Then, you can use the script located under scripts/qupath-utils/measurements/renameMeasurements.groovy to rename the generated measurements with a properly-formatted name. Finally, you can export regions measurements.

Since cuisto will compute a \"density\", eg. the measurement divided by the region area, in this case, it will correspond to the fraction of surface occupied by classified pixels. This is showcased in the Examples.

"},{"location":"guide-prepare-qupath.html#qupath-export","title":"QuPath export","text":"

Once you imported atlas regions registered with ABBA, detected objects in your images and added properly formatted measurements to detections and annotations, you can :

  • Head to Measure > Export measurements
  • Select relevant images
  • Choose the Output file (specify in the file name if it is a detections or annotations file)
  • Chose either Detections or Annoations in Export type
  • Click Export

Do this for both Detections and Annotations, you can then use those files with cuisto (see the Examples).

"},{"location":"guide-qupath-objects.html","title":"Detect objects with QuPath","text":"

The QuPath documentation is quite extensive, detailed, very well explained and contains full guides on how to create a QuPath project and how to find objects of interests. It is therefore a highly recommended read, nevertheless, you will find below some quick reminders.

"},{"location":"guide-qupath-objects.html#qupath-project","title":"QuPath project","text":"

QuPath works with projects. It is basically a folder with a main project.qproj file, which is a JSON file that contains all the data about your images except the images themselves. Algonside, there is a data folder with an entry for each image, that stores the thumbnails, metadata about the image and detections and annotations but, again, not the image itself. The actual images can be stored anywhere (including a remote server), the QuPath project merely contains the information needed to fetch them and display them. QuPath will never modify your image data.

This design makes the QuPath project itself lightweight (should never exceed 500MB even with millions of detections), and portable : upon opening, if QuPath is not able to find the images where they should be, it will ask for their new locations.

Tip

It is recommended to create the QuPath project locally on your computer, to avoid any risk of conflicts if two people open it at the same time. Nevertheless, you should backup the project regularly on a remote server.

To create a new project, simply drag & drop an empty folder into QuPath window and accept to create a new empty project. Then, add images :

  • If you have a single file, just drag & drop it in the main window.
  • If you have several images, in the left panel, click Add images, then Choose files on the bottom. Drag & drop does not really work as the images will not be sorted properly.

Then, choose the following options :

Image server

Default (let QuPath decide)

Set image type

Most likely, fluorescence

Rotate image

No rotation (unless all your images should be rotated)

Optional args

Leave empty

Auto-generate pyramids

Uncheck

Import objects

Uncheck

Show image selector

Might be useful to check if the images are read correctly (mostly for CZI files).

"},{"location":"guide-qupath-objects.html#detect-objects","title":"Detect objects","text":""},{"location":"guide-qupath-objects.html#built-in-cell-detection","title":"Built-in cell detection","text":"

QuPath has a built-in cell detection feature, available in Analyze > Cell detection. You hava a full tutorial in the official documentation.

Briefly, this uses a watershed algorithm to find bright spots and can perform a cell expansion to estimate the full cell shape based on the detected nuclei. Therefore, this works best to segment nuclei but one can expect good performance for cells as well, depending on the imaging and staining conditions.

Tip

In scripts/qupath-utils/segmentation, there is watershedDetectionFilters.groovy which uses this feature from a script. It further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#pixel-classifier","title":"Pixel classifier","text":"

Another very powerful and versatile way to segment cells if through machine learning. Note the term \"machine\" and not \"deep\" as it relies on statistics theory from the 1980s. QuPath provides an user-friendly interface to that, similar to what ilastik provides.

The general idea is to train a model to classify every pixel as a signal or as background. You can find good resources on how to procede in the official documentation and some additionnal tips and tutorials on Michael Neslon's blog (here and here).

Specifically, you will manually annotate some pixels of objects of interest and background. Then, you will apply some image processing filters (gaussian blur, laplacian...) to reveal specific features in your images (shapes, textures...). Finally, the pixel classifier will fit a model on those pixel values, so that it will be able to predict if a pixel, given the values with the different filters you applied, belongs to an object of interest or to the background.

This is done in an intuitive GUI with live predictions to get an instant feedback on the effects of the filters and manual annotations.

"},{"location":"guide-qupath-objects.html#train-a-model","title":"Train a model","text":"

First and foremost, you should use a QuPath project dedicated to the training of a pixel classifier, as it is the only way to be able to edit it later on.

  1. You should choose some images from different animals, with different imaging conditions (staining efficiency and LED intensity) in different regions (eg. with different objects' shape, size, sparsity...). The goal is to get the most diversity of objects you could encounter in your experiments. 10 images is more than enough !
  2. Import those images to the new, dedicated QuPath project.
  3. Create the classifications you'll need, \"Cells: marker+\" for example. The \"Ignore*\" classification is used for the background.
  4. Head to Classify > Pixel classification > Train pixel classifier, and turn on Live prediction.
  5. Load all your images in Load training.
  6. In Advanced settings, check Reweight samples to help make sure a classification is not over-represented.
  7. Modify the different parameters :
    • Classifier : typically, RTrees or ANN_MLP. This can be changed dynamically afterwards to see which works best for you.
    • Resolution : this is the pixel size used. This is a trade-off between accuracy and speed. If your objects are only composed of a few pixels, you'll the full resolution, for big objects reducing the resolution will be faster.
    • Features : this is the core of the process -- where you choose the filters. In Edit, you'll need to choose :
      • The fluorescence channels
      • The scales, eg. the size of the filters applied to the image. The bigger, the coarser the filter is. Again, this will depend on the size of the objects you want to segment.
      • The features themselves, eg. the filters applied to your images before feeding the pixel values to the model. For starters, you can select them all to see what they look like.
    • Output :
      • Classification : QuPath will directly classify the pixels. Use that to create objects directly from the pixel classifier within QuPath.
      • Probability : this will output an image where each pixel is its probability to belong to each of the classifications. This is useful to create objects externally.
  8. In the bottom-right corner of the pixel classifier window, you can select to display each filters individually. Then in the QuPath main window, hitting C will switch the view to appreciate what the filter looks like. Identify the ones that makes your objects the most distinct from the background as possible. Switch back to Show classification once you begin to make annotations.
  9. Begin to annotate ! Use the Polyline annotation tool (V) to classify some pixels belonging to an object and some pixels belonging to the background across your images.

    Tip

    You can select the RTrees Classifier, then Edit : check the Calculate variable importance checkbox. Then in the log (Ctrl+Shift+L), you can inspect the weight each features have. This can help discard some filters to keep only the ones most efficient to distinguish the objects of interest.

  10. See in live the effect of your annotations on the classification using C and continue until you're satisfied.

    Important

    This is machine learning. The lesser annotations, the better, as this will make your model more general and adapt to new images. The goal is to find the minimal number of annotations to make it work.

  11. Once you're done, give your classifier a name in the text box in the bottom and save it. It will be stored as a JSON file in the classifiers folder of the QuPath project. This file can be imported in your other QuPath projects.

"},{"location":"guide-qupath-objects.html#built-in-create-objects","title":"Built-in create objects","text":"

Once you imported your model JSON file (Classify > Pixel classification > Load pixel classifier, three-dotted menu and Import from file), you can create objects out of it, measure the surface occupied by classified pixels in each annotation or classify existing detections based on the prediction at their centroid.

In scripts/qupath-utils/segmentation, there is a createDetectionsFromPixelClassifier.groovy script to batch-process your project.

"},{"location":"guide-qupath-objects.html#probability-map-segmentation","title":"Probability map segmentation","text":"

Alternatively, a Python script provided with cuisto can be used to segment the probability map generated by the pixel classifier (the script is located in scripts/segmentation).

You will first need to export those with the exportPixelClassifierProbabilities.groovy script (located in scripts/qupath-utils).

Then the segmentation script can :

  • find punctal objects as polygons (with a shape) or points (punctal) than can be counted.
  • trace fibers with skeletonization to create lines whose lengths can be measured.

Several parameters have to be specified by the user, see the segmentation script API reference. This script will generate GeoJson files that can be imported back to QuPath with the importGeojsonFiles.groovy script.

"},{"location":"guide-qupath-objects.html#third-party-extensions","title":"Third-party extensions","text":"

QuPath being open-source and extensible, there are third-party extensions that implement popular deep learning segmentation algorithms directly in QuPath. They can be used to find objects of interest as detections in the QuPath project and thus integrate nicely with cuisto to quantify them afterwards.

"},{"location":"guide-qupath-objects.html#instanseg","title":"InstanSeg","text":"

QuPath extension : https://github.com/qupath/qupath-extension-instanseg Original repository : https://github.com/instanseg/instanseg Reference papers : doi:10.48550/arXiv.2408.15954, doi:10.1101/2024.09.04.611150

"},{"location":"guide-qupath-objects.html#stardist","title":"Stardist","text":"

QuPath extension : https://github.com/qupath/qupath-extension-stardist Original repository : https://github.com/stardist/stardist Reference paper : doi:10.48550/arXiv.1806.03535

There is a stardistDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#cellpose","title":"Cellpose","text":"

QuPath extension : https://github.com/BIOP/qupath-extension-cellpose Original repository : https://github.com/MouseLand/cellpose Reference papers : doi:10.1038/s41592-020-01018-x, doi:10.1038/s41592-022-01663-4, doi:10.1101/2024.02.10.579780

There is a cellposeDetectionFilter.groovy script in scripts/qupath-utils/segmentation to use it from a script which further allows you to filter out detected cells based on shape measurements as well as fluorescence itensity in several channels and cell compartments.

"},{"location":"guide-qupath-objects.html#sam","title":"SAM","text":"

QuPath extension : https://github.com/ksugar/qupath-extension-sam Original repositories : samapi, SAM Reference papers : doi:10.1101/2023.06.13.544786, doi:10.48550/arXiv.2304.02643

This is more an interactive annotation tool than a fully automatic segmentation algorithm.

"},{"location":"guide-register-abba.html","title":"Registration with ABBA","text":"

The ABBA documentation is quite extensive and contains guided tutorials and a video tutorial. You should therefore check it out ! Nevertheless, you will find below some quick reminders.

"},{"location":"guide-register-abba.html#import-a-qupath-project","title":"Import a QuPath project","text":"

Always use ABBA with a QuPath project, if you import the images directly it will not be possible to export the results back to QuPath. In the toolbar, head to Import > Import QuPath Project.

  • Select the .qproj file corresponding to the QuPath project to be aligned.
  • Initial axis position : this is the initial position where to put your stack. It will be modified afterwards.
  • Axis increment between slices : this is the spatial spacing, in mm, between two slices. This would correspond to the slice thickness multiplied by the number of set. If your images are ordered from rostral to caudal, set it negative.

Warning

ABBA is not the most stable software, it is highly recommended to save in a different file each time you do anything.

"},{"location":"guide-register-abba.html#navigation","title":"Navigation","text":""},{"location":"guide-register-abba.html#interface","title":"Interface","text":"
  • Left Button + drag to select slices
  • Right Button for display options
  • Right Button + drag to browse the view
  • Middle Button to zoom in and or out
"},{"location":"guide-register-abba.html#right-panel","title":"Right panel","text":"

In the right panel, there is everything related to the images, both yours and the atlas.

In the Atlas Display section, you can turn on and off different channels (the first is the reference image, the last is the regions outlines). The Displayed slicing [atlas steps] slider can increase or decrease the number of displayed 2D slices extracted from the 3D volume. It is comfortable to set to to the same spacing as your slices. Remember it is in \"altas steps\", so for an atlas imaged at 10\u00b5m, a 120\u00b5m spacing corresponds to 12 atlas steps.

The Slices Display section lists all your slices. Ctrl+A to select all, and click on the Vis. header to make them visible. Then, you can turn on and off each channels (generally the NISSL channel and the ChAT channel will be used) by clicking on the corresponding header. Finally, set the display limits clicking on the empty header containing the colors.

Right Button in the main view to Change overlap mode twice to get the slices right under the atlas slices.

Tip

Every action in ABBA are stored and are cancellable with Right Button+Z, except the Interactive transform.

"},{"location":"guide-register-abba.html#find-position-and-angle","title":"Find position and angle","text":"

This is the hardest task. You need to drag the slices along the rostro-caudal axis and modify the virtual slicing angle (X Rotation [deg] and Y Rotation [deg] sliders at the bottom of the right panel) until you match the brain structures observed in both your images and the atlas.

Tip

With a high number of slices, most likely, it will be impossible to find a position and slicing angle that works for all your slices. In that case, you should procede in batch, eg. sub-stack of images with a unique position and slicing angle that works for all images in the sub-stack. Then, remove the remaining slices (select them, Right Button > Remove Selected Slices), but do not remove them from the QuPath project.

Procede as usual, including saving (note the slices range it corresponds to) and exporting the registration back to QuPath. Then, reimport the project in a fresh ABBA instance, remove the slices that were already registered and redo the whole process with the next sub-stack and so on.

Once you found the correct position and slicing angle, it must not change anymore, otherwise the registration operations you perform will not make any sense anymore.

"},{"location":"guide-register-abba.html#in-plane-registration","title":"In-plane registration","text":"

The next step is to deform your slices to match the corresponding atlas image, extracted from the 3D volume given the position and virtual slicing angle defined at the previous step.

Info

ABBA makes the choice to deform your slices to the atlas, but the transformations are invertible. This means that you will still be able to work on your raw data and deform the altas onto it instead.

In image processing, there are two kinds of deformation one can apply on an image :

  • Affine (or linear) : simple, image-wide, linear operations - translation, rotation, scaling, shearing.
  • Spline (or non-linear) : complex non-linear operations that can allow for local deformation.

Both can be applied manually or automatically (if the imaging quality allows it). You have different tools to achieve this, all of which can be combined in any order, except the Interactive transform tool (coarse, linear manual deformation).

Change the overlap mode (Right Button) to overlay the slice onto the atlas regions borders. Select the slice you want to align.

"},{"location":"guide-register-abba.html#coarse-linear-manual-deformation","title":"Coarse, linear manual deformation","text":"

While not mandatory, if this tool shall be used, it must be before any operation as it is not cancellable. Head to Register > Affine > Interactive transform. This will open a box where you can rotate, translate and resize the image to make a first, coarse alignment.

Close the box. Again, this is not cancellable. Afterwards, you're free to apply any numbers of transformations in any order.

"},{"location":"guide-register-abba.html#automatic-registration","title":"Automatic registration","text":"

This uses the elastix toolbox to compute the transformations needed to best match two images. It is available in both affine and spline mode, in the Register > Affine and Register > Spline menus respectively.

In both cases, it will open a dialog where you need to choose :

  • Atlas channels : the reference image of the atlas, usually channel number 0
  • Slices channels : the fluorescence channel that looks like the most to the reference image, usually channel number 0
  • Registration re-sampling (micrometers) : the pixel size to resize the images before registration, as it is a computationally intensive task. Going below 20\u00b5m won't help much.

For the Spline mode, there an additional parameter :

  • Number of control points along X : the algorithm will set points as a grid in the image and perform the transformations from those. The higher number of points, the more local transformations will be.
"},{"location":"guide-register-abba.html#manual-registration","title":"Manual registration","text":"

This uses BigWarp to manually deform the images with the mouse. It can be done from scratch (eg. you place the points yourself) or from a previous registration (either a previous BigWarp session or elastix in Spline mode).

"},{"location":"guide-register-abba.html#from-scratch","title":"From scratch","text":"

Register > Spline > BigWarp registration to launch the tool. Choose the atlas that allows you to best see the brain structures (usually the regions outlines channels, the last one), and the reference fluorescence channel.

It will open two viewers, called \"BigWarp moving image\" and \"BigWarp fixed image\". Briefly, they correspond to the two spaces you're working in, the \"Atlas space\" and the \"Slice space\".

Tip

Do not panick yet, while the explanations might be confusing (at least they were to me), in practice, it is easy, intuitive and can even be fun (sometimes, at small dose).

To browse the viewer, use Right Button + drag (Left Button is used to rotate the viewer), Middle Button zooms in and out.

The idea is to place points, called landmarks, that always go in pairs : one in the moving image and one where it corresponds to in the fixed image (or vice-versa). In practice, we will only work in the BigWarp fixed image viewer to place landmarks in both space in one click, then drag it to the corresponding location, with a live feedback of the transformation needed to go from one to another.

To do so :

  1. Press Space to switch to the \"Landmark mode\".

    Warning

    In \"Landmark mode\", Right Button can't be used to browse the view anymore. To do so, turn off the \"Landmark mode\" hitting Space again.

  2. Use Ctrl+Left Button to place a landmark.

    Info

    At least 4 landmarks are needed before activating the live-transform view.

  3. When there are at least 4 landmarks, hit T to activate the \"Transformed\" view. Transformed will be written at the bottom.

  4. Hold Left Button on a landmark to drag it to deform the image onto the atlas.
  5. Add as many landmarks as needed, when you're done, find the Fiji window called \"Big Warp registration\" that opened at the beginning and click OK.

Important remarks and tips

  • A landmark is a location where you said \"this location correspond to this one\". Therefore, BigWarp is not allowed to move this particular location. Everywhere else, it is free to transform the image without any restrictions, including the borders. Thus, it is a good idea to delimit the coarse contour of the brain with landmarks to constrain the registration.
  • Left Button without holding Ctrl will place a landmark in the fixed image only, without pair, and BigWarp won't like it. To delete landmarks, head to the \"Landmarks\" window that lists all of them. They highlight in the viewer upon selection. Hit Del to delete one. Alternatively, click on it on the viewer and hit Del.
"},{"location":"guide-register-abba.html#from-a-previous-registration","title":"From a previous registration","text":"

Head to Register > Edit last Registration to work on a previous registration.

If the previous registration was done with elastix (Spline) or BigWarp, it will launch the BigWarp interface exactly like above, but with landmarks already placed, either on a grid (elastix) or the one you manually placed (BigWarp).

Tip

It will ask which channels to use, you can modify the channel for your slices to work on two channels successively. For instance, one could make a first registration using the NISSL staining, then refine the motoneurons with the ChAT staining, if available.

"},{"location":"guide-register-abba.html#abba-state-file","title":"ABBA state file","text":"

ABBA can save the state you're in, from the File > Save State menu. It will be saved as a .abba file, which is actually a zip archive containing a bunch of JSON, listing every actions you made and in which order, meaning you will stil be able to cancel actions after quitting ABBA.

To load a state, quit ABBA, launch it again, then choose File > Load State and select the .abba file to carry on with the registration.

Save, save, save !

Those state files are cheap, eg. they are lightweight (less than 200KB). You should save the state each time you finish a slice, and you can keep all your files, without overwritting the previous ones, appending a number to its file name. This will allow to roll back to the previous slice in the event of any problem you might face.

"},{"location":"guide-register-abba.html#export-registration-back-to-qupath","title":"Export registration back to QuPath","text":""},{"location":"guide-register-abba.html#export-the-registration-from-abba","title":"Export the registration from ABBA","text":"

Once you are satisfied with your registration, select the registered slices and head to Export > QuPath > Export Registrations To QuPath Project. Check the box to make sure to get the latest registered regions.

It will export several files in the QuPath projects, including the transformed atlas regions ready to be imported in QuPath and the transformations parameters to be able to convert coordinates from the extension.

"},{"location":"guide-register-abba.html#import-the-registration-in-qupath","title":"Import the registration in QuPath","text":"

Make sure you installed the ABBA extension in QuPath.

From your project with an image open, the basic usage is to head to Extensions > ABBA > Load Atlas Annotations into Open Image. Choose to Split Left and Right Regions to make the two hemispheres independent, and choose the \"acronym\" to name the regions. The registered regions should be imported as Annotations in the image.

Tip

With ABBA in regular Fiji using the CCFv3 Allen mouse brain atlas, the left and right regions are flipped, because ABBA considers the slices as backward facing. The importAbba.groovy script located in scripts/qupath-utils-atlas allows you to flip left/right regions names. This is OK because the Allen brain is symmetrical by construction.

For more complex use, check the Groovy scripts in scripts/qupath-utils/atlas. ABBA registration is used throughout the guides, to either work with brain regions (and count objects for instance) or to get the detections' coordinates in the atlas space.

"},{"location":"main-citing.html","title":"Citing","text":"

While cuisto does not have a reference paper as of now, you can reference the GitHub repository.

Please make sure to cite all the softwares used in your research. Citations are usually the only metric used by funding agencies, so citing properly the tools used in your research ensures the continuation of those projects.

  • Fiji : https://imagej.net/software/fiji/#publication
  • QuPath : https://qupath.readthedocs.io/en/stable/docs/intro/citing.html
  • ABBA : doi:10.1101/2024.09.06.611625
  • Brainglobe :
    • AtlasAPI : https://brainglobe.info/documentation/brainglobe-atlasapi/index.html#citation
    • Brainrender : https://brainglobe.info/documentation/brainrender/index.html#citation
  • Allen brain atlas (CCFv3) : doi:10.1016/j.cell.2020.04.007
  • 3D Allen spinal cord atlas : doi:10.1016/j.crmeth.2021.100074
  • Skeleton analysis (for fibers-like segmentation) : doi:10.7717/peerj.4312
"},{"location":"main-configuration-files.html","title":"The configuration files","text":"

There are three configuration files : altas_blacklist, atlas_fusion and a modality-specific file, that we'll call config in this document. The former two are related to the atlas you're using, the latter is what is used by cuisto to know what and how to compute and display things. There is a fourth, optional, file, used to provide some information on a specific experiment, info.

The configuration files are in the TOML file format, that are basically text files formatted in a way that is easy to parse in Python. See here for a basic explanation of the syntax.

Most lines of each template file are commented to explain what each parameter do.

"},{"location":"main-configuration-files.html#atlas_blacklisttoml","title":"atlas_blacklist.toml","text":"Click to see an example file atlas_blacklist.toml
# TOML file to list Allen brain regions to ignore during analysis.\n# \n# It is used to blacklist regions and all descendants regions (\"WITH_CHILD\").\n# Objects belonging to those regions and their descendants will be discarded.\n# And you can specify an exact region where to remove objects (\"EXACT\"),\n# descendants won't be affected.\n# Use it to remove noise in CBX, ventricual systems and fiber tracts.\n# Regions are referenced by their exact acronym.\n#\n# Syntax :\n#   [WITH_CHILDS]\n#   members = [\"CBX\", \"fiber tracts\", \"VS\"]\n#\n#   [EXACT]\n#   members = [\"CB\"]\n\n\n[WITH_CHILDS]\nmembers = [\"CBX\", \"fiber tracts\", \"VS\"]\n\n[EXACT]\nmembers = [\"CB\"]\n

This file is used to filter out specified regions and objects belonging to them.

  • The atlas regions present in the members keys will be ignored. Objects whose parents are in here will be ignored as well.
  • In the [WITH_CHILDS] section, regions and objects belonging to those regions and all descending regions (child regions, as per the altas hierarchy) will be removed.
  • In the [EXACT] section, only regions and objects belonging to those exact regions are removed. Descendants regions are not taken into account.
"},{"location":"main-configuration-files.html#atlas_fusiontoml","title":"atlas_fusion.toml","text":"Click to see an example file atlas_blacklist.toml
# TOML file to determine which brain regions should be merged together.\n# Regions are referenced by their exact acronym.\n# The syntax should be the following :\n# \n#   [MY]\n#   name = \"Medulla\"  # new or existing full name\n#   acronym = \"MY\"  # new or existing acronym\n#   members = [\"MY-mot\", \"MY-sat\"]  # existing Allen Brain acronyms that should belong to the new region\n#\n# Then, regions labelled \"MY-mot\" and \"MY-sat\" will be labelled \"MY\" and will join regions already labelled \"MY\".\n# What's in [] does not matter but must be unique and is used to group.\n# The new \"name\" and \"acronym\" can be existing Allen Brain regions or a new (meaningful) one.\n# Note that it is case sensitive.\n\n[PHY]\nname = \"Perihypoglossal nuclei\"\nacronym = \"PHY\"\nmembers = [\"NR\", \"PRP\"]\n\n[NTS]\nname = \"Nucleus of the solitary tract\"\nacronym = \"NTS\"\nmembers = [\"ts\", \"NTSce\", \"NTSco\", \"NTSge\", \"NTSl\", \"NTSm\"]\n\n[AMB]\nname = \"Nucleus ambiguus\"\nacronym = \"AMB\"\nmembers = [\"AMBd\", \"AMBv\"]\n\n[MY]\nname = \"Medulla undertermined\"\nacronym = \"MYu\"\nmembers = [\"MY-mot\", \"MY-sat\"]\n\n[IRN]\nname = \"Intermediate reticular nucleus\"\nacronym = \"IRN\"\nmembers = [\"IRN\", \"LIN\"]\n

This file is used to group regions together, to customize the atlas' hierarchy. It is particularly useful to group smalls brain regions that are impossible to register precisely. Keys name, acronym and members should belong to a [section].

  • [section] is just for organizing, the name does not matter but should be unique.
  • name should be a human-readable name for your new region.
  • acronym is how the region will be refered to. It can be a new acronym, or an existing one.
  • members is a list of acronyms of atlas regions that should be part of the new one.
"},{"location":"main-configuration-files.html#configtoml","title":"config.toml","text":"Click to see an example file config_template.toml
########################################################################################\n# Configuration file for cuisto package\n# -----------------------------------------\n# This is a TOML file. It maps a key to a value : `key = value`.\n# Each key must exist and be filled. The keys' names can't be modified, except:\n#   - entries in the [channels.names] section and its corresponding [channels.colors] section,\n#   - entries in the [regions.metrics] section.                                                                                   \n#\n# It is strongly advised to NOT modify this template but rather copy it and modify the copy.\n# Useful resources :\n#   - the TOML specification : https://toml.io/en/\n#   - matplotlib colors : https://matplotlib.org/stable/gallery/color/color_demo.html\n#\n# Configuration file part of the python cuisto package.\n# version : 2.1\n########################################################################################\n\nobject_type = \"Cells\"  # name of QuPath base classification (eg. without the \": subclass\" part)\nsegmentation_tag = \"cells\"  # type of segmentation, matches directory name, used only in the full pipeline\n\n[atlas]  # information related to the atlas used\nname = \"allen_mouse_10um\"  # brainglobe-atlasapi atlas name\ntype = \"brain\"  # brain or cord (eg. registration done in ABBA or abba_python)\nmidline = 5700  # midline Z coordinates (left/right limit) in microns\noutline_structures = [\"root\", \"CB\", \"MY\", \"P\"]  # structures to show an outline of in heatmaps\n\n[channels]  # information related to imaging channels\n[channels.names]  # must contain all classifications derived from \"object_type\"\n\"marker+\" = \"Positive\"  # classification name = name to display\n\"marker-\" = \"Negative\"\n[channels.colors]  # must have same keys as names' keys\n\"marker+\" = \"#96c896\"  # classification name = matplotlib color (either #hex, color name or RGB list)\n\"marker-\" = \"#688ba6\"\n\n[hemispheres]  # information related to hemispheres\n[hemispheres.names]\nLeft = \"Left\"  # Left = name to display\nRight = \"Right\"  # Right = name to display\n[hemispheres.colors]  # must have same keys as names' keys\nLeft = \"#ff516e\"  # Left = matplotlib color (either #hex, color name or RGB list)\nRight = \"#960010\"  # Right = matplotlib color\n\n[distributions]  # spatial distributions parameters\nstereo = true  # use stereotaxic coordinates (Paxinos, only for brain)\nap_lim = [-8.0, 0.0]  # bins limits for anterio-posterior\nap_nbins = 75  # number of bins for anterio-posterior\ndv_lim = [-1.0, 7.0]  # bins limits for dorso-ventral\ndv_nbins = 50  # number of bins for dorso-ventral\nml_lim = [-5.0, 5.0]  # bins limits for medio-lateral\nml_nbins = 50  # number of bins for medio-lateral\nhue = \"channel\"  # color curves with this parameter, must be \"hemisphere\" or \"channel\"\nhue_filter = \"Left\"  # use only a subset of data. If hue=hemisphere : channel name, list of such or \"all\". If hue=channel : hemisphere name or \"both\".\ncommon_norm = true  # use a global normalization for each hue (eg. the sum of areas under all curves is 1)\n[distributions.display]\nshow_injection = false  # add a patch showing the extent of injection sites. Uses corresponding channel colors\ncmap = \"OrRd\"  # matplotlib color map for heatmaps\ncmap_nbins = 50  # number of bins for heatmaps\ncmap_lim = [1, 50]  # color limits for heatmaps\n\n[regions]  # distributions per regions parameters\nbase_measurement = \"Count\"  # the name of the measurement in QuPath to derive others from\nhue = \"channel\"  # color bars with this parameter, must be \"hemisphere\" or \"channel\"\nhue_filter = \"Left\"  # use only a subset of data. If hue=hemisphere : channel name, list of such or \"all\". If hue=channel : hemisphere name or \"both\".\nhue_mirror = false  # plot two hue_filter in mirror instead of discarding the other\nnormalize_starter_cells = false  # normalize non-relative metrics by the number of starter cells\n[regions.metrics]  # names of metrics. Do not change the keys !\n\"density \u00b5m^-2\" = \"density \u00b5m^-2\"\n\"density mm^-2\" = \"density mm^-2\"\n\"coverage index\" = \"coverage index\"\n\"relative measurement\" = \"relative count\"\n\"relative density\" = \"relative density\"\n[regions.display]\nnregions = 18  # number of regions to display (sorted by max.)\norientation = \"h\"  # orientation of the bars (\"h\" or \"v\")\norder = \"max\"  # order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order\ndodge = true  # enforce the bar not being stacked\nlog_scale = false  # use log. scale for metrics\n[regions.display.metrics]  # name of metrics to display\n\"count\" = \"count\"  # real_name = display_name, with real_name the \"values\" in [regions.metrics]\n\"density mm^-2\" = \"density (mm^-2)\"\n\n[files]  # full path to information TOML files\nblacklist = \"../../atlas/atlas_blacklist.toml\"\nfusion = \"../../atlas/atlas_fusion.toml\"\noutlines = \"/data/atlases/allen_mouse_10um_outlines.h5\"\ninfos = \"../../configs/infos_template.toml\"\n

This file is used to configure cuisto behavior. It specifies what to compute, how, and display parameters such as colors associated to each classifications, hemisphere names, distributions bins limits...

Warning

When editing your config.toml file, you're allowed to modify the keys only in the [channels] section.

Click for a more readable parameters explanation

object_type : name of QuPath base classification (eg. without the \": subclass\" part) segmentation_tag : type of segmentation, matches directory name, used only in the full pipeline

atlas Information related to the atlas used

name : brainglobe-atlasapi atlas name type : \"brain\" or \"cord\" (eg. registration done in ABBA or abba_python). This will determine whether to flip Left/Right when determining detections hemisphere based on their coordinates. Also adapts the axes in the 2D heatmaps. midline : midline Z coordinates (left/right limit) in microns to determine detections hemisphere based on their coordinates. outline_structures : structures to show an outline of in heatmaps

channels Information related to imaging channels

names Must contain all classifications derived from \"object_type\" you want to process. In the form subclassification name = name to display on the plots

\"marker+\" : classification name = name to display \"marker-\" : add any number of sub-classification

colors Must have same keys as \"names\" keys, in the form subclassification name = color, with color specified as a matplotlib named color, an RGB list or an hex code.

\"marker+\" : classification name = matplotlib color \"marker-\" : must have the same entries as \"names\".

hemispheres Information related to hemispheres, same structure as channels

names

Left : Left = name to display Right : Right = name to display

colors Must have same keys as names' keys

Left : ff516e\" # Left = matplotlib color (either #hex, color name or RGB list) Right : 960010\" # Right = matplotlib color

distributions Spatial distributions parameters

stereo : use stereotaxic coordinates (as in Paxinos, only for mouse brain CCFv3) ap_lim : bins limits for anterio-posterior in mm ap_nbins : number of bins for anterio-posterior dv_lim : bins limits for dorso-ventral in mm dv_nbins : number of bins for dorso-ventral ml_lim : bins limits for medio-lateral in mm ml_nbins : number of bins for medio-lateral hue : color curves with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

common_norm : use a global normalization (eg. the sum of areas under all curves is 1). Otherwise, normalize each hue individually

display Display parameters

show_injection : add a patch showing the extent of injection sites. Uses corresponding channel colors. Requires the information TOML configuration file set up cmap : matplotlib color map for 2D heatmaps cmap_nbins : number of bins for 2D heatmaps cmap_lim : color limits for 2D heatmaps

regions Distributions per regions parameters

base_measurement : the name of the measurement in QuPath to derive others from. Usually \"Count\" or \"Length \u00b5m\" hue : color bars with this parameter, must be \"hemisphere\" or \"channel\" hue_filter : use only a subset of data

  • If hue=hemisphere : it should be a channel name, a list of such or \"all\"
  • If hue=channel : it should be a hemisphere name or \"both\"

hue_mirror : plot two hue_filter in mirror instead of discarding the others. For example, if hue=channel and hue_filter=\"both\", plots the two hemisphere in mirror. normalize_starter_cells : normalize non-relative metrics by the number of starter cells

metrics Names of metrics. The keys are used internally in cuisto as is so should NOT be modified. The values will only chang etheir names in the ouput file

\"density \u00b5m^-2\" : relevant name \"density mm^-2\" : relevant name \"coverage index\" : relevant name \"relative measurement\" : relevant name \"relative density\" : relevant name

display

nregions : number of regions to display (sorted by max.) orientation : orientation of the bars (\"h\" or \"v\") order : order the regions by \"ontology\" or by \"max\". Set to \"max\" to provide a custom order dodge : enforce the bar not being stacked log_scale : use log. scale for metrics

metrics name of metrics to display

\"count\" : real_name = display_name, with real_name the \"values\" in [regions.metrics] \"density mm^-2\"

files Full path to information TOML files and atlas outlines for 2D heatmaps.

blacklist fusion outlines infos

"},{"location":"main-configuration-files.html#infotoml","title":"info.toml","text":"Click to see an example file info_template.toml
# TOML file to specify experimental settings of each animals.\n# Syntax should be :\n#   [animalid0]  # animal ID\n#   slice_thickness = 30  # slice thickness in microns\n#   slice_spacing = 60  # spacing between two slices in microns\n#   [animalid0.marker-name]  # [{Animal id}.{segmented channel name}]\n#   starter_cells = 190  # number of starter cells\n#   injection_site = [x, y, z]  # approx. injection site in CCFv3 coordinates\n#\n# --------------------------------------------------------------------------\n[animalid0]\nslice_thickness = 30\nslice_spacing = 60\n[animalid0.\"marker+\"]\nstarter_cells = 150\ninjection_site = [ 10.8937328, 6.18522070, 6.841855301 ]\n[animalid0.\"marker-\"]\nstarter_cells = 175\ninjection_site = [ 10.7498512, 6.21545461, 6.815487203 ]\n# --------------------------------------------------------------------------\n[animalid1-SC]\nslice_thickness = 30\nslice_spacing = 120\n[animalid1-SC.EGFP]\nstarter_cells = 250\ninjection_site = [ 10.9468211, 6.3479642, 6.0061113 ]\n[animalid1-SC.DsRed]\nstarter_cells = 275\ninjection_site = [ 10.9154874, 6.2954872, 8.1587125 ]\n# --------------------------------------------------------------------------\n

This file is used to specify injection sites for each animal and each channel, to display it in distributions.

"},{"location":"main-getting-help.html","title":"Getting help","text":"

For help in QuPath, ABBA, Fiji or any image processing-related questions, your one stop is the image.sc forum. There, you can search with specific tags (#qupath, #abba, ...). You can also ask questions or even answer to some by creating an account !

For help with cuisto in particular, you can open an issue in Github (which requires an account as well), or send an email to me or Antoine Lesage.

"},{"location":"main-getting-started.html","title":"Getting started","text":""},{"location":"main-getting-started.html#quick-start","title":"Quick start","text":"
  1. Install QuPath, ABBA and conda.
  2. Create an environment :
    conda create -c conda-forge -n cuisto-env python=3.12\n
  3. Activate it :
    conda activate cuisto-env\n
  4. Download the latest release .zip, unzip it and install it with pip, from inside the cuisto-xxx folder :
    pip install .\n
    If you want to build the doc :
    pip install .[doc]\n
"},{"location":"main-getting-started.html#slow-start","title":"Slow start","text":"

Tip

If all goes well, you shouldn't need any admin rights to install the various pieces of software used before cuisto.

Important

Remember to cite all softwares you use ! See Citing.

"},{"location":"main-getting-started.html#qupath","title":"QuPath","text":"

QuPath is an \"open source software for bioimage analysis\". You can install it from the official website : https://qupath.github.io/. The documentation is quite clear and comprehensive : https://qupath.readthedocs.io/en/stable/index.html.

This is where you'll create QuPath projects, in which you'll be able to browse your images, annotate them, import registered brain regions and find objects of interests (via automatic segmentation, thresholding, pixel classification, ...). Then, those annotations and detections can be exported to be processed by cuisto.

"},{"location":"main-getting-started.html#aligning-big-brain-and-atlases-abba","title":"Aligning Big Brain and Atlases (ABBA)","text":"

This is the tool you'll use to register 2D histological sections to 3D atlases. See the dedicated page.

"},{"location":"main-getting-started.html#python-virtual-environment-manager-conda","title":"Python virtual environment manager (conda)","text":"

The cuisto package is written in Python. It depends on scientific libraries (such as NumPy, pandas and many more). Those libraries need to be installed in versions that are compatible with each other and with cuisto. To make sure those versions do not conflict with other Python tools you might be using (deeplabcut, abba_python, ...), we will install cuisto and its dependencies in a dedicated virtual environment.

conda is a software that takes care of this. It comes with a \"base\" environment, from which we will create and manage other, project-specific environments. It is also used to download and install python in each of those environments, as well as third-party libraries. conda in itself is free and open-source and can be used freely by anyone.

It is included with the Anaconda distribution, which is subject to specific terms of service, which state that unless you're an individual, a member of a company with less than 200 employees or a member of an university (but not a national research lab) it's free to use, otherwise, you need to pay a licence. conda, while being free, is by default configured to use the \"defaults\" channel to fetch the packages (including Python itself), a repository operated by Anaconda, which is, itself, subject to the Anaconda terms of service.

In contrast, conda-forge is a community-run repository that contains more numerous and more update-to-date packages. This is free to use for anyone. The idea is to use conda directly (instead of Anaconda graphical interface) and download packages from conda-forge (instead of the Anaconda-run defaults). To try to decipher this mess, Anaconda provides this figure :

Furthermore, the \"base\" conda environment installed with the Anaconda distribution is bloated and already contains tons of libraries, and tends to self-destruct at some point (eg. becomes unable to resolve the inter-dependencies), which makes you unable to install new libraries nor create new environments.

This is why it is highly recommended to install Miniconda instead, a minimal installer for conda, and configure it to use the free, community-run channel conda-forge, or, even better, use Miniforge which is basically the same but pre-configured to use conda-forge. The only downside is that will not get the Anaonda graphical user interface and you'll need to use the terminal instead, but worry not ! We got you covered.

  1. Download and install Miniforge (choose the latest release for your system). During the installation, choose to install for the current user, add conda to PATH and make python the default interpreter.
  2. Open a terminal (PowerShell in Windows). Run :
    conda init\n
    This will activate conda and its base environment whenever you open a new PowerShell window. Now, when opening a new PowerShell (or terminal), you should see a prompt like this :
    (base) PS C:\\Users\\myname>\n

Tip

If Anaconda is already installed and you don't have the rights to uninstall it, you'll have to use it instead. You can launch the \"Anaconda Prompt (PowerShell)\", run conda init. Open a regular PowerShell window and run conda config --add channels conda-forge, so that subsequent installations and environments creation will fetch required dependencies from conda-forge.

"},{"location":"main-getting-started.html#installation","title":"Installation","text":"

This section explains how to actually install the cuisto package. The following commands should be run from a terminal (PowerShell). Remember that the -c conda-forge bits are not necessary if you installed conda with the miniforge distribution.

  1. Create a virtual environment with python 3.12 :
    conda create -c conda-forge -n cuisto-env python=3.12\n
  2. Get a copy of the cuisto Source code .zip package, from the Releases page.
  3. We need to install it inside the cuisto-env environment we just created. First, you need to activate the cuisto-env environment :
    conda activate cuisto-env\n
    Now, the prompt should look like this :
    (cuisto-env) PS C:\\Users\\myname>\n
    This means that Python packages will now be installed in the cuisto-env environment and won't conflict with other toolboxes you might be using. Then, we use pip to install cuisto. pip was installed with Python, and will scan the cuisto folder, specifically the \"pyproject.toml\" file that lists all the required dependencies. To do so, you can either :
    • pip install /path/to/cuisto\n
    • Change directory from the terminal :
      cd /path/to/cuisto\n
      Then install the package, \".\" denotes \"here\" :
      pip install .\n
    • Use the file explorer to get to the cuisto folder, use Shift+Right Button to \"Open PowerShell window here\" and run :
      pip install .\n

cuisto is now installed inside the cuisto-env environment and will be available in Python from that environment !

Tip

You will need to perform step 3. each time you want to update the package.

If you already have registered data and cells in QuPath, you can export Annotations and Detections as TSV files and head to the Example section.

"},{"location":"main-using-notebooks.html","title":"Using notebooks","text":"

A Jupyter notebook is a way to use Python in an interactive manner. It uses cells that contain Python code, and that are to be executed to immediately see the output, including figures.

You can see some rendered notebooks in the examples here, but you can also download them (downward arrow button on the top right corner of each notebook) and run them locally with your own data.

To do so, you can either use an integrated development environment (basically a supercharged text editor) that supports Jupyter notebooks, or directly the Jupyter web interface.

IDEJupyter web interface

You can use for instance Visual Studio Code, also known as vscode.

  1. Download it and install it.
  2. Launch vscode.
  3. Follow or skip tutorials.
  4. In the left panel, open Extension (squared pieces).
  5. Install the \"Python\" and \"Jupyter\" extensions (by Microsoft).
  6. You now should be able to open .ipynb (notebooks) files with vscode. On the top right, you should be able to Select kernel : choose \"cuisto-env\".
  1. Create a folder dedicated to working with notebooks, for example \"Documents\\notebooks\".
  2. Copy the notebooks you're interested in in this folder.
  3. Open a terminal inside this folder (by either using cd Documents\\notebooks or, in the file explorer in your \"notebooks\" folder, Shift+Right Button to \"Open PowerShell window here\")
  4. Activate the conda environment :
    conda activate cuisto-env\n
  5. Launch the Jupyter Lab web interface :
    jupyter lab\n
    This should open a web page where you can open the ipynb files.
"},{"location":"tips-abba.html","title":"ABBA","text":""},{"location":"tips-brain-contours.html","title":"Brain contours","text":"

With cuisto, it is possible to plot 2D heatmaps on brain contours.

All the detections are projected in a single plane, thus it is up to you to select a relevant data range. It is primarily intended to give a quick, qualitative overview of the spreading of your data.

To do so, it requires the brain regions outlines, stored in a hdf5 file. This can be generated with brainglobe-atlasapi. The generate_atlas_outlines.py located in scripts/atlas will show you how to make such a file, that the cuisto.display module can use.

Alternatively it is possible to directly plot density maps without cuisto, using brainglobe-heatmap. An example is shown here.

"},{"location":"tips-formats.html","title":"Data format","text":""},{"location":"tips-formats.html#some-concepts","title":"Some concepts","text":""},{"location":"tips-formats.html#tiles","title":"Tiles","text":"

The representation of an image in a computer is basically a table where each element represents the pixel value (see more here). It can be n-dimensional, where the typical dimensions would be \\((x, y, z)\\), time and the fluorescence channels.

In large images, such as histological slices that are more than 10000\\(\\times\\)10000 pixels, a strategy called tiling is used to optimize access to specific regions in the image. Storing the whole image at once in a file would imply to load the whole thing at once in the memory (RAM), even though one would only need to access a given rectangular region with a given zoom. Instead, the image is stored as tiles, small squares (512--2048 pixels) that pave the whole image and are used to reconstruct the original image. Therefore, when zooming-in, only the relevant tiles are loaded and displayed, allowing for smooth large image navigation. This process is done seamlessly by software like QuPath and BigDataViewer (the Fiji plugin ABBA is based on) when loading tiled images. This is also leveraged for image processing in QuPath, which will work on tiles instead of the whole image to not saturate your computer RAM.

Most images are already tiled, including Zeiss CZI images. Note that those tiles do not necessarily correspond to the actual, real-world, tiles the microscope did to image the whole slide.

"},{"location":"tips-formats.html#pyramids","title":"Pyramids","text":"

In the same spirit as tiles, it would be a waste to have to load the entire image (and all the tiles) at once when viewing the image at max zoom-out, as your monitor nor your eyes would handle it. Instead, smaller, rescaled versions of the original image are stored alongside it, and depending on the zoom you are using, the sub-resolution version is displayed. Again, this is done seamlessly by QuPath and ABBA, allowing you to quickly switch from an image to another, without having to load the GB-sized image. Also, for image processing that does not require the original pixel size, QuPath can also leverage pyramids to go faster.

Usually, upon openning a CZI file in ZEN, there is a pop-up suggesting you to generate pyramids. It is a very good idea to say yes, wait a bit and save the file so that the pyramidal levels are saved within the file.

"},{"location":"tips-formats.html#metadata","title":"Metadata","text":"

Metadata, while often overlooked, are of paramount importance in microscopy data. It allows both softwares and users to interpret the raw data of images, eg. the values of each pixels. Most image file formats support this, including the microcope manufacturer file formats. Metadata may include :

  • Pixel size. Usually expressed in \u00b5m for microscopy, this maps computer pixel units into real world distance. QuPath and ABBA uses that calibration to scale your image properly, so that it match the atlas you'll register your slices on,
  • Channels colors and names,
  • Image type (fluorescence, brightfield, ...),
  • Dimensions,
  • Magnification...

Pixel size is the parameter that is absolutely necessary. Channel names and colors are more a quality of life feature, to make sure not to mix your difference fluorescence channels. CZI files or exported OME-TIFF files include this out of the box so you don't really need to pay attention.

"},{"location":"tips-formats.html#bio-formats","title":"Bio-formats","text":"

Bio-formats is an initiative of the Open Microscopy Environment (OME) consortium, aiming at being able to read proprietary microscopy image data and metadata. It is used in QuPath, Fiji and ABBA.

This page summarizes the level of support of numerous file formats. You can see that Zeiss CZI files and Leica LIF are quite well supported, and should therefore work out of the box in QuPath.

"},{"location":"tips-formats.html#zeiss-czi-files","title":"Zeiss CZI files","text":"

QuPath and ABBA supports any Bio-formats supported, tiled, pyramidal images.

If you're in luck, adding the pyramidal CZI file to your QuPath project will just work. If it doesn't, you'll notice immediately : the tiles will be shuffled and you'll see only a part of the image instead of the whole one. Unfortunately I was not able to determine why this happens and did not find a way to even predict if a file will or will not work.

In the event you experience this bug, you'll need to export the CZI files to OME-TIFF files from ZEN, then generate tiled pyramidal images with the pyramid-creator package that you can find here.

"},{"location":"tips-formats.html#markdown-md-files","title":"Markdown (.md) files","text":"

Markdown is a markup language to create formatted text. It is basically a simple text file that could be opened with any text editor software (notepad and the like), but features specific tags to format the text with heading levels, typesetting (bold, itallic), links, lists... This very page is actually written in markdown, and the engine that builds it renders the text in a nicely formatted manner.

If you open a .md file with vscode for example, you'll get a magnigying glass on the top right corner to switch to the rendered version of the file.

"},{"location":"tips-formats.html#toml-toml-files","title":"TOML (.toml) files","text":"

TOML, or Tom's Obvious Minimal Language, is a configuration file format (similar to YAML). Again, it is basically a simple text file that can be opened with any text editor and is human-readable, but also computer-readable. This means that it is easy for most software and programming language to parse the file to associate a variable (or \"key\") to a value, thus making it a good file format for configuration. It is used in cuisto (see The configuration files page).

The syntax looks like this :

# a comment, ignored by the computer\nkey1 = 10  # the key \"key1\" is mapped to the number 10\nkey2 = \"something\"  # \"key2\" is mapped to the string \"something\"\nkey3 = [\"something else\", 1.10, -25]  # \"key3\" is mapped to a list with 3 elements\n[section]  # we can declare sections\nkey1 = 5  # this is not \"key1\", it actually is section.key1\n[section.example]  # we can have nested sections\nkey1 = true  # this is section.example.key1, mapped to the boolean True\n

You can check the full specification of this language here.

"},{"location":"tips-formats.html#csv-csv-tsv-files","title":"CSV (.csv, .tsv) files","text":"

CSV (or TSV) stands for Comma-Separated Values (or Tab-Separated Values) and is, once again, a simple text file formatted in a way that allows LibreOffice Calc (or Excel) to open them as a table. Lines of the table are delimited with new lines, and columns are separated with commas (,) or tabulations. Those files are easily parsed by programming languages (including Python). QuPath can export annotations and detections measurements in TSV format.

"},{"location":"tips-formats.html#json-and-geojson-files","title":"JSON and GeoJSON files","text":"

JSON is a \"data-interchange format\". It is used to store data, very much like toml, but supports more complex data and is more efficient to read and write, but is less human-readable. It is used in cuisto to store fibers-like objects coordinates, as they can contain several millions of points (making CSV not usable).

GeoJson is a file format used to store geographic data structures, basically objects coordinates with various shapes. It is based on and compatible with JSON, which makes it easy to parse in numerous programming language. It used in QuPath to import and export objects, that can be point, line, polygons...

"},{"location":"tips-qupath.html","title":"QuPath","text":""},{"location":"tips-qupath.html#custom-scripts","title":"Custom scripts","text":"

While QuPath graphical user interface (GUI) should meet a lot of your needs, it is very convenient to use scripting to automate certain tasks, execute them in batch (on all your images) and do things you couldn't do otherwise. QuPath uses the Groovy programming language, which is mostly Java.

Warning

Not all commands will appear in the history.

In QuPath, in the left panel in the \"Workflow\" tab, there is an history of most of the commands you used during the session. On the bottom, you can click on Create workflow to select the relevant commands and create a script. This will open the built-in script editor that will contain the groovy version of what you did graphically.

Tip

The scripts/qupath-utils folder contains a bunch of utility scripts.

They can be run in batch with the three-dotted menu on the bottom right corner of the script editor : Run for project, then choose the images you want the script to run on.

"},{"location":"demo_notebooks/cells_distributions.html","title":"Cells distributions","text":"

This notebook shows how to load data exported from QuPath, compute metrics and display them, according to the configuration file. This is meant for a single-animal.

There are some conventions that need to be met in the QuPath project so that the measurements are usable with cuisto:

  • Objects' classifications must be derived, eg. be in the form \"something: else\". The primary classification (\"something\") will be refered to \"object_type\" and the secondary classification (\"else\") to \"channel\" in the configuration file.
  • Only one \"object_type\" can be processed at once, but supports any numbers of channels.
  • Annotations (brain regions) must have properly formatted measurements. For punctual objects, it would be the count. Run the \"add_regions_count.groovy\" script to add them. The measurements names must be in the form \"something: else name\", for instance, \"something: else Count\". \"name\" is refered to \"base_measurement\" in the configuration file.

You should copy this notebook, the configuration file and the atlas-related configuration files (blacklist and fusion) elsewhere and edit them according to your need.

The data was generated from QuPath with stardist cell detection on toy data.

In\u00a0[1]: Copied!
import pandas as pd\n\nimport cuisto\n
import pandas as pd import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_cells.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_cells.toml\" In\u00a0[3]: Copied!
# - Files\n# animal identifier\nanimal = \"animalid0\"\n# set the full path to the annotations tsv file from QuPath\nannotations_file = \"../../resources/cells_measurements_annotations.tsv\"\n# set the full path to the detections tsv file from QuPath\ndetections_file = \"../../resources/cells_measurements_detections.tsv\"\n
# - Files # animal identifier animal = \"animalid0\" # set the full path to the annotations tsv file from QuPath annotations_file = \"../../resources/cells_measurements_annotations.tsv\" # set the full path to the detections tsv file from QuPath detections_file = \"../../resources/cells_measurements_detections.tsv\" In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.config.Config(config_file)\n
# get configuration cfg = cuisto.config.Config(config_file) In\u00a0[5]: Copied!
# read data\ndf_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\ndf_detections = pd.read_csv(detections_file, index_col=\"Object ID\", sep=\"\\t\")\n\n# remove annotations that are not brain regions\ndf_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\ndf_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n\n# convert atlas coordinates from mm to microns\ndf_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[\n    [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]\n].multiply(1000)\n\n# have a look\ndisplay(df_annotations.head())\ndisplay(df_detections.head())\n
# read data df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\") df_detections = pd.read_csv(detections_file, index_col=\"Object ID\", sep=\"\\t\") # remove annotations that are not brain regions df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"] df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"] # convert atlas coordinates from mm to microns df_detections[[\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"]] = df_detections[ [\"Atlas_X\", \"Atlas_Y\", \"Atlas_Z\"] ].multiply(1000) # have a look display(df_annotations.head()) display(df_detections.head()) Image Object type Name Classification Parent ROI Centroid X \u00b5m Centroid Y \u00b5m Cells: marker+ Count Cells: marker- Count ID Side Parent ID Num Detections Num Cells: marker+ Num Cells: marker- Area \u00b5m^2 Perimeter \u00b5m Object ID 4781ed63-0d8e-422e-aead-b685fbe20eb5 animalid0_030.ome.tiff Annotation Root NaN Root object (Image) Geometry 5372.5 3922.1 0 0 NaN NaN NaN 2441 136 2305 31666431.6 37111.9 aa4b133d-13f9-42d9-8c21-45f143b41a85 animalid0_030.ome.tiff Annotation root Right: root Root Polygon 7094.9 4085.7 0 0 997 0.0 NaN 1284 41 1243 15882755.9 18819.5 42c3b914-91c5-4b65-a603-3f9431717d48 animalid0_030.ome.tiff Annotation grey Right: grey root Geometry 7256.8 4290.6 0 0 8 0.0 997.0 1009 24 985 12026268.7 49600.3 887af3eb-4061-4f8a-aa4c-fe9b81184061 animalid0_030.ome.tiff Annotation CB Right: CB grey Geometry 7778.7 3679.2 0 16 512 0.0 8.0 542 5 537 6943579.0 30600.2 adaabc05-36d1-4aad-91fe-2e904adc574f animalid0_030.ome.tiff Annotation CBN Right: CBN CB Geometry 6790.5 3567.9 0 0 519 0.0 512.0 55 1 54 864212.3 7147.4 Image Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z Object ID 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11523.0 4272.4 4276.7 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11520.2 4278.4 4418.6 481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11506.0 4317.2 4356.3 fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11528.4 4257.4 4336.4 3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11548.7 4203.3 4294.3 In\u00a0[6]: Copied!
# get distributions per regions, spatial distributions and coordinates\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n    animal, df_annotations, df_detections, cfg, compute_distributions=True\n)\n\n# have a look\ndisplay(df_regions.head())\ndisplay(df_coordinates.head())\n
# get distributions per regions, spatial distributions and coordinates df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal( animal, df_annotations, df_detections, cfg, compute_distributions=True ) # have a look display(df_regions.head()) display(df_coordinates.head()) Name hemisphere Area \u00b5m^2 Area mm^2 count density \u00b5m^-2 density mm^-2 coverage index relative count relative density channel animal 0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 0.00012 0.002132 0.205275 Positive animalid0 0 ACVII Left 8307.1 0.008307 1 0.00012 120.378953 0.00012 0.000189 0.020671 Negative animalid0 1 ACVII Right 7061.4 0.007061 0 0.0 0.0 0.0 0.0 0.0 Positive animalid0 1 ACVII Right 7061.4 0.007061 1 0.000142 141.614977 0.000142 0.000144 0.021646 Negative animalid0 2 ACVII both 15368.5 0.015369 1 0.000065 65.068159 0.000065 0.001362 0.153797 Positive animalid0 Image Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z hemisphere channel Atlas_AP Atlas_DV Atlas_ML animal Object ID 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5230 4.2724 4.2767 Right Negative -6.433716 3.098278 -1.4233 animalid0 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5202 4.2784 4.4186 Right Negative -6.431449 3.104147 -1.2814 animalid0 481a519b-8b40-4450-9ec6-725181807d72 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5060 4.3172 4.3563 Right Negative -6.420685 3.141780 -1.3437 animalid0 fd28e09c-2c64-4750-b026-cd99e3526a57 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5284 4.2574 4.3364 Right Negative -6.437788 3.083737 -1.3636 animalid0 3d9ce034-f2ed-4c73-99be-f782363cf323 animalid0_030.ome.tiff Detection NaN Cells: marker- VeCB Polygon 11.5487 4.2033 4.2943 Right Negative -6.453296 3.031224 -1.4057 animalid0 In\u00a0[7]: Copied!
# plot distributions per regions\nfigs_regions = cuisto.display.plot_regions(df_regions, cfg)\n# specify which regions to plot\n# figs_regions = cuisto.display.plot_regions(df_regions, cfg, names_list=[\"GRN\", \"IRN\", \"MDRNv\"])\n\n# save as svg\n# figs_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_count.svg\")\n# figs_regions[1].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_density.svg\")\n
# plot distributions per regions figs_regions = cuisto.display.plot_regions(df_regions, cfg) # specify which regions to plot # figs_regions = cuisto.display.plot_regions(df_regions, cfg, names_list=[\"GRN\", \"IRN\", \"MDRNv\"]) # save as svg # figs_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_count.svg\") # figs_regions[1].savefig(r\"C:\\Users\\glegoc\\Downloads\\regions_density.svg\") In\u00a0[8]: Copied!
# plot 1D distributions\nfig_distrib = cuisto.display.plot_1D_distributions(\n    dfs_distributions, cfg, df_coordinates=df_coordinates\n)\n
# plot 1D distributions fig_distrib = cuisto.display.plot_1D_distributions( dfs_distributions, cfg, df_coordinates=df_coordinates )

If there were several animal in the measurement file, it would be displayed as mean +/- sem instead.

In\u00a0[9]: Copied!
# plot heatmap (all types of cells pooled)\nfig_heatmap = cuisto.display.plot_2D_distributions(df_coordinates, cfg)\n
# plot heatmap (all types of cells pooled) fig_heatmap = cuisto.display.plot_2D_distributions(df_coordinates, cfg)"},{"location":"demo_notebooks/density_map.html","title":"Density map","text":"

Draw 2D heatmaps as density isolines.

This notebook does not actually use histoquant and relies only on brainglobe-heatmap to extract brain structures outlines.

Only the detections measurements with atlas coordinates exported from QuPath are used.

You need to select the range of data to be used, the regions outlines will be extracted at the centroid of that range. Therefore, a range that is too large will be misleading and irrelevant.

In\u00a0[1]: Copied!
import brainglobe_heatmap as bgh\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n
import brainglobe_heatmap as bgh import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as sns In\u00a0[2]: Copied!
# path to the exported measurements from QuPath\nfilename = \"../../resources/cells_measurements_detections.tsv\"\n
# path to the exported measurements from QuPath filename = \"../../resources/cells_measurements_detections.tsv\"

Settings

In\u00a0[3]: Copied!
# atlas to use\natlas_name = \"allen_mouse_10um\"\n# brain regions whose outlines will be plotted\nregions = [\"root\", \"CB\", \"MY\", \"GRN\", \"IRN\"]\n# range to include, in Allen coordinates, in microns\nap_lims = [9800, 10000]  # lims : [0, 13200] for coronal\nml_lims = [5600, 5800]  # lims : [0, 11400] for sagittal\ndv_lims = [3900, 4100]  # lims : [0, 8000] for top\n# number of isolines\nnlevels = 5\n# color mapping between classification and matplotlib color\npalette = {\"Cells: marker-\": \"#d8782f\", \"Cells: marker+\": \"#8ccb73\"}\n
# atlas to use atlas_name = \"allen_mouse_10um\" # brain regions whose outlines will be plotted regions = [\"root\", \"CB\", \"MY\", \"GRN\", \"IRN\"] # range to include, in Allen coordinates, in microns ap_lims = [9800, 10000] # lims : [0, 13200] for coronal ml_lims = [5600, 5800] # lims : [0, 11400] for sagittal dv_lims = [3900, 4100] # lims : [0, 8000] for top # number of isolines nlevels = 5 # color mapping between classification and matplotlib color palette = {\"Cells: marker-\": \"#d8782f\", \"Cells: marker+\": \"#8ccb73\"} In\u00a0[4]: Copied!
df = pd.read_csv(filename, sep=\"\\t\")\ndisplay(df.head())\n
df = pd.read_csv(filename, sep=\"\\t\") display(df.head())
 Image Object ID Object type Name Classification Parent ROI Atlas_X Atlas_Y Atlas_Z 0 animalid0_030.ome.tiff 5ff386a8-5abd-46d1-8e0d-f5c5365457c1 Detection NaN Cells: marker- VeCB Polygon 11.5230 4.2724 4.2767 1 animalid0_030.ome.tiff 9a2a9a8c-acbe-4308-bc5e-f3c9fd1754c0 Detection NaN Cells: marker- VeCB Polygon 11.5202 4.2784 4.4186 2 animalid0_030.ome.tiff 481a519b-8b40-4450-9ec6-725181807d72 Detection NaN Cells: marker- VeCB Polygon 11.5060 4.3172 4.3563 3 animalid0_030.ome.tiff fd28e09c-2c64-4750-b026-cd99e3526a57 Detection NaN Cells: marker- VeCB Polygon 11.5284 4.2574 4.3364 4 animalid0_030.ome.tiff 3d9ce034-f2ed-4c73-99be-f782363cf323 Detection NaN Cells: marker- VeCB Polygon 11.5487 4.2033 4.2943 

Here we can filter out classifications we don't wan't to display.

In\u00a0[5]: Copied!
# select objects\n# df = df[df[\"Classification\"] == \"example: classification\"]\n
# select objects # df = df[df[\"Classification\"] == \"example: classification\"] In\u00a0[6]: Copied!
# get outline coordinates in coronal (=frontal) orientation\ncoords_coronal = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"frontal\",\n    atlas_name=atlas_name,\n    position=(np.mean(ap_lims), 0, 0),\n)\n# get outline coordinates in sagittal orientation\ncoords_sagittal = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"sagittal\",\n    atlas_name=atlas_name,\n    position=(0, 0, np.mean(ml_lims)),\n)\n# get outline coordinates in top (=horizontal) orientation\ncoords_top = bgh.get_structures_slice_coords(\n    regions,\n    orientation=\"horizontal\",\n    atlas_name=atlas_name,\n    position=(0, np.mean(dv_lims), 0),\n)\n
# get outline coordinates in coronal (=frontal) orientation coords_coronal = bgh.get_structures_slice_coords( regions, orientation=\"frontal\", atlas_name=atlas_name, position=(np.mean(ap_lims), 0, 0), ) # get outline coordinates in sagittal orientation coords_sagittal = bgh.get_structures_slice_coords( regions, orientation=\"sagittal\", atlas_name=atlas_name, position=(0, 0, np.mean(ml_lims)), ) # get outline coordinates in top (=horizontal) orientation coords_top = bgh.get_structures_slice_coords( regions, orientation=\"horizontal\", atlas_name=atlas_name, position=(0, np.mean(dv_lims), 0), ) In\u00a0[7]: Copied!
# Coronal projection\n# select objects within the rostro-caudal range\ndf_coronal = df[\n    (df[\"Atlas_X\"] >= ap_lims[0] / 1000) & (df[\"Atlas_X\"] <= ap_lims[1] / 1000)\n]\n\nplt.figure()\n\nfor struct_name, contours in coords_coronal.items():\n    for cont in contours:\n        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_coronal,\n    x=\"Atlas_Z\",\n    y=\"Atlas_Y\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([2, 3], [8, 8], \"k\", linewidth=3)\nplt.text(2, 7.9, \"1 mm\")\n
# Coronal projection # select objects within the rostro-caudal range df_coronal = df[ (df[\"Atlas_X\"] >= ap_lims[0] / 1000) & (df[\"Atlas_X\"] <= ap_lims[1] / 1000) ] plt.figure() for struct_name, contours in coords_coronal.items(): for cont in contours: plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_coronal, x=\"Atlas_Z\", y=\"Atlas_Y\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([2, 3], [8, 8], \"k\", linewidth=3) plt.text(2, 7.9, \"1 mm\")
 Out[7]: 
Text(2, 7.9, '1 mm')
 In\u00a0[8]: Copied! 
# Sagittal projection\n# select objects within the medio-lateral range\ndf_sagittal = df[\n    (df[\"Atlas_Z\"] >= ml_lims[0] / 1000) & (df[\"Atlas_Z\"] <= ml_lims[1] / 1000)\n]\n\nplt.figure()\n\nfor struct_name, contours in coords_sagittal.items():\n    for cont in contours:\n        plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_sagittal,\n    x=\"Atlas_X\",\n    y=\"Atlas_Y\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([2, 3], [7.1, 7.1], \"k\", linewidth=3)\nplt.text(2, 7, \"1 mm\")\n
# Sagittal projection # select objects within the medio-lateral range df_sagittal = df[ (df[\"Atlas_Z\"] >= ml_lims[0] / 1000) & (df[\"Atlas_Z\"] <= ml_lims[1] / 1000) ] plt.figure() for struct_name, contours in coords_sagittal.items(): for cont in contours: plt.fill(cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_sagittal, x=\"Atlas_X\", y=\"Atlas_Y\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([2, 3], [7.1, 7.1], \"k\", linewidth=3) plt.text(2, 7, \"1 mm\")
 Out[8]: 
Text(2, 7, '1 mm')
 In\u00a0[9]: Copied! 
# Top projection\n# select objects within the dorso-ventral range\ndf_top = df[(df[\"Atlas_Y\"] >= dv_lims[0] / 1000) & (df[\"Atlas_Y\"] <= dv_lims[1] / 1000)]\n\nplt.figure()\n\nfor struct_name, contours in coords_top.items():\n    for cont in contours:\n        plt.fill(-cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\")\n\n# see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize\nax = sns.kdeplot(\n    df_top,\n    x=\"Atlas_Z\",\n    y=\"Atlas_X\",\n    hue=\"Classification\",\n    levels=nlevels,\n    common_norm=False,\n    palette=palette,\n)\nax.invert_yaxis()\nsns.despine(left=True, bottom=True)\nplt.axis(\"equal\")\nplt.xlabel(None)\nplt.ylabel(None)\nplt.xticks([])\nplt.yticks([])\nplt.plot([0.5, 1.5], [0.5, 0.5], \"k\", linewidth=3)\nplt.text(0.5, 0.4, \"1 mm\")\n
# Top projection # select objects within the dorso-ventral range df_top = df[(df[\"Atlas_Y\"] >= dv_lims[0] / 1000) & (df[\"Atlas_Y\"] <= dv_lims[1] / 1000)] plt.figure() for struct_name, contours in coords_top.items(): for cont in contours: plt.fill(-cont[:, 0] / 1000, cont[:, 1] / 1000, lw=1, fc=\"none\", ec=\"k\") # see https://seaborn.pydata.org/generated/seaborn.kdeplot.html to customize ax = sns.kdeplot( df_top, x=\"Atlas_Z\", y=\"Atlas_X\", hue=\"Classification\", levels=nlevels, common_norm=False, palette=palette, ) ax.invert_yaxis() sns.despine(left=True, bottom=True) plt.axis(\"equal\") plt.xlabel(None) plt.ylabel(None) plt.xticks([]) plt.yticks([]) plt.plot([0.5, 1.5], [0.5, 0.5], \"k\", linewidth=3) plt.text(0.5, 0.4, \"1 mm\")
 Out[9]: 
Text(0.5, 0.4, '1 mm')
 In\u00a0[\u00a0]: Copied! 
\n
"},{"location":"demo_notebooks/fibers_coverage.html","title":"Fibers coverage","text":"

Plot regions coverage percentage in the spinal cord.

This showcases that any brainglobe atlases should be supported.

Here we're going to quantify the percentage of area of each spinal cord regions innervated by axons.

The \"area \u00b5m^2\" measurement for each annotations can be created in QuPath with a pixel classifier, using the Measure button.

We're going to consider that the \"area \u00b5m^2\" measurement generated by the pixel classifier is an object count. histoquant computes a density, which is the count in each region divided by its aera. Therefore, in this case, it will be actually the fraction of area covered by fibers in a given color.

The data was generated using QuPath with a pixel classifier on toy data.

In\u00a0[1]: Copied!
import pandas as pd\n\nimport cuisto\n
import pandas as pd import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_fibers.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_fibers.toml\" In\u00a0[3]: Copied!
# - Files\n# not important if only one animal\nanimal = \"animalid1-SC\"\n# set the full path to the annotations tsv file from QuPath\nannotations_file = \"../../resources/fibers_measurements_annotations.tsv\"\n
# - Files # not important if only one animal animal = \"animalid1-SC\" # set the full path to the annotations tsv file from QuPath annotations_file = \"../../resources/fibers_measurements_annotations.tsv\" In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.config.Config(config_file)\n
# get configuration cfg = cuisto.config.Config(config_file) In\u00a0[5]: Copied!
# read data\ndf_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\")\ndf_detections = pd.DataFrame()  # empty DataFrame\n\n# remove annotations that are not brain regions\ndf_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"]\ndf_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"]\n\n# have a look\ndisplay(df_annotations.head())\n
# read data df_annotations = pd.read_csv(annotations_file, index_col=\"Object ID\", sep=\"\\t\") df_detections = pd.DataFrame() # empty DataFrame # remove annotations that are not brain regions df_annotations = df_annotations[df_annotations[\"Classification\"] != \"Region*\"] df_annotations = df_annotations[df_annotations[\"ROI\"] != \"Rectangle\"] # have a look display(df_annotations.head()) Image Object type Name Classification Parent ROI Centroid X \u00b5m Centroid Y \u00b5m Fibers: EGFP area \u00b5m^2 Fibers: DsRed area \u00b5m^2 ID Side Parent ID Area \u00b5m^2 Perimeter \u00b5m Object ID dcfe5196-4e8d-4126-b255-a9ea393c383a animalid1-SC_s1.ome.tiff Annotation Root NaN Root object (Image) Geometry 1353.70 1060.00 108993.1953 15533.3701 NaN NaN NaN 3172474.0 9853.3 acc74bc0-3dd0-4b3e-86e3-e6c7b681d544 animalid1-SC_s1.ome.tiff Annotation root Right: root Root Polygon 864.44 989.95 39162.8906 5093.2798 250.0 0.0 NaN 1603335.7 4844.2 94571cf9-f22b-453f-860c-eb13d0e72440 animalid1-SC_s1.ome.tiff Annotation WM Right: WM root Geometry 791.00 1094.60 20189.0469 2582.4824 130.0 0.0 250.0 884002.0 7927.8 473d65fb-fda4-4721-ba6f-cc659efc1d5a animalid1-SC_s1.ome.tiff Annotation vf Right: vf WM Polygon 984.31 1599.00 6298.3574 940.4100 70.0 0.0 130.0 281816.9 2719.5 449e2cd1-eca2-4708-83fe-651f378c3a14 animalid1-SC_s1.ome.tiff Annotation df Right: df WM Polygon 1242.90 401.26 1545.0750 241.3800 74.0 0.0 130.0 152952.8 1694.4 In\u00a0[6]: Copied!
# get distributions per regions, spatial distributions and coordinates\ndf_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal(\n    animal, df_annotations, df_detections, cfg, compute_distributions=False\n)\n\n# convert the \"density \u00b5m^-2\" column, which is actually the coverage fraction, to a percentage\ndf_regions[\"density \u00b5m^-2\"] = df_regions[\"density \u00b5m^-2\"] * 100\n\n# have a look\ndisplay(df_regions.head())\n
# get distributions per regions, spatial distributions and coordinates df_regions, dfs_distributions, df_coordinates = cuisto.process.process_animal( animal, df_annotations, df_detections, cfg, compute_distributions=False ) # convert the \"density \u00b5m^-2\" column, which is actually the coverage fraction, to a percentage df_regions[\"density \u00b5m^-2\"] = df_regions[\"density \u00b5m^-2\"] * 100 # have a look display(df_regions.head()) Name hemisphere Area \u00b5m^2 Area mm^2 area \u00b5m^2 area mm^2 density \u00b5m^-2 density mm^-2 coverage index relative count relative density channel animal 0 10Sp Contra. 1749462.18 1.749462 53117.3701 53.11737 3.036211 30362.113973 1612.755645 0.036535 0.033062 Negative animalid1-SC 0 10Sp Contra. 1749462.18 1.749462 5257.1025 5.257103 0.300498 3004.98208 15.797499 0.030766 0.02085 Positive animalid1-SC 1 10Sp Ipsi. 1439105.93 1.439106 64182.9823 64.182982 4.459921 44599.206328 2862.51007 0.023524 0.023265 Negative animalid1-SC 1 10Sp Ipsi. 1439105.93 1.439106 8046.3375 8.046337 0.559121 5591.205854 44.988729 0.028911 0.022984 Positive animalid1-SC 2 10Sp both 3188568.11 3.188568 117300.3524 117.300352 3.678778 36787.783216 4315.219935 0.028047 0.025734 Negative animalid1-SC In\u00a0[7]: Copied!
# plot distributions per regions\nfig_regions = cuisto.display.plot_regions(df_regions, cfg)\n# specify which regions to plot\n# fig_regions = hq.display.plot_regions(df_regions, cfg, names_list=[\"Rh9\", \"Sr9\", \"8Sp\"])\n\n# save as svg\n# fig_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\nice_figure.svg\")\n
# plot distributions per regions fig_regions = cuisto.display.plot_regions(df_regions, cfg) # specify which regions to plot # fig_regions = hq.display.plot_regions(df_regions, cfg, names_list=[\"Rh9\", \"Sr9\", \"8Sp\"]) # save as svg # fig_regions[0].savefig(r\"C:\\Users\\glegoc\\Downloads\\nice_figure.svg\")"},{"location":"demo_notebooks/fibers_length_multi.html","title":"Fibers length in multi animals","text":"In\u00a0[1]: Copied!
import cuisto\n
import cuisto In\u00a0[2]: Copied!
# Full path to your configuration file, edited according to your need beforehand\nconfig_file = \"../../resources/demo_config_multi.toml\"\n
# Full path to your configuration file, edited according to your need beforehand config_file = \"../../resources/demo_config_multi.toml\" In\u00a0[3]: Copied!
# Files\nwdir = \"../../resources/multi\"\nanimals = [\"mouse0\", \"mouse1\"]\n
# Files wdir = \"../../resources/multi\" animals = [\"mouse0\", \"mouse1\"] In\u00a0[4]: Copied!
# get configuration\ncfg = cuisto.Config(config_file)\n
# get configuration cfg = cuisto.Config(config_file) In\u00a0[5]: Copied!
# get distributions per regions\ndf_regions, _, _ = cuisto.process.process_animals(\n    wdir, animals, cfg, compute_distributions=False\n)\n\n# have a look\ndisplay(df_regions.head(10))\n
# get distributions per regions df_regions, _, _ = cuisto.process.process_animals( wdir, animals, cfg, compute_distributions=False ) # have a look display(df_regions.head(10))
Processing mouse1: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 2/2 [00:00<00:00, 15.66it/s]\n
Name hemisphere Area \u00b5m^2 Area mm^2 length \u00b5m length mm density \u00b5m^-1 density mm^-1 coverage index relative count relative density channel animal 0 ACVII Contra. 9099.04 0.009099 468.0381 0.468038 0.051438 51438.184688 24.07503 0.00064 0.022168 marker3 mouse0 1 ACVII Contra. 9099.04 0.009099 4260.4844 4.260484 0.468234 468234.495068 1994.905762 0.0019 0.056502 marker2 mouse0 2 ACVII Contra. 9099.04 0.009099 5337.7103 5.33771 0.586623 586623.45698 3131.226069 0.010104 0.242734 marker1 mouse0 3 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker3 mouse0 4 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker2 mouse0 5 ACVII Ipsi. 4609.90 0.004610 0.0 0.0 0.0 0.0 0.0 0.0 0.0 marker1 mouse0 6 ACVII both 13708.94 0.013709 468.0381 0.468038 0.034141 34141.086036 15.979329 0.000284 0.011001 marker3 mouse0 7 ACVII both 13708.94 0.013709 4260.4844 4.260484 0.310781 310781.460857 1324.079566 0.000934 0.030688 marker2 mouse0 8 ACVII both 13708.94 0.013709 5337.7103 5.33771 0.38936 389359.811918 2078.289878 0.00534 0.142623 marker1 mouse0 9 AMB Contra. 122463.80 0.122464 30482.7815 30.482782 0.248913 248912.588863 7587.548059 0.041712 0.107271 marker3 mouse0 In\u00a0[6]: Copied!
figs_regions = cuisto.display.plot_regions(df_regions, cfg)\n
figs_regions = cuisto.display.plot_regions(df_regions, cfg)"},{"location":"demo_notebooks/fibers_length_multi.html#fibers-length-in-multi-animals","title":"Fibers length in multi animals\u00b6","text":"

This example uses synthetic data to showcase how histoquant can be used in a pipeline.

Annotations measurements should be exported from QuPath, following the required directory structure.

Alternatively, you can merge all your CSV files yourself, one per animal, adding an animal ID to each table. Those can be processed with the histoquant.process.process_animal() function, in a loop, collecting the results at each iteration and finally concatenating the results. Finally, those can be used with display module. See the API reference for the process module.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0f8724e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..13d8081 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/stylesheets/extra.css b/stylesheets/extra.css new file mode 100644 index 0000000..305128f --- /dev/null +++ b/stylesheets/extra.css @@ -0,0 +1,24 @@ +/* mark external links with an arrow */ +.md-typeset a:not(.md-icon) { + &[href^="//"]::after, + &[href^="http://"]::after, + &[href^="https://"]::after { + content: "↗"; + font-size: smaller; + margin-left: .2em; + vertical-align: top; + } +} + +/* change default code blocks color to red */ +/* :root > * { + --md-code-fg-color: #d52a2a; + } */ + +/* change bullet style in nested lists */ + article ul ul { + list-style-type: circle !important; +} +article ul ul ul { + list-style-type: square !important; +} \ No newline at end of file diff --git a/tips-abba.html b/tips-abba.html new file mode 100644 index 0000000..2abdbfb --- /dev/null +++ b/tips-abba.html @@ -0,0 +1,1269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ABBA - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

ABBA#

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tips-brain-contours.html b/tips-brain-contours.html new file mode 100644 index 0000000..23ebd55 --- /dev/null +++ b/tips-brain-contours.html @@ -0,0 +1,1273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Brain contours - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

Brain contours#

+

With cuisto, it is possible to plot 2D heatmaps on brain contours.

+

All the detections are projected in a single plane, thus it is up to you to select a relevant data range. It is primarily intended to give a quick, qualitative overview of the spreading of your data.

+

To do so, it requires the brain regions outlines, stored in a hdf5 file. This can be generated with brainglobe-atlasapi. The generate_atlas_outlines.py located in scripts/atlas will show you how to make such a file, that the cuisto.display module can use.

+

Alternatively it is possible to directly plot density maps without cuisto, using brainglobe-heatmap. An example is shown here.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tips-formats.html b/tips-formats.html new file mode 100644 index 0000000..e5744f9 --- /dev/null +++ b/tips-formats.html @@ -0,0 +1,1545 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Data format - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + + + + +

Data format#

+

Some concepts#

+

Tiles#

+

The representation of an image in a computer is basically a table where each element represents the pixel value (see more here). It can be n-dimensional, where the typical dimensions would be \((x, y, z)\), time and the fluorescence channels.

+

In large images, such as histological slices that are more than 10000\(\times\)10000 pixels, a strategy called tiling is used to optimize access to specific regions in the image. Storing the whole image at once in a file would imply to load the whole thing at once in the memory (RAM), even though one would only need to access a given rectangular region with a given zoom. Instead, the image is stored as tiles, small squares (512--2048 pixels) that pave the whole image and are used to reconstruct the original image. Therefore, when zooming-in, only the relevant tiles are loaded and displayed, allowing for smooth large image navigation. This process is done seamlessly by software like QuPath and BigDataViewer (the Fiji plugin ABBA is based on) when loading tiled images. This is also leveraged for image processing in QuPath, which will work on tiles instead of the whole image to not saturate your computer RAM.

+

Most images are already tiled, including Zeiss CZI images. Note that those tiles do not necessarily correspond to the actual, real-world, tiles the microscope did to image the whole slide.

+

Pyramids#

+

In the same spirit as tiles, it would be a waste to have to load the entire image (and all the tiles) at once when viewing the image at max zoom-out, as your monitor nor your eyes would handle it. Instead, smaller, rescaled versions of the original image are stored alongside it, and depending on the zoom you are using, the sub-resolution version is displayed. Again, this is done seamlessly by QuPath and ABBA, allowing you to quickly switch from an image to another, without having to load the GB-sized image. Also, for image processing that does not require the original pixel size, QuPath can also leverage pyramids to go faster.

+

Usually, upon openning a CZI file in ZEN, there is a pop-up suggesting you to generate pyramids. It is a very good idea to say yes, wait a bit and save the file so that the pyramidal levels are saved within the file.

+

Metadata#

+

Metadata, while often overlooked, are of paramount importance in microscopy data. It allows both softwares and users to interpret the raw data of images, eg. the values of each pixels. Most image file formats support this, including the microcope manufacturer file formats. Metadata may include :

+
    +
  • Pixel size. Usually expressed in µm for microscopy, this maps computer pixel units into real world distance. QuPath and ABBA uses that calibration to scale your image properly, so that it match the atlas you'll register your slices on,
  • +
  • Channels colors and names,
  • +
  • Image type (fluorescence, brightfield, ...),
  • +
  • Dimensions,
  • +
  • Magnification...
  • +
+

Pixel size is the parameter that is absolutely necessary. Channel names and colors are more a quality of life feature, to make sure not to mix your difference fluorescence channels. CZI files or exported OME-TIFF files include this out of the box so you don't really need to pay attention.

+

Bio-formats#

+

Bio-formats is an initiative of the Open Microscopy Environment (OME) consortium, aiming at being able to read proprietary microscopy image data and metadata. It is used in QuPath, Fiji and ABBA.

+

This page summarizes the level of support of numerous file formats. You can see that Zeiss CZI files and Leica LIF are quite well supported, and should therefore work out of the box in QuPath.

+

Zeiss CZI files#

+

QuPath and ABBA supports any Bio-formats supported, tiled, pyramidal images.

+

If you're in luck, adding the pyramidal CZI file to your QuPath project will just work. If it doesn't, you'll notice immediately : the tiles will be shuffled and you'll see only a part of the image instead of the whole one. Unfortunately I was not able to determine why this happens and did not find a way to even predict if a file will or will not work.

+

In the event you experience this bug, you'll need to export the CZI files to OME-TIFF files from ZEN, then generate tiled pyramidal images with the pyramid-creator package that you can find here.

+

Markdown (.md) files#

+

Markdown is a markup language to create formatted text. It is basically a simple text file that could be opened with any text editor software (notepad and the like), but features specific tags to format the text with heading levels, typesetting (bold, itallic), links, lists... This very page is actually written in markdown, and the engine that builds it renders the text in a nicely formatted manner.

+

If you open a .md file with vscode for example, you'll get a magnigying glass on the top right corner to switch to the rendered version of the file.

+

TOML (.toml) files#

+

TOML, or Tom's Obvious Minimal Language, is a configuration file format (similar to YAML). Again, it is basically a simple text file that can be opened with any text editor and is human-readable, but also computer-readable. This means that it is easy for most software and programming language to parse the file to associate a variable (or "key") to a value, thus making it a good file format for configuration. It is used in cuisto (see The configuration files page).

+

The syntax looks like this : +

# a comment, ignored by the computer
+key1 = 10  # the key "key1" is mapped to the number 10
+key2 = "something"  # "key2" is mapped to the string "something"
+key3 = ["something else", 1.10, -25]  # "key3" is mapped to a list with 3 elements
+[section]  # we can declare sections
+key1 = 5  # this is not "key1", it actually is section.key1
+[section.example]  # we can have nested sections
+key1 = true  # this is section.example.key1, mapped to the boolean True
+

+

You can check the full specification of this language here.

+

CSV (.csv, .tsv) files#

+

CSV (or TSV) stands for Comma-Separated Values (or Tab-Separated Values) and is, once again, a simple text file formatted in a way that allows LibreOffice Calc (or Excel) to open them as a table. Lines of the table are delimited with new lines, and columns are separated with commas (,) or tabulations. Those files are easily parsed by programming languages (including Python). QuPath can export annotations and detections measurements in TSV format.

+

JSON and GeoJSON files#

+

JSON is a "data-interchange format". It is used to store data, very much like toml, but supports more complex data and is more efficient to read and write, but is less human-readable. It is used in cuisto to store fibers-like objects coordinates, as they can contain several millions of points (making CSV not usable).

+

GeoJson is a file format used to store geographic data structures, basically objects coordinates with various shapes. It is based on and compatible with JSON, which makes it easy to parse in numerous programming language. It used in QuPath to import and export objects, that can be point, line, polygons...

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tips-qupath.html b/tips-qupath.html new file mode 100644 index 0000000..87c38f5 --- /dev/null +++ b/tips-qupath.html @@ -0,0 +1,1337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + QuPath - cuisto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + +

QuPath#

+

Custom scripts#

+

While QuPath graphical user interface (GUI) should meet a lot of your needs, it is very convenient to use scripting to automate certain tasks, execute them in batch (on all your images) and do things you couldn't do otherwise. QuPath uses the Groovy programming language, which is mostly Java.

+
+

Warning

+

Not all commands will appear in the history.

+
+

In QuPath, in the left panel in the "Workflow" tab, there is an history of most of the commands you used during the session. On the bottom, you can click on Create workflow to select the relevant commands and create a script. This will open the built-in script editor that will contain the groovy version of what you did graphically.

+
+

Tip

+

The scripts/qupath-utils folder contains a bunch of utility scripts.

+
+

They can be run in batch with the three-dotted menu on the bottom right corner of the script editor : Run for project, then choose the images you want the script to run on.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file