Basic plotting tools¶
hv resources
Gallery: https://holoviews.org/reference/
https://holoviews.org/user_guide/Customizing_Plots.html
https://holoviews.org/user_guide/Style_Mapping.html
https://holoviews.org/user_guide/Colormaps.html
https://holoviews.org/user_guide/Plotting_with_Bokeh.html
%load_ext autoreload
%autoreload 2
import holoviews as hv
import hv_anndata
from hv_anndata import A, register
from hv_anndata import scanpy as hv_sc
register()
hv.extension("bokeh")
import numpy as np
import scanpy as sc
rng = np.random.default_rng()
adata = sc.datasets.pbmc68k_reduced()
adata.layers["counts"] = adata.raw.X
del adata.raw
sc.tl.umap(adata)
adata
/home/docs/.local/share/hatch/env/virtual/hv-anndata/STk7F69l/docs/lib/python3.13/site-packages/numba/cpython/hashing.py:477: UserWarning: FNV hashing is not implemented in Numba. See PEP 456 https://www.python.org/dev/peps/pep-0456/ for rationale over not using FNV. Numba will continue to work, but hashes for built in types will be computed using siphash24. This will permit e.g. dictionaries to continue to behave as expected, however anything relying on the value of the hash opposed to hash as a derived property is likely to not work as expected.
warnings.warn(msg)
AnnData object with n_obs × n_vars = 700 × 765
obs: 'bulk_labels', 'n_genes', 'percent_mito', 'n_counts', 'S_score', 'G2M_score', 'phase', 'louvain'
var: 'n_counts', 'means', 'dispersions', 'dispersions_norm', 'highly_variable'
uns: 'bulk_labels_colors', 'louvain', 'louvain_colors', 'neighbors', 'pca', 'rank_genes_groups', 'umap'
obsm: 'X_pca', 'X_umap'
varm: 'PCs'
obsp: 'connectivities', 'distances'
layers: None (.X), 'counts'
missing features:
use_raw(deprecated!)na_color(not super important)color=dimensionin plotly backend: holoviz/holoviews#5222
missing convenience:
basisfor easy X&Y
(
hv_sc.scatter(adata, A.X[:, ["PSAP", "C1QA"]], color=A.obs["bulk_labels"]).opts(
cmap="tab10", show_legend=False
)
+ hv_sc.scatter(
adata, A.layers["counts"][:, ["PSAP", "C1QA"]], color=A.obs["bulk_labels"]
).opts(cmap="tab10")
)
# add NAs to check how missing values look
adata_scatter = adata.copy()
adata_scatter.obs.loc[
(
(adata_scatter.obs["bulk_labels"] == "Dendritic")
& rng.choice([True, False], size=len(adata_scatter))
),
"bulk_labels",
] = np.nan
hv_sc.umap(adata_scatter) + hv_sc.umap(adata_scatter, color=A.obs["bulk_labels"]).opts(
cmap="tab10"
)
missing:
groupby/ TickBarstandard_scale(see implemantation inhv_anndata.Dotmap)maybe done using
dimexpressions?
dendrogram doesn’t work on heatmap (again ndim problem: dendrogram should tread
(n, 1)as 1D)
markers = ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]
(
hv_sc.heatmap(adata[:, markers], A.X, [A.obs["n_counts"]], add_dendrogram="obs")
+ hv_sc.heatmap(adata[:, markers], A.layers["counts"], [A.obs["n_counts"]])
).cols(1).opts(hv.opts.HeatMap(xticks=0, width=800, height=300)).opts(shared_axes=False)
TODO: support sparse data
hv_sc.heatmap(adata[:40], A.obsp["distances"]).opts(tools=["hover"])
missing:
var_group_*(highlight groups ofvar_namesby drawing brackets)
markers = ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]
dm = hv_anndata.Dotmap(adata=adata, marker_genes=markers, groupby="bulk_labels")
dm
WARNING:param.main: JSONEditor was not imported on instantiation and may not render in a notebook. Restart the notebook kernel and ensure you load it as part of the extension using:
pn.extension('jsoneditor')
hv.operation.dendrogram(
dm.plot(), adjoint_dims=["cluster"], main_dim="mean_expression", invert=True
)
missing:
shared_xaxis=Falsedoesn’t seem to work on GridSpaceGridSpace can only be 2D or row-only, not col-only
hv_sc.tracksplot(
adata,
A.X[:, ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]],
color=A.obs["bulk_labels"],
).opts(hv.opts.Curve(aspect=20))
missing:
density_norm
hv_sc.violin(adata, A.obs[["percent_mito", "n_counts", "n_genes"]]).opts(
hv.opts.Violin(ylim=(0, None))
)
hv_sc.violin(adata, A.obs["S_score"], color=A.obs["bulk_labels"]).opts(
width=500, xrotation=30
)
missing:
see tracksplot above
can’t do
.hist()or.operations.dendrogramon GridSpaceslow!
markers = ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]
hv_sc.stacked_violin(adata[:, markers], A.var.index, A.obs["bulk_labels"]).opts(
hv.opts.Violin(frame_height=50, frame_width=50)
)
missing:
aspect="equal"breaks (bokeh tries to divideNone/None)hist doesn’t align properly
markers = ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]
hv_sc.matrixplot(
adata[:, markers], A.obs["bulk_labels"], data=A.layers["counts"], add_totals=True
).opts(hv.opts.Bars(width=150))
missing:
TickBar (see above)
hv_anndata.ClusterMap(adata=adata)