pertpy 0.6.0__py3-none-any.whl → 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pertpy/__init__.py +4 -2
 - pertpy/data/__init__.py +66 -1
 - pertpy/data/_dataloader.py +28 -26
 - pertpy/data/_datasets.py +261 -92
 - pertpy/metadata/__init__.py +6 -0
 - pertpy/metadata/_cell_line.py +795 -0
 - pertpy/metadata/_compound.py +128 -0
 - pertpy/metadata/_drug.py +238 -0
 - pertpy/metadata/_look_up.py +569 -0
 - pertpy/metadata/_metadata.py +70 -0
 - pertpy/metadata/_moa.py +125 -0
 - pertpy/plot/__init__.py +0 -13
 - pertpy/preprocessing/__init__.py +2 -0
 - pertpy/preprocessing/_guide_rna.py +89 -6
 - pertpy/tools/__init__.py +48 -15
 - pertpy/tools/_augur.py +329 -32
 - pertpy/tools/_cinemaot.py +145 -6
 - pertpy/tools/_coda/_base_coda.py +1237 -116
 - pertpy/tools/_coda/_sccoda.py +66 -36
 - pertpy/tools/_coda/_tasccoda.py +46 -39
 - pertpy/tools/_dialogue.py +180 -77
 - pertpy/tools/_differential_gene_expression/__init__.py +20 -0
 - pertpy/tools/_differential_gene_expression/_base.py +657 -0
 - pertpy/tools/_differential_gene_expression/_checks.py +41 -0
 - pertpy/tools/_differential_gene_expression/_dge_comparison.py +86 -0
 - pertpy/tools/_differential_gene_expression/_edger.py +125 -0
 - pertpy/tools/_differential_gene_expression/_formulaic.py +189 -0
 - pertpy/tools/_differential_gene_expression/_pydeseq2.py +95 -0
 - pertpy/tools/_differential_gene_expression/_simple_tests.py +162 -0
 - pertpy/tools/_differential_gene_expression/_statsmodels.py +72 -0
 - pertpy/tools/_distances/_distance_tests.py +29 -24
 - pertpy/tools/_distances/_distances.py +584 -98
 - pertpy/tools/_enrichment.py +460 -0
 - pertpy/tools/_kernel_pca.py +1 -1
 - pertpy/tools/_milo.py +406 -49
 - pertpy/tools/_mixscape.py +677 -55
 - pertpy/tools/_perturbation_space/_clustering.py +10 -3
 - pertpy/tools/_perturbation_space/_comparison.py +112 -0
 - pertpy/tools/_perturbation_space/_discriminator_classifiers.py +524 -0
 - pertpy/tools/_perturbation_space/_perturbation_space.py +146 -52
 - pertpy/tools/_perturbation_space/_simple.py +52 -11
 - pertpy/tools/_scgen/__init__.py +1 -1
 - pertpy/tools/_scgen/_base_components.py +2 -3
 - pertpy/tools/_scgen/_scgen.py +706 -0
 - pertpy/tools/_scgen/_utils.py +3 -5
 - pertpy/tools/decoupler_LICENSE +674 -0
 - {pertpy-0.6.0.dist-info → pertpy-0.8.0.dist-info}/METADATA +48 -20
 - pertpy-0.8.0.dist-info/RECORD +57 -0
 - {pertpy-0.6.0.dist-info → pertpy-0.8.0.dist-info}/WHEEL +1 -1
 - pertpy/plot/_augur.py +0 -234
 - pertpy/plot/_cinemaot.py +0 -81
 - pertpy/plot/_coda.py +0 -1001
 - pertpy/plot/_dialogue.py +0 -91
 - pertpy/plot/_guide_rna.py +0 -82
 - pertpy/plot/_milopy.py +0 -284
 - pertpy/plot/_mixscape.py +0 -594
 - pertpy/plot/_scgen.py +0 -337
 - pertpy/tools/_differential_gene_expression.py +0 -99
 - pertpy/tools/_metadata/__init__.py +0 -0
 - pertpy/tools/_metadata/_cell_line.py +0 -613
 - pertpy/tools/_metadata/_look_up.py +0 -342
 - pertpy/tools/_perturbation_space/_discriminator_classifier.py +0 -381
 - pertpy/tools/_scgen/_jax_scgen.py +0 -370
 - pertpy-0.6.0.dist-info/RECORD +0 -50
 - /pertpy/tools/_scgen/{_jax_scgenvae.py → _scgenvae.py} +0 -0
 - {pertpy-0.6.0.dist-info → pertpy-0.8.0.dist-info}/licenses/LICENSE +0 -0
 
    
        pertpy/plot/_dialogue.py
    DELETED
    
    | 
         @@ -1,91 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            import matplotlib.pyplot as plt
         
     | 
| 
       2 
     | 
    
         
            -
            import pandas as pd
         
     | 
| 
       3 
     | 
    
         
            -
            import scanpy as sc
         
     | 
| 
       4 
     | 
    
         
            -
            import seaborn as sns
         
     | 
| 
       5 
     | 
    
         
            -
            from anndata import AnnData
         
     | 
| 
       6 
     | 
    
         
            -
            from seaborn import PairGrid
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            class DialoguePlot:
         
     | 
| 
       10 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       11 
     | 
    
         
            -
                def split_violins(
         
     | 
| 
       12 
     | 
    
         
            -
                    adata: AnnData,
         
     | 
| 
       13 
     | 
    
         
            -
                    split_key: str,
         
     | 
| 
       14 
     | 
    
         
            -
                    celltype_key=str,
         
     | 
| 
       15 
     | 
    
         
            -
                    split_which: tuple[str, str] = None,
         
     | 
| 
       16 
     | 
    
         
            -
                    mcp: str = "mcp_0",
         
     | 
| 
       17 
     | 
    
         
            -
                ) -> plt.Axes:
         
     | 
| 
       18 
     | 
    
         
            -
                    """Plots split violin plots for a given MCP and split variable.
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                    Any cells with a value for split_key not in split_which are removed from the plot.
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                    Args:
         
     | 
| 
       23 
     | 
    
         
            -
                        adata: Annotated data object.
         
     | 
| 
       24 
     | 
    
         
            -
                        split_key: Variable in adata.obs used to split the data.
         
     | 
| 
       25 
     | 
    
         
            -
                        celltype_key: Key for cell type annotations.
         
     | 
| 
       26 
     | 
    
         
            -
                        split_which: Which values of split_key to plot. Required if more than 2 values in split_key.
         
     | 
| 
       27 
     | 
    
         
            -
                        mcp: Key for MCP data. Defaults to "mcp_0".
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       30 
     | 
    
         
            -
                        A :class:`~matplotlib.axes.Axes` object
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       33 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       34 
     | 
    
         
            -
                        >>> import scanpy as sc
         
     | 
| 
       35 
     | 
    
         
            -
                        >>> adata = pt.dt.dialogue_example()
         
     | 
| 
       36 
     | 
    
         
            -
                        >>> sc.pp.pca(adata)
         
     | 
| 
       37 
     | 
    
         
            -
                        >>> dl = pt.tl.Dialogue(sample_id = "clinical.status", celltype_key = "cell.subtypes", \
         
     | 
| 
       38 
     | 
    
         
            -
                            n_counts_key = "nCount_RNA", n_mpcs = 3)
         
     | 
| 
       39 
     | 
    
         
            -
                        >>> adata, mcps, ws, ct_subs = dl.calculate_multifactor_PMD(adata, normalize=True)
         
     | 
| 
       40 
     | 
    
         
            -
                        >>> pt.pl.dl.split_violins(adata, split_key='gender', celltype_key='cell.subtypes')
         
     | 
| 
       41 
     | 
    
         
            -
                    """
         
     | 
| 
       42 
     | 
    
         
            -
                    df = sc.get.obs_df(adata, [celltype_key, mcp, split_key])
         
     | 
| 
       43 
     | 
    
         
            -
                    if split_which is None:
         
     | 
| 
       44 
     | 
    
         
            -
                        split_which = df[split_key].unique()
         
     | 
| 
       45 
     | 
    
         
            -
                    df = df[df[split_key].isin(split_which)]
         
     | 
| 
       46 
     | 
    
         
            -
                    df[split_key] = df[split_key].cat.remove_unused_categories()
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                    ax = sns.violinplot(data=df, x=celltype_key, y=mcp, hue=split_key, split=True)
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                    ax.set_xticklabels(ax.get_xticklabels(), rotation=90)
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                    return ax
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       55 
     | 
    
         
            -
                def pairplot(adata: AnnData, celltype_key: str, color: str, sample_id: str, mcp: str = "mcp_0") -> PairGrid:
         
     | 
| 
       56 
     | 
    
         
            -
                    """Generate a pairplot visualization for multi-cell perturbation (MCP) data.
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                    Computes the mean of a specified MCP feature (mcp) for each combination of sample and cell type,
         
     | 
| 
       59 
     | 
    
         
            -
                    then creates a pairplot to visualize the relationships between these mean MCP values.
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                    Args:
         
     | 
| 
       62 
     | 
    
         
            -
                        adata: Annotated data object.
         
     | 
| 
       63 
     | 
    
         
            -
                        celltype_key: Key in adata.obs containing cell type annotations.
         
     | 
| 
       64 
     | 
    
         
            -
                        color: Key in adata.obs for color annotations. This parameter is used as the hue
         
     | 
| 
       65 
     | 
    
         
            -
                        sample_id: Key in adata.obs for the sample annotations.
         
     | 
| 
       66 
     | 
    
         
            -
                        mcp: Key in adata.obs for MCP feature values. Defaults to "mcp_0".
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       69 
     | 
    
         
            -
                        Seaborn Pairgrid object.
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       72 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       73 
     | 
    
         
            -
                        >>> import scanpy as sc
         
     | 
| 
       74 
     | 
    
         
            -
                        >>> adata = pt.dt.dialogue_example()
         
     | 
| 
       75 
     | 
    
         
            -
                        >>> sc.pp.pca(adata)
         
     | 
| 
       76 
     | 
    
         
            -
                        >>> dl = pt.tl.Dialogue(sample_id = "clinical.status", celltype_key = "cell.subtypes", \
         
     | 
| 
       77 
     | 
    
         
            -
                            n_counts_key = "nCount_RNA", n_mpcs = 3)
         
     | 
| 
       78 
     | 
    
         
            -
                        >>> adata, mcps, ws, ct_subs = dl.calculate_multifactor_PMD(adata, normalize=True)
         
     | 
| 
       79 
     | 
    
         
            -
                        >>> pt.pl.dl.pairplot(adata, celltype_key="cell.subtypes", color="gender", sample_id="clinical.status")
         
     | 
| 
       80 
     | 
    
         
            -
                    """
         
     | 
| 
       81 
     | 
    
         
            -
                    mean_mcps = adata.obs.groupby([sample_id, celltype_key])[mcp].mean()
         
     | 
| 
       82 
     | 
    
         
            -
                    mean_mcps = mean_mcps.reset_index()
         
     | 
| 
       83 
     | 
    
         
            -
                    mcp_pivot = pd.pivot(mean_mcps[[sample_id, celltype_key, mcp]], index=sample_id, columns=celltype_key)[mcp]
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                    aggstats = adata.obs.groupby([sample_id])[color].describe()
         
     | 
| 
       86 
     | 
    
         
            -
                    aggstats = aggstats.loc[list(mcp_pivot.index), :]
         
     | 
| 
       87 
     | 
    
         
            -
                    aggstats[color] = aggstats["top"]
         
     | 
| 
       88 
     | 
    
         
            -
                    mcp_pivot = pd.concat([mcp_pivot, aggstats[color]], axis=1)
         
     | 
| 
       89 
     | 
    
         
            -
                    ax = sns.pairplot(mcp_pivot, hue=color, corner=True)
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                    return ax
         
     | 
    
        pertpy/plot/_guide_rna.py
    DELETED
    
    | 
         @@ -1,82 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            from __future__ import annotations
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            from typing import TYPE_CHECKING
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            import numpy as np
         
     | 
| 
       6 
     | 
    
         
            -
            import scanpy as sc
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            if TYPE_CHECKING:
         
     | 
| 
       9 
     | 
    
         
            -
                from anndata import AnnData
         
     | 
| 
       10 
     | 
    
         
            -
                from matplotlib.axes import Axes
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            class GuideRnaPlot:
         
     | 
| 
       14 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       15 
     | 
    
         
            -
                def heatmap(
         
     | 
| 
       16 
     | 
    
         
            -
                    adata: AnnData,
         
     | 
| 
       17 
     | 
    
         
            -
                    layer: str | None = None,
         
     | 
| 
       18 
     | 
    
         
            -
                    order_by: np.ndarray | str | None = None,
         
     | 
| 
       19 
     | 
    
         
            -
                    key_to_save_order: str = None,
         
     | 
| 
       20 
     | 
    
         
            -
                    **kwds,
         
     | 
| 
       21 
     | 
    
         
            -
                ) -> list[Axes]:
         
     | 
| 
       22 
     | 
    
         
            -
                    """Heatmap plotting of guide RNA expression matrix.
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                    Assuming guides have sparse expression, this function reorders cells
         
     | 
| 
       25 
     | 
    
         
            -
                    and plots guide RNA expression so that a nice sparse representation is achieved.
         
     | 
| 
       26 
     | 
    
         
            -
                    The cell ordering can be stored and reused in future plots to obtain consistent
         
     | 
| 
       27 
     | 
    
         
            -
                    plots before and after analysis of the guide RNA expression.
         
     | 
| 
       28 
     | 
    
         
            -
                    Note: This function expects a log-normalized or binary data.
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                     Args:
         
     | 
| 
       31 
     | 
    
         
            -
                         adata: Annotated data matrix containing gRNA values
         
     | 
| 
       32 
     | 
    
         
            -
                         layer: Key to the layer containing log normalized count values of the gRNAs.
         
     | 
| 
       33 
     | 
    
         
            -
                                adata.X is used if layer is None.
         
     | 
| 
       34 
     | 
    
         
            -
                         order_by: The order of cells in y axis. Defaults to None.
         
     | 
| 
       35 
     | 
    
         
            -
                                   If None, cells will be reordered to have a nice sparse representation.
         
     | 
| 
       36 
     | 
    
         
            -
                                   If a string is provided, adata.obs[order_by] will be used as the order.
         
     | 
| 
       37 
     | 
    
         
            -
                                   If a numpy array is provided, the array will be used for ordering.
         
     | 
| 
       38 
     | 
    
         
            -
                         key_to_save_order: The obs key to save cell orders in the current plot. Only saves if not None.
         
     | 
| 
       39 
     | 
    
         
            -
                         kwds: Are passed to sc.pl.heatmap.
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                     Returns:
         
     | 
| 
       42 
     | 
    
         
            -
                         List of Axes. Alternatively you can pass save or show parameters as they will be passed to sc.pl.heatmap.
         
     | 
| 
       43 
     | 
    
         
            -
                         Order of cells in the y axis will be saved on adata.obs[key_to_save_order] if provided.
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       46 
     | 
    
         
            -
                        Each cell is assigned to gRNA that occurs at least 5 times in the respective cell, which is then
         
     | 
| 
       47 
     | 
    
         
            -
                        visualized using a heatmap.
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       50 
     | 
    
         
            -
                        >>> mdata = pt.data.papalexi_2021()
         
     | 
| 
       51 
     | 
    
         
            -
                        >>> gdo = mdata.mod['gdo']
         
     | 
| 
       52 
     | 
    
         
            -
                        >>> ga = pt.pp.GuideAssignment()
         
     | 
| 
       53 
     | 
    
         
            -
                        >>> ga.assign_by_threshold(gdo, assignment_threshold=5)
         
     | 
| 
       54 
     | 
    
         
            -
                        >>> pt.pl.guide.heatmap(gdo)
         
     | 
| 
       55 
     | 
    
         
            -
                    """
         
     | 
| 
       56 
     | 
    
         
            -
                    data = adata.X if layer is None else adata.layers[layer]
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                    if order_by is None:
         
     | 
| 
       59 
     | 
    
         
            -
                        max_guide_index = np.where(
         
     | 
| 
       60 
     | 
    
         
            -
                            np.array(data.max(axis=1)).squeeze() != data.min(), np.array(data.argmax(axis=1)).squeeze(), -1
         
     | 
| 
       61 
     | 
    
         
            -
                        )
         
     | 
| 
       62 
     | 
    
         
            -
                        order = np.argsort(max_guide_index)
         
     | 
| 
       63 
     | 
    
         
            -
                    elif isinstance(order_by, str):
         
     | 
| 
       64 
     | 
    
         
            -
                        order = adata.obs[order_by]
         
     | 
| 
       65 
     | 
    
         
            -
                    else:
         
     | 
| 
       66 
     | 
    
         
            -
                        order = order_by
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                    adata.obs["_tmp_pertpy_grna_plot_dummy_group"] = ""
         
     | 
| 
       69 
     | 
    
         
            -
                    if key_to_save_order is not None:
         
     | 
| 
       70 
     | 
    
         
            -
                        adata.obs[key_to_save_order] = order
         
     | 
| 
       71 
     | 
    
         
            -
                    axis_group = sc.pl.heatmap(
         
     | 
| 
       72 
     | 
    
         
            -
                        adata[order],
         
     | 
| 
       73 
     | 
    
         
            -
                        adata.var.index.tolist(),
         
     | 
| 
       74 
     | 
    
         
            -
                        groupby="_tmp_pertpy_grna_plot_dummy_group",
         
     | 
| 
       75 
     | 
    
         
            -
                        cmap="viridis",
         
     | 
| 
       76 
     | 
    
         
            -
                        use_raw=False,
         
     | 
| 
       77 
     | 
    
         
            -
                        dendrogram=False,
         
     | 
| 
       78 
     | 
    
         
            -
                        layer=layer,
         
     | 
| 
       79 
     | 
    
         
            -
                        **kwds,
         
     | 
| 
       80 
     | 
    
         
            -
                    )
         
     | 
| 
       81 
     | 
    
         
            -
                    del adata.obs["_tmp_pertpy_grna_plot_dummy_group"]
         
     | 
| 
       82 
     | 
    
         
            -
                    return axis_group
         
     | 
    
        pertpy/plot/_milopy.py
    DELETED
    
    | 
         @@ -1,284 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            from __future__ import annotations
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            from typing import TYPE_CHECKING
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            import matplotlib.pyplot as plt
         
     | 
| 
       6 
     | 
    
         
            -
            import numpy as np
         
     | 
| 
       7 
     | 
    
         
            -
            import pandas as pd
         
     | 
| 
       8 
     | 
    
         
            -
            import scanpy as sc
         
     | 
| 
       9 
     | 
    
         
            -
            import seaborn as sns
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            if TYPE_CHECKING:
         
     | 
| 
       12 
     | 
    
         
            -
                from collections.abc import Sequence
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                from mudata import MuData
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
            class MilopyPlot:
         
     | 
| 
       18 
     | 
    
         
            -
                """Plotting functions for Milopy."""
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       21 
     | 
    
         
            -
                def nhood_graph(
         
     | 
| 
       22 
     | 
    
         
            -
                    mdata: MuData,
         
     | 
| 
       23 
     | 
    
         
            -
                    alpha: float = 0.1,
         
     | 
| 
       24 
     | 
    
         
            -
                    min_logFC: float = 0,
         
     | 
| 
       25 
     | 
    
         
            -
                    min_size: int = 10,
         
     | 
| 
       26 
     | 
    
         
            -
                    plot_edges: bool = False,
         
     | 
| 
       27 
     | 
    
         
            -
                    title: str = "DA log-Fold Change",
         
     | 
| 
       28 
     | 
    
         
            -
                    show: bool | None = None,
         
     | 
| 
       29 
     | 
    
         
            -
                    save: bool | str | None = None,
         
     | 
| 
       30 
     | 
    
         
            -
                    **kwargs,
         
     | 
| 
       31 
     | 
    
         
            -
                ) -> None:
         
     | 
| 
       32 
     | 
    
         
            -
                    """Visualize DA results on abstracted graph (wrapper around sc.pl.embedding)
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                    Args:
         
     | 
| 
       35 
     | 
    
         
            -
                        mdata: MuData object
         
     | 
| 
       36 
     | 
    
         
            -
                        alpha: Significance threshold. (default: 0.1)
         
     | 
| 
       37 
     | 
    
         
            -
                        min_logFC: Minimum absolute log-Fold Change to show results. If is 0, show all significant neighbourhoods. (default: 0)
         
     | 
| 
       38 
     | 
    
         
            -
                        min_size: Minimum size of nodes in visualization. (default: 10)
         
     | 
| 
       39 
     | 
    
         
            -
                        plot_edges: If edges for neighbourhood overlaps whould be plotted. Defaults to False.
         
     | 
| 
       40 
     | 
    
         
            -
                        title: Plot title. Defaults to "DA log-Fold Change".
         
     | 
| 
       41 
     | 
    
         
            -
                        show: Show the plot, do not return axis.
         
     | 
| 
       42 
     | 
    
         
            -
                        save: If `True` or a `str`, save the figure. A string is appended to the default filename.
         
     | 
| 
       43 
     | 
    
         
            -
                              Infer the filetype if ending on {`'.pdf'`, `'.png'`, `'.svg'`}.
         
     | 
| 
       44 
     | 
    
         
            -
                        **kwargs: Additional arguments to `scanpy.pl.embedding`.
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       47 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       48 
     | 
    
         
            -
                        >>> adata = pt.dt.bhattacherjee()
         
     | 
| 
       49 
     | 
    
         
            -
                        >>> milo = pt.tl.Milo()
         
     | 
| 
       50 
     | 
    
         
            -
                        >>> mdata = milo.load(adata)
         
     | 
| 
       51 
     | 
    
         
            -
                        >>> sc.pp.neighbors(mdata["rna"])
         
     | 
| 
       52 
     | 
    
         
            -
                        >>> sc.tl.umap(mdata["rna"])
         
     | 
| 
       53 
     | 
    
         
            -
                        >>> milo.make_nhoods(mdata["rna"])
         
     | 
| 
       54 
     | 
    
         
            -
                        >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
         
     | 
| 
       55 
     | 
    
         
            -
                        >>> milo.da_nhoods(mdata, design="~label")
         
     | 
| 
       56 
     | 
    
         
            -
                        >>> milo.build_nhood_graph(mdata)
         
     | 
| 
       57 
     | 
    
         
            -
                        >>> pt.pl.milo.nhood_graph(mdata)
         
     | 
| 
       58 
     | 
    
         
            -
                        # TODO: If necessary adjust after fixing StopIteration error, which is currently thrown
         
     | 
| 
       59 
     | 
    
         
            -
                    """
         
     | 
| 
       60 
     | 
    
         
            -
                    nhood_adata = mdata["milo"].T.copy()
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                    if "Nhood_size" not in nhood_adata.obs.columns:
         
     | 
| 
       63 
     | 
    
         
            -
                        raise KeyError(
         
     | 
| 
       64 
     | 
    
         
            -
                            'Cannot find "Nhood_size" column in adata.uns["nhood_adata"].obs -- \
         
     | 
| 
       65 
     | 
    
         
            -
                                please run milopy.utils.build_nhood_graph(adata)'
         
     | 
| 
       66 
     | 
    
         
            -
                        )
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                    nhood_adata.obs["graph_color"] = nhood_adata.obs["logFC"]
         
     | 
| 
       69 
     | 
    
         
            -
                    nhood_adata.obs.loc[nhood_adata.obs["SpatialFDR"] > alpha, "graph_color"] = np.nan
         
     | 
| 
       70 
     | 
    
         
            -
                    nhood_adata.obs["abs_logFC"] = abs(nhood_adata.obs["logFC"])
         
     | 
| 
       71 
     | 
    
         
            -
                    nhood_adata.obs.loc[nhood_adata.obs["abs_logFC"] < min_logFC, "graph_color"] = np.nan
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                    # Plotting order - extreme logFC on top
         
     | 
| 
       74 
     | 
    
         
            -
                    nhood_adata.obs.loc[nhood_adata.obs["graph_color"].isna(), "abs_logFC"] = np.nan
         
     | 
| 
       75 
     | 
    
         
            -
                    ordered = nhood_adata.obs.sort_values("abs_logFC", na_position="first").index
         
     | 
| 
       76 
     | 
    
         
            -
                    nhood_adata = nhood_adata[ordered]
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                    vmax = np.max([nhood_adata.obs["graph_color"].max(), abs(nhood_adata.obs["graph_color"].min())])
         
     | 
| 
       79 
     | 
    
         
            -
                    vmin = -vmax
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                    sc.pl.embedding(
         
     | 
| 
       82 
     | 
    
         
            -
                        nhood_adata,
         
     | 
| 
       83 
     | 
    
         
            -
                        "X_milo_graph",
         
     | 
| 
       84 
     | 
    
         
            -
                        color="graph_color",
         
     | 
| 
       85 
     | 
    
         
            -
                        cmap="RdBu_r",
         
     | 
| 
       86 
     | 
    
         
            -
                        size=nhood_adata.obs["Nhood_size"] * min_size,
         
     | 
| 
       87 
     | 
    
         
            -
                        edges=plot_edges,
         
     | 
| 
       88 
     | 
    
         
            -
                        neighbors_key="nhood",
         
     | 
| 
       89 
     | 
    
         
            -
                        sort_order=False,
         
     | 
| 
       90 
     | 
    
         
            -
                        frameon=False,
         
     | 
| 
       91 
     | 
    
         
            -
                        vmax=vmax,
         
     | 
| 
       92 
     | 
    
         
            -
                        vmin=vmin,
         
     | 
| 
       93 
     | 
    
         
            -
                        title=title,
         
     | 
| 
       94 
     | 
    
         
            -
                        show=show,
         
     | 
| 
       95 
     | 
    
         
            -
                        save=save,
         
     | 
| 
       96 
     | 
    
         
            -
                        **kwargs,
         
     | 
| 
       97 
     | 
    
         
            -
                    )
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       100 
     | 
    
         
            -
                def nhood(
         
     | 
| 
       101 
     | 
    
         
            -
                    mdata: MuData,
         
     | 
| 
       102 
     | 
    
         
            -
                    ix: int,
         
     | 
| 
       103 
     | 
    
         
            -
                    feature_key: str | None = "rna",
         
     | 
| 
       104 
     | 
    
         
            -
                    basis="X_umap",
         
     | 
| 
       105 
     | 
    
         
            -
                    show: bool | None = None,
         
     | 
| 
       106 
     | 
    
         
            -
                    save: bool | str | None = None,
         
     | 
| 
       107 
     | 
    
         
            -
                    **kwargs,
         
     | 
| 
       108 
     | 
    
         
            -
                ) -> None:
         
     | 
| 
       109 
     | 
    
         
            -
                    """Visualize cells in a neighbourhood.
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                    Args:
         
     | 
| 
       112 
     | 
    
         
            -
                        mdata: MuData object with feature_key slot, storing neighbourhood assignments in `mdata[feature_key].obsm['nhoods']`
         
     | 
| 
       113 
     | 
    
         
            -
                        ix: index of neighbourhood to visualize
         
     | 
| 
       114 
     | 
    
         
            -
                        basis: Embedding to use for visualization. Defaults to "X_umap".
         
     | 
| 
       115 
     | 
    
         
            -
                        show: Show the plot, do not return axis.
         
     | 
| 
       116 
     | 
    
         
            -
                        save: If True or a str, save the figure. A string is appended to the default filename. Infer the filetype if ending on {'.pdf', '.png', '.svg'}.
         
     | 
| 
       117 
     | 
    
         
            -
                        **kwargs: Additional arguments to `scanpy.pl.embedding`.
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       120 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       121 
     | 
    
         
            -
                        >>> import scanpy as sc
         
     | 
| 
       122 
     | 
    
         
            -
                        >>> adata = pt.dt.bhattacherjee()
         
     | 
| 
       123 
     | 
    
         
            -
                        >>> milo = pt.tl.Milo()
         
     | 
| 
       124 
     | 
    
         
            -
                        >>> mdata = milo.load(adata)
         
     | 
| 
       125 
     | 
    
         
            -
                        >>> sc.pp.neighbors(mdata["rna"])
         
     | 
| 
       126 
     | 
    
         
            -
                        >>> sc.tl.umap(mdata["rna"])
         
     | 
| 
       127 
     | 
    
         
            -
                        >>> milo.make_nhoods(mdata["rna"])
         
     | 
| 
       128 
     | 
    
         
            -
                        >>> pt.pl.milo.nhood(mdata, ix=0)
         
     | 
| 
       129 
     | 
    
         
            -
                    """
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                    mdata[feature_key].obs["Nhood"] = mdata[feature_key].obsm["nhoods"][:, ix].toarray().ravel()
         
     | 
| 
       132 
     | 
    
         
            -
                    sc.pl.embedding(
         
     | 
| 
       133 
     | 
    
         
            -
                        mdata[feature_key], basis, color="Nhood", size=30, title="Nhood" + str(ix), show=show, save=save, **kwargs
         
     | 
| 
       134 
     | 
    
         
            -
                    )
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       137 
     | 
    
         
            -
                def da_beeswarm(
         
     | 
| 
       138 
     | 
    
         
            -
                    mdata: MuData,
         
     | 
| 
       139 
     | 
    
         
            -
                    feature_key: str | None = "rna",
         
     | 
| 
       140 
     | 
    
         
            -
                    anno_col: str = "nhood_annotation",
         
     | 
| 
       141 
     | 
    
         
            -
                    alpha: float = 0.1,
         
     | 
| 
       142 
     | 
    
         
            -
                    subset_nhoods: list[str] = None,
         
     | 
| 
       143 
     | 
    
         
            -
                    palette: str | Sequence[str] | dict[str, str] | None = None,
         
     | 
| 
       144 
     | 
    
         
            -
                ):
         
     | 
| 
       145 
     | 
    
         
            -
                    """Plot beeswarm plot of logFC against nhood labels
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
                    Args:
         
     | 
| 
       148 
     | 
    
         
            -
                        mdata: MuData object
         
     | 
| 
       149 
     | 
    
         
            -
                        anno_col: Column in adata.uns['nhood_adata'].obs to use as annotation. (default: 'nhood_annotation'.)
         
     | 
| 
       150 
     | 
    
         
            -
                        alpha: Significance threshold. (default: 0.1)
         
     | 
| 
       151 
     | 
    
         
            -
                        subset_nhoods: List of nhoods to plot. If None, plot all nhoods. (default: None)
         
     | 
| 
       152 
     | 
    
         
            -
                        palette: Name of Seaborn color palette for violinplots.
         
     | 
| 
       153 
     | 
    
         
            -
                                 Defaults to pre-defined category colors for violinplots.
         
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
                    Examples:
         
     | 
| 
       156 
     | 
    
         
            -
                        >>> import pertpy as pt
         
     | 
| 
       157 
     | 
    
         
            -
                        >>> import scanpy as sc
         
     | 
| 
       158 
     | 
    
         
            -
                        >>> adata = pt.dt.bhattacherjee()
         
     | 
| 
       159 
     | 
    
         
            -
                        >>> milo = pt.tl.Milo()
         
     | 
| 
       160 
     | 
    
         
            -
                        >>> mdata = milo.load(adata)
         
     | 
| 
       161 
     | 
    
         
            -
                        >>> sc.pp.neighbors(mdata["rna"])
         
     | 
| 
       162 
     | 
    
         
            -
                        >>> milo.make_nhoods(mdata["rna"])
         
     | 
| 
       163 
     | 
    
         
            -
                        >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
         
     | 
| 
       164 
     | 
    
         
            -
                        >>> milo.da_nhoods(mdata, design="~label")
         
     | 
| 
       165 
     | 
    
         
            -
                        >>> milo.annotate_nhoods(mdata, anno_col='cell_type')
         
     | 
| 
       166 
     | 
    
         
            -
                        >>> pt.pl.milo.da_beeswarm(mdata)
         
     | 
| 
       167 
     | 
    
         
            -
                    """
         
     | 
| 
       168 
     | 
    
         
            -
                    try:
         
     | 
| 
       169 
     | 
    
         
            -
                        nhood_adata = mdata["milo"].T.copy()
         
     | 
| 
       170 
     | 
    
         
            -
                    except KeyError:
         
     | 
| 
       171 
     | 
    
         
            -
                        raise RuntimeError(
         
     | 
| 
       172 
     | 
    
         
            -
                            "mdata should be a MuData object with two slots: feature_key and 'milo'. Run 'milopy.count_nhoods(adata)' first."
         
     | 
| 
       173 
     | 
    
         
            -
                        ) from None
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                    if subset_nhoods is not None:
         
     | 
| 
       176 
     | 
    
         
            -
                        nhood_adata = nhood_adata[subset_nhoods]
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                    try:
         
     | 
| 
       179 
     | 
    
         
            -
                        nhood_adata.obs[anno_col]
         
     | 
| 
       180 
     | 
    
         
            -
                    except KeyError:
         
     | 
| 
       181 
     | 
    
         
            -
                        raise RuntimeError(
         
     | 
| 
       182 
     | 
    
         
            -
                            f"Unable to find {anno_col} in mdata.uns['nhood_adata']. Run 'milopy.utils.annotate_nhoods(adata, anno_col)' first"
         
     | 
| 
       183 
     | 
    
         
            -
                        ) from None
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                    try:
         
     | 
| 
       186 
     | 
    
         
            -
                        nhood_adata.obs["logFC"]
         
     | 
| 
       187 
     | 
    
         
            -
                    except KeyError:
         
     | 
| 
       188 
     | 
    
         
            -
                        raise RuntimeError(
         
     | 
| 
       189 
     | 
    
         
            -
                            "Unable to find 'logFC' in mdata.uns['nhood_adata'].obs. Run 'core.da_nhoods(adata)' first."
         
     | 
| 
       190 
     | 
    
         
            -
                        ) from None
         
     | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
                    sorted_annos = (
         
     | 
| 
       193 
     | 
    
         
            -
                        nhood_adata.obs[[anno_col, "logFC"]].groupby(anno_col).median().sort_values("logFC", ascending=True).index
         
     | 
| 
       194 
     | 
    
         
            -
                    )
         
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
                    anno_df = nhood_adata.obs[[anno_col, "logFC", "SpatialFDR"]].copy()
         
     | 
| 
       197 
     | 
    
         
            -
                    anno_df["is_signif"] = anno_df["SpatialFDR"] < alpha
         
     | 
| 
       198 
     | 
    
         
            -
                    anno_df = anno_df[anno_df[anno_col] != "nan"]
         
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
                    try:
         
     | 
| 
       201 
     | 
    
         
            -
                        obs_col = nhood_adata.uns["annotation_obs"]
         
     | 
| 
       202 
     | 
    
         
            -
                        if palette is None:
         
     | 
| 
       203 
     | 
    
         
            -
                            palette = dict(
         
     | 
| 
       204 
     | 
    
         
            -
                                zip(mdata[feature_key].obs[obs_col].cat.categories, mdata[feature_key].uns[f"{obs_col}_colors"])
         
     | 
| 
       205 
     | 
    
         
            -
                            )
         
     | 
| 
       206 
     | 
    
         
            -
                        sns.violinplot(
         
     | 
| 
       207 
     | 
    
         
            -
                            data=anno_df,
         
     | 
| 
       208 
     | 
    
         
            -
                            y=anno_col,
         
     | 
| 
       209 
     | 
    
         
            -
                            x="logFC",
         
     | 
| 
       210 
     | 
    
         
            -
                            order=sorted_annos,
         
     | 
| 
       211 
     | 
    
         
            -
                            size=190,
         
     | 
| 
       212 
     | 
    
         
            -
                            inner=None,
         
     | 
| 
       213 
     | 
    
         
            -
                            orient="h",
         
     | 
| 
       214 
     | 
    
         
            -
                            palette=palette,
         
     | 
| 
       215 
     | 
    
         
            -
                            linewidth=0,
         
     | 
| 
       216 
     | 
    
         
            -
                            scale="width",
         
     | 
| 
       217 
     | 
    
         
            -
                        )
         
     | 
| 
       218 
     | 
    
         
            -
                    except BaseException:  # noqa: BLE001
         
     | 
| 
       219 
     | 
    
         
            -
                        sns.violinplot(
         
     | 
| 
       220 
     | 
    
         
            -
                            data=anno_df,
         
     | 
| 
       221 
     | 
    
         
            -
                            y=anno_col,
         
     | 
| 
       222 
     | 
    
         
            -
                            x="logFC",
         
     | 
| 
       223 
     | 
    
         
            -
                            order=sorted_annos,
         
     | 
| 
       224 
     | 
    
         
            -
                            size=190,
         
     | 
| 
       225 
     | 
    
         
            -
                            inner=None,
         
     | 
| 
       226 
     | 
    
         
            -
                            orient="h",
         
     | 
| 
       227 
     | 
    
         
            -
                            linewidth=0,
         
     | 
| 
       228 
     | 
    
         
            -
                            scale="width",
         
     | 
| 
       229 
     | 
    
         
            -
                        )
         
     | 
| 
       230 
     | 
    
         
            -
                    sns.stripplot(
         
     | 
| 
       231 
     | 
    
         
            -
                        data=anno_df,
         
     | 
| 
       232 
     | 
    
         
            -
                        y=anno_col,
         
     | 
| 
       233 
     | 
    
         
            -
                        x="logFC",
         
     | 
| 
       234 
     | 
    
         
            -
                        order=sorted_annos,
         
     | 
| 
       235 
     | 
    
         
            -
                        size=2,
         
     | 
| 
       236 
     | 
    
         
            -
                        hue="is_signif",
         
     | 
| 
       237 
     | 
    
         
            -
                        palette=["grey", "black"],
         
     | 
| 
       238 
     | 
    
         
            -
                        orient="h",
         
     | 
| 
       239 
     | 
    
         
            -
                        alpha=0.5,
         
     | 
| 
       240 
     | 
    
         
            -
                    )
         
     | 
| 
       241 
     | 
    
         
            -
                    plt.legend(loc="upper left", title=f"< {int(alpha * 100)}% SpatialFDR", bbox_to_anchor=(1, 1), frameon=False)
         
     | 
| 
       242 
     | 
    
         
            -
                    plt.axvline(x=0, ymin=0, ymax=1, color="black", linestyle="--")
         
     | 
| 
       243 
     | 
    
         
            -
             
     | 
| 
       244 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       245 
     | 
    
         
            -
                def nhood_counts_by_cond(
         
     | 
| 
       246 
     | 
    
         
            -
                    mdata: MuData,
         
     | 
| 
       247 
     | 
    
         
            -
                    test_var: str,
         
     | 
| 
       248 
     | 
    
         
            -
                    subset_nhoods: list = None,
         
     | 
| 
       249 
     | 
    
         
            -
                    log_counts: bool = False,
         
     | 
| 
       250 
     | 
    
         
            -
                ):
         
     | 
| 
       251 
     | 
    
         
            -
                    """Plot boxplot of cell numbers vs condition of interest
         
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
                    Args:
         
     | 
| 
       254 
     | 
    
         
            -
                        mdata: MuData object storing cell level and nhood level information
         
     | 
| 
       255 
     | 
    
         
            -
                        test_var: Name of column in adata.obs storing condition of interest (y-axis for boxplot)
         
     | 
| 
       256 
     | 
    
         
            -
                        subset_nhoods: List of obs_names for neighbourhoods to include in plot. If None, plot all nhoods. (default: None)
         
     | 
| 
       257 
     | 
    
         
            -
                        log_counts: Whether to plot log1p of cell counts. (default: False)
         
     | 
| 
       258 
     | 
    
         
            -
                    """
         
     | 
| 
       259 
     | 
    
         
            -
                    try:
         
     | 
| 
       260 
     | 
    
         
            -
                        nhood_adata = mdata["milo"].T.copy()
         
     | 
| 
       261 
     | 
    
         
            -
                    except KeyError:
         
     | 
| 
       262 
     | 
    
         
            -
                        raise RuntimeError(
         
     | 
| 
       263 
     | 
    
         
            -
                            "mdata should be a MuData object with two slots: feature_key and 'milo'. Run milopy.count_nhoods(mdata) first"
         
     | 
| 
       264 
     | 
    
         
            -
                        ) from None
         
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
                    if subset_nhoods is None:
         
     | 
| 
       267 
     | 
    
         
            -
                        subset_nhoods = nhood_adata.obs_names
         
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
                    pl_df = pd.DataFrame(nhood_adata[subset_nhoods].X.A, columns=nhood_adata.var_names).melt(
         
     | 
| 
       270 
     | 
    
         
            -
                        var_name=nhood_adata.uns["sample_col"], value_name="n_cells"
         
     | 
| 
       271 
     | 
    
         
            -
                    )
         
     | 
| 
       272 
     | 
    
         
            -
                    pl_df = pd.merge(pl_df, nhood_adata.var)
         
     | 
| 
       273 
     | 
    
         
            -
                    pl_df["log_n_cells"] = np.log1p(pl_df["n_cells"])
         
     | 
| 
       274 
     | 
    
         
            -
                    if not log_counts:
         
     | 
| 
       275 
     | 
    
         
            -
                        sns.boxplot(data=pl_df, x=test_var, y="n_cells", color="lightblue")
         
     | 
| 
       276 
     | 
    
         
            -
                        sns.stripplot(data=pl_df, x=test_var, y="n_cells", color="black", s=3)
         
     | 
| 
       277 
     | 
    
         
            -
                        plt.ylabel("# cells")
         
     | 
| 
       278 
     | 
    
         
            -
                    else:
         
     | 
| 
       279 
     | 
    
         
            -
                        sns.boxplot(data=pl_df, x=test_var, y="log_n_cells", color="lightblue")
         
     | 
| 
       280 
     | 
    
         
            -
                        sns.stripplot(data=pl_df, x=test_var, y="log_n_cells", color="black", s=3)
         
     | 
| 
       281 
     | 
    
         
            -
                        plt.ylabel("log(# cells + 1)")
         
     | 
| 
       282 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
                    plt.xticks(rotation=90)
         
     | 
| 
       284 
     | 
    
         
            -
                    plt.xlabel(test_var)
         
     |