Source code for sc_utils.plotting

from typing import Collection, Optional

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import scanpy as sc


[docs]def expr_colormap(): """\ Gray-to-blue colormap for expression data """ cdict = { 'red': [ (0.0, 220/256, 220/256), (0.5, 42/256, 42/256), (1.0, 6/256, 6/256) ], 'green': [ (0.0, 220/256, 220/256), (0.5, 145/256, 145/256), (1.0, 37/256, 27/256) ], 'blue': [ (0.0, 220/256, 220/256), (0.5, 174/256, 174/256), (1.0, 170/256, 170/256) ] } return mpl.colors.LinearSegmentedColormap('exprCmap', segmentdata=cdict, N=256)
[docs]def feature_plot( adata: sc.AnnData, feature: str, gridsize: tuple = (180, 70), linewidths: float = 0.15, figsize: Optional[float] = None ) -> mpl.figure.Figure: """\ Plot expression of gene or feature in hexbin Plots numeric feature value, commonly gene expression, on UMAP coordinates using hexbin. Feature is taken from ``adata.obs`` if it is found there, otherwise from ``adata.raw``. Parameters ---------- adata Annotated data matrix feature Name of the feature to plot gridsize Tuple of hexbin dimentions, larger numbers produce smaller hexbins linewidths Width of the lines to draw around each hexbin figsize Optional, make figure of this size Returns ------- Matplotlib figure with colorbar added. """ if feature in adata.obs.columns: values = adata.obs_vector(feature) else: values = adata.raw.obs_vector(feature) kwargs = {} if figsize is not None: kwargs["figsize"] = figsize fig, ax = plt.subplots(**kwargs) hb = ax.hexbin( adata.obsm["X_umap"][:, 0], adata.obsm["X_umap"][:, 1], C=values, cmap=expr_colormap(), gridsize=gridsize, linewidths=linewidths ) cax = fig.add_axes((0.92, 0.8, 0.02, 0.15)) fig.colorbar(hb, cax=cax, fraction=0.05, pad=0.02, aspect=40) ax.set_xticks([]) ax.set_yticks([]) ax.set_title(f"{feature}") ax.set_xlabel("UMAP1") ax.set_ylabel("UMAP2") ax.spines["top"].set_visible(False) ax.spines["right"].set_visible(False) fig.tight_layout() return fig
[docs]def plot_composition( adata: sc.AnnData, group_by: str, color: str, relative: bool = False, palette: Optional[Collection] = None, plot_numbers: bool = False ) -> mpl.axes.Axes: """\ Plot composition of clusters or other metadata Groups cells by one metadata field and plots stacked barplot colored by another metadata field. Common use case is to see which samples contribute to which clusters. Plots horizontally. Parameters ---------- adata Annotated data matrix group_by Name of the field to group by on y axis color Name of the field to color by relative Plot percentage for each cluster if ``True`` or absolute counts if ``False`` palette Optional, pass your own palette plot_numbers If ``True``, plot number of cells next to the bars Returns ------- Matplotlib axes with the plot. """ left = np.zeros(len(adata.obs[group_by].unique())) total = None if relative: total = adata.obs[group_by].value_counts().sort_index(ascending=False) fig, ax = plt.subplots() num_colors = adata.obs[color].unique().size # TODO: adjust if palette is not None: colors = palette elif num_colors <= 10: colors = mpl.cm.tab10 elif num_colors <= 20: colors = mpl.cm.tab20 elif num_colors <= 28: colors = sc.pl.palettes.default_28 else: colors = sc.pl.palettes.default_102 for i, s in enumerate(adata.obs[color].cat.categories): cnt = adata.obs[group_by][adata.obs[color] == s].value_counts().sort_index(ascending=False) if relative: cnt = cnt / total * 100 c = isinstance(colors, list) and colors[i] or colors(i) ax.barh(cnt.index, cnt, left=left, label=s, color=c) left += cnt if plot_numbers: for i, count in enumerate(total): ax.text(left[i] + 2, i, str(count), va="center") ax.legend(title=color.capitalize()) ax.set_title(f"{group_by.capitalize()} by {color}") return ax