Source code for sccellfie.plotting.distributions

import os
import textwrap
import scanpy as sc
import matplotlib.pyplot as plt


[docs] def create_multi_violin_plots(adata, features, groupby, n_cols=4, figsize=(5, 5), ylabel=None, title=None, fontsize=10, rotation=90, wrapped_title_length=45, save=None, dpi=300, tight_layout=True, w_pad=None, h_pad=None, **kwargs): """ Plots a grid of violin plots for multiple genes in Scanpy, controlling the number of columns. Parameters ---------- adata : AnnData Annotated data matrix. features : list of str List of feature names to plot. Should match names in adata.var_names. groupby : str Key in `adata.obs` containing the groups to plot. For each unique value in this column, a violin plot will be generated. n_cols : int, optional (default: 4) Number of columns in the grid. figsize : tuple of float, optional (default: (5, 5)) Size of each subplot in inches. ylabel : str, optional (default: None) Label for the y-axis. If None, the label will be the variable name. title : list of str, optional (default: None) List of labels for each feature. If None, the feature name will be used. fontsize : int, optional (default: 10) Font size for the title and axis labels. The tick labels will be set to `fontsize`, while the title will be set to `fontsize + 4`. Ylabel will be set to `fontsize + 2`. rotation : int, optional (default: 90) Rotation of the x-axis tick labels wrapped_title_length : int, optional (default: 50) The maximum number of characters per line in the title. save : str, optional (default: None) Filepath to save the figure. If not provided, the figure will be displayed. dpi : int, optional (default: 300) Resolution of the saved figure. tight_layout : bool, optional (default: True) Whether to use tight layout. w_pad : float, optional (default: None) Width padding between subplots. h_pad : float, optional (default: None) Height padding between subplots. **kwargs : dict Additional arguments to pass to `sc.pl.violin`. For example, `rotation` can be used to rotate the x-axis labels. """ n_genes = len(features) n_rows = -(-n_genes // n_cols) # Ceiling division fig, axes = plt.subplots(n_rows, n_cols, figsize=(figsize[0] * n_cols, figsize[1] * n_rows), squeeze=False) fig.tight_layout(pad=3.0) for i, feature in enumerate(features): row = i // n_cols col = i % n_cols ax = axes[row, col] sc.pl.violin(adata, keys=feature, groupby=groupby, ax=ax, show=False, rotation=rotation, **kwargs) if title is not None: wrapped_title = "\n".join(textwrap.wrap(title[i], width=wrapped_title_length)) else: wrapped_title = "\n".join(textwrap.wrap(feature, width=wrapped_title_length)) if ylabel is None: ylabel_ = wrapped_title else: ax.set_title(wrapped_title, fontsize=fontsize + 4) ylabel_ = ylabel ax.set_ylabel(ylabel_, fontsize=fontsize + 2) ax.tick_params(axis='x', labelsize=fontsize) ax.tick_params(axis='y', labelsize=fontsize) # Remove empty subplots for i in range(n_genes, n_rows * n_cols): row = i // n_cols col = i % n_cols fig.delaxes(axes[row, col]) if tight_layout: plt.tight_layout(w_pad=w_pad, h_pad=h_pad) if save: from sccellfie.plotting.plot_utils import _get_file_format, _get_file_dir dir, basename = _get_file_dir(save) os.makedirs(dir, exist_ok=True) format = _get_file_format(save) plt.savefig(f'{dir}/violin_{basename}.{format}', dpi=dpi, bbox_inches='tight') return fig, axes