Source code for scplotkit.markers

"""Marker gene visualizations: rank_genes_groups dot/matrix plots and
matrix/violin plots for a user-supplied marker set."""

from __future__ import annotations

from pathlib import Path

import matplotlib.pyplot as plt
import scanpy as sc

from ._config import PlotConfig
from ._style import save_figure
from ._utils import require_columns

__all__ = [
    "rank_genes_matrix_and_dot",
    "annotation_marker_matrixplot",
    "annotation_marker_stacked_violin",
]


[docs] def rank_genes_matrix_and_dot( adata, groupby_column: str, n_markers: int = 5, method: str = "wilcoxon", layer: str | None = None, standard_scale: str | None = "var", use_expression: bool = False, figsize: tuple = (12, 8), # title: str | None = None, save_name: str | None = None, config: PlotConfig | None = None, output_dir: str | Path | None = "figures", **kwargs, ): """Compute marker genes with ``sc.tl.rank_genes_groups`` and plot them as a dotplot and a matrixplot, both ordered by a dendrogram over ``groupby_column``. By default, dot/matrix color encodes log fold change (``config.rank_genes`` defaults: ``values_to_plot="logfoldchanges"``, diverging ``cmap``/``vmin``/ ``vmax``). Set ``use_expression=True`` to instead color by mean expression, scaled per gene via ``standard_scale`` (``"var"`` by default). ``**kwargs`` are forwarded to both the ``sc.pl.rank_genes_groups_dotplot`` and ``sc.pl.rank_genes_groups_matrixplot`` calls, overriding this function's own defaults -- anything the underlying scanpy functions accept. Returns ``(fig_dot, fig_matrix)``. """ config = PlotConfig.load(config) require_columns(adata, groupby_column) general = config.general rank_cfg = config["rank_genes"] print(f"Computing marker genes for '{groupby_column}' using {method} method...") sc.tl.dendrogram(adata, groupby=groupby_column) sc.tl.rank_genes_groups( adata, groupby=groupby_column, method=method, layer=layer, use_raw=False, min_logfoldchange=rank_cfg["min_logfoldchange"], ) plt.rcParams["font.family"] = general["font_family"] if use_expression: values_to_plot = None plot_standard_scale = standard_scale vmin = None vmax = None cmap = config["continuous"]["cmap"] else: values_to_plot = rank_cfg["values_to_plot"] plot_standard_scale = None vmin = rank_cfg["vmin"] vmax = rank_cfg["vmax"] cmap = rank_cfg["cmap"] print("Generating dotplot...") fig_dot = plt.figure(figsize=figsize, dpi=general["dpi"]) sc.pl.rank_genes_groups_dotplot( adata, **{ "groupby": groupby_column, "standard_scale": plot_standard_scale, "n_genes": n_markers, "use_raw": False, "layer": layer, "ax": fig_dot.gca(), "var_group_rotation": rank_cfg["var_group_rotation"], "values_to_plot": values_to_plot, "vmin": vmin, "vmax": vmax, "cmap": cmap, "show": False, **kwargs, }, ) ax_dot = fig_dot.gca() legend = ax_dot.get_legend() if legend: for text in legend.get_texts(): text.set_fontsize(general["legend_fontsize"]) text.set_fontweight(general["legend_fontweight"]) plt.tight_layout() if save_name is not None: save_figure(fig_dot, output_dir, "marker_analysis", f"{save_name}_dotplot.png", config) print("Generating matrixplot...") fig_matrix = plt.figure(figsize=figsize, dpi=general["dpi"]) sc.pl.rank_genes_groups_matrixplot( adata, **{ "groupby": groupby_column, "standard_scale": plot_standard_scale, "n_genes": n_markers, "use_raw": False, "layer": layer, "ax": fig_matrix.gca(), "var_group_rotation": rank_cfg["var_group_rotation"], "values_to_plot": values_to_plot, "vmin": vmin, "vmax": vmax, "cmap": cmap, "show": False, **kwargs, }, ) plt.tight_layout() if save_name is not None: save_figure(fig_matrix, output_dir, "marker_analysis", f"{save_name}_matrixplot.png", config) return fig_dot, fig_matrix
def _flatten_markers(markers: dict[str, list[str]]) -> tuple[list[str], list[str]]: cell_types = sorted(markers.keys()) flat = [gene for ct in cell_types for gene in markers[ct]] return cell_types, flat
[docs] def annotation_marker_matrixplot( adata, markers: dict[str, list[str]], groupby_column: str, layer: str | None = None, standard_scale: str | None = "var", cmap: str = "coolwarm", figsize: tuple = (12, 8), save_name: str | None = None, config: PlotConfig | None = None, output_dir: str | Path | None = "figures", **kwargs, ): """Matrixplot of a user-supplied ``{cell_type: [marker_genes]}`` set, restricted to cells whose ``groupby_column`` value is one of ``markers``' keys. ``**kwargs`` are forwarded to ``sc.pl.matrixplot``, overriding this function's own defaults -- anything the underlying scanpy function accepts. """ config = PlotConfig.load(config) require_columns(adata, groupby_column) cell_types, flat_markers = _flatten_markers(markers) fig = plt.figure(figsize=figsize, dpi=config.general["dpi"]) sc.pl.matrixplot( adata[adata.obs[groupby_column].isin(cell_types)], **{ "standard_scale": standard_scale, "layer": layer, "var_names": flat_markers, "groupby": groupby_column, "cmap": cmap, "ax": fig.gca(), "show": False, **kwargs, }, ) plt.tight_layout() if save_name is not None: save_figure(fig, output_dir, "marker_analysis", f"{save_name}_matrixplot_markers.png", config) return fig
[docs] def annotation_marker_stacked_violin( adata, markers: dict[str, list[str]], groupby_column: str, layer: str | None = None, standard_scale: str | None = "var", cmap: str = "coolwarm", figsize: tuple = (12, 8), save_name: str | None = None, config: PlotConfig | None = None, output_dir: str | Path | None = "figures", **kwargs, ): """Stacked violin plot of a user-supplied ``{cell_type: [marker_genes]}`` set, restricted to cells whose ``groupby_column`` value is one of ``markers``' keys. ``**kwargs`` are forwarded to ``sc.pl.stacked_violin``, overriding this function's own defaults -- anything the underlying scanpy function accepts. """ config = PlotConfig.load(config) require_columns(adata, groupby_column) cell_types, flat_markers = _flatten_markers(markers) fig = plt.figure(figsize=figsize, dpi=config.general["dpi"]) sc.pl.stacked_violin( adata[adata.obs[groupby_column].isin(cell_types)], **{ "standard_scale": standard_scale, "layer": layer, "var_names": flat_markers, "groupby": groupby_column, "cmap": cmap, "ax": fig.gca(), "show": False, **kwargs, }, ) plt.tight_layout() if save_name is not None: save_figure(fig, output_dir, "marker_analysis", f"{save_name}_stacked_violin_markers.png", config) return fig