Source code for magic.plot

# (C) 2017 Krishnaswamy Lab GPLv2

from .magic import MAGIC
from .utils import in_ipynb
from matplotlib import animation
from matplotlib import rc

import matplotlib.pyplot as plt
import numbers
import numpy as np
import pandas as pd
import scprep


def _validate_gene(gene, data):
    if isinstance(gene, str):
        if not isinstance(data, pd.DataFrame):
            raise ValueError(
                "Non-integer gene names only valid with pd.DataFrame "
                "input. X is a {}, gene = {}".format(type(data).__name__, gene)
            )
        if gene not in data.columns:
            raise ValueError("gene {} not found".format(gene))
    elif gene is not None and not isinstance(gene, numbers.Integral):
        raise TypeError("Expected int or str. Got {}".format(type(gene).__name__))
    return gene


[docs]def animate_magic( data, gene_x, gene_y, gene_color=None, t_max=20, delay=2, operator=None, filename=None, ax=None, figsize=None, s=1, cmap="inferno", interval=200, dpi=100, ipython_html="jshtml", verbose=False, **kwargs, ): """Animate a gene-gene relationship with increased diffusion Parameters ---------- data: array-like Input data matrix gene_x : int or str Gene to put on the x axis gene_y : int or str Gene to put on the y axis gene_color : int or str, optional (default: None) Gene to color by. If None, no color vector is used t_max : int, optional (default: 20) maximum value of t to include in the animation delay : int, optional (default: 5) number of frames to dwell on the first frame before applying MAGIC operator : magic.MAGIC, optional (default: None) precomputed MAGIC operator. If None, one is created. filename : str, optional (default: None) If not None, saves a .gif or .mp4 with the output ax : `matplotlib.Axes` or None, optional (default: None) axis on which to plot. If None, an axis is created figsize : tuple, optional (default: None) Tuple of floats for creation of new `matplotlib` figure. Only used if `ax` is None. s : int, optional (default: 1) Point size cmap : str or callable, optional (default: 'inferno') Matplotlib colormap interval : float, optional (default: 30) Time in milliseconds between frames dpi : int, optional (default: 100) Dots per inch (image quality) in saved animation) ipython_html : {'html5', 'jshtml'} which html writer to use if using a Jupyter Notebook verbose : bool, optional (default: False) MAGIC operator verbosity *kwargs : arguments for MAGIC Returns ------- A Matplotlib animation showing diffusion of an edge with increased t """ if in_ipynb(): # credit to # http://tiao.io/posts/notebooks/save-matplotlib-animations-as-gifs/ rc("animation", html=ipython_html) if filename is not None: if filename.endswith(".gif"): writer = "imagemagick" elif filename.endswith(".mp4"): writer = "ffmpeg" else: raise ValueError( "filename must end in .gif or .mp4. Got {}".format(filename) ) if operator is None: operator = MAGIC(verbose=verbose, **kwargs).fit(data) else: operator.set_params(verbose=verbose, **kwargs) gene_x = _validate_gene(gene_x, data) gene_y = _validate_gene(gene_y, data) gene_color = _validate_gene(gene_color, data) if gene_color is not None: genes = np.array([gene_x, gene_y, gene_color]) else: genes = np.array([gene_x, gene_y]) if isinstance(cmap, str): cmap = plt.cm.cmap_d[cmap] if ax is None: fig, ax = plt.subplots(figsize=figsize) show = True else: fig = ax.get_figure() show = False data_magic = scprep.select.select_cols(data, idx=genes) data_magic = scprep.utils.toarray(data_magic) c = data_magic[gene_color] if gene_color is not None else None sc = ax.scatter(data_magic[gene_x], data_magic[gene_y], c=c, cmap=cmap) ax.set_title("t = 0") ax.set_xlabel(gene_x) ax.set_ylabel(gene_y) ax.set_xticks([]) ax.set_yticks([]) ax.set_xticklabels([]) ax.set_yticklabels([]) if gene_color is not None: plt.colorbar(sc, label=gene_color, ticks=[]) data_magic = [data] for t in range(t_max): operator.set_params(t=t + 1) data_magic.append(operator.transform(genes=genes)) def init(): return ax def animate(i): i = max(i - delay, 0) data_t = data_magic[i] data_t = data_t if isinstance(data, pd.DataFrame) else data_t.T sc.set_offsets(np.array([data_t[gene_x], data_t[gene_y]]).T) xlim = np.min(data_t[gene_x]), np.max(data_t[gene_x]) xrange = xlim[1] - xlim[0] ax.set_xlim(xlim[0] - xrange / 10, xlim[1] + xrange / 10) ylim = np.min(data_t[gene_y]), np.max(data_t[gene_y]) yrange = ylim[1] - ylim[0] ax.set_ylim(ylim[0] - yrange / 10, ylim[1] + yrange / 10) ax.set_title("t = {}".format(i)) if gene_color is not None: color_t = data_t[gene_color] color_t -= np.min(color_t) color_t /= np.max(color_t) sc.set_facecolor(cmap(color_t)) return ax ani = animation.FuncAnimation( fig, animate, init_func=init, frames=range(t_max + delay + 1), interval=interval, blit=False, ) if filename is not None: ani.save(filename, writer=writer, dpi=dpi) if in_ipynb(): # credit to https://stackoverflow.com/a/45573903/3996580 plt.close() elif show: plt.tight_layout() fig.show() return ani