Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/release-notes/1.10.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* {func}`~scanpy.pp.scrublet` and {func}`~scanpy.pp.scrublet_simulate_doublets` were moved from {mod}`scanpy.external.pp` to {mod}`scanpy.pp`.
The `scrublet` implementation is now maintained as part of scanpy {pr}`2703` {smaller}`P Angerer`
* Enhanced dask support for some internal utilities, paving the way for more extensive dask support {pr}`2696` {smaller}`P Angerer`
* {func}`scanpy.tl.dendrogram` now accepts `axis` argument to enable dendrograms on `obs` or `var` {pr}`2771` {smaller}`D Burkhardt`
* {func}`scanpy.pp.pca`, {func}`scanpy.pp.scale`, {func}`scanpy.pl.embedding`, and {func}`scanpy.experimental.pp.normalize_pearson_residuals_pca`
now support a `mask` parameter {pr}`2272` {smaller}`C Bright, T Marcella, & P Angerer`
* {func}`scanpy.tl.rank_genes_groups` no longer warns that it's default was changed from t-test_overestim_var to t-test {pr}`2798` {smaller}`L Heumos`
Expand All @@ -33,6 +34,7 @@
* Fix {func}`~scanpy.pp.normalize_total` {pr}`2466` {smaller}`P Angerer`
* Fix testing package build {pr}`2468` {smaller}`P Angerer`
* Fix setting `sc.settings.verbosity` in some cases {pr}`2605` {smaller}`P Angerer`
* Fix `sc.tl.dendrogram` ignoring passed `var_names` {pr}`2771` {smaller}`D Burkhardt`
* Fix all remaining pandas warnings {pr}`2789` {smaller}`P Angerer`
* Fix some annoying plotting warnings around violin plots {pr}`2844` {smaller}`P Angerer`
* Scanpy now has a test job which tests against the minumum versions of the dependencies. In the process of implementing this, many bugs associated with using older versions of `pandas`, `anndata`, `numpy`, and `matplotlib` were fixed. {pr}`2816` {smaller}`I Virshup`
Expand Down
60 changes: 23 additions & 37 deletions scanpy/plotting/_anndata.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from .._compat import old_positionals
from .._settings import settings
from .._utils import _check_use_raw, _doc_params, sanitize_anndata
from ..tools._dendrogram import _get_dendrogram_key
from ..tools._utils import _resolve_axis
from . import _utils
from ._docs import (
doc_common_plot_args,
Expand Down Expand Up @@ -1738,8 +1740,9 @@ def tracksplot(
@_doc_params(show_save_ax=doc_show_save_ax)
def dendrogram(
adata: AnnData,
groupby: str,
groupby: str | Sequence[str] | None = None,
*,
axis: Literal["obs", 0, "var", 1] = "obs",
dendrogram_key: str | None = None,
orientation: Literal["top", "bottom", "left", "right"] = "top",
remove_labels: bool = False,
Expand All @@ -1758,6 +1761,8 @@ def dendrogram(
Annotated data matrix.
groupby
Categorical data column used to create the dendrogram
axis
Axis for which to plot the dendrogram.
dendrogram_key
Key under with the dendrogram information was stored.
By default the dendrogram information is stored under
Expand Down Expand Up @@ -1788,10 +1793,12 @@ def dendrogram(
"""
if ax is None:
_, ax = plt.subplots()
axis, axis_name = _resolve_axis(axis)
_plot_dendrogram(
ax,
adata,
groupby,
axis_name=axis_name,
dendrogram_key=dendrogram_key,
remove_labels=remove_labels,
orientation=orientation,
Expand Down Expand Up @@ -1867,7 +1874,9 @@ def correlation_matrix(
>>> sc.pl.correlation_matrix(adata, 'bulk_labels')
"""

dendrogram_key = _get_dendrogram_key(adata, dendrogram, groupby)
dendrogram_key = _get_dendrogram_key(
dendrogram, groupby, axis_name="obs", adata=adata
)

index = adata.uns[dendrogram_key]["categories_idx_ordered"]
corr_matrix = adata.uns[dendrogram_key]["correlation_matrix"]
Expand Down Expand Up @@ -2244,8 +2253,8 @@ def _plot_gene_groups_brackets(

def _reorder_categories_after_dendrogram(
adata: AnnData,
groupby,
dendrogram,
groupby: str | Sequence[str],
dendrogram: bool | str | None,
*,
var_names=None,
var_group_labels=None,
Expand All @@ -2270,12 +2279,14 @@ def _reorder_categories_after_dendrogram(
'var_group_labels', and 'var_group_positions'
"""

key = _get_dendrogram_key(adata, dendrogram, groupby)
dendrogram_key = _get_dendrogram_key(
dendrogram, groupby, axis_name="obs", adata=adata
)

if isinstance(groupby, str):
groupby = [groupby]

dendro_info = adata.uns[key]
dendro_info = adata.uns[dendrogram_key]
if groupby != dendro_info["groupby"]:
raise ValueError(
"Incompatible observations. The precomputed dendrogram contains "
Expand Down Expand Up @@ -2355,50 +2366,25 @@ def _format_first_three_categories(categories):
return ", ".join(categories)


def _get_dendrogram_key(adata, dendrogram_key, groupby):
# the `dendrogram_key` can be a bool an NoneType or the name of the
# dendrogram key. By default the name of the dendrogram key is 'dendrogram'
if not isinstance(dendrogram_key, str):
if isinstance(groupby, str):
dendrogram_key = f"dendrogram_{groupby}"
elif isinstance(groupby, list):
dendrogram_key = f'dendrogram_{"_".join(groupby)}'

if dendrogram_key not in adata.uns:
from ..tools._dendrogram import dendrogram

logg.warning(
f"dendrogram data not found (using key={dendrogram_key}). "
"Running `sc.tl.dendrogram` with default parameters. For fine "
"tuning it is recommended to run `sc.tl.dendrogram` independently."
)
dendrogram(adata, groupby, key_added=dendrogram_key)

if "dendrogram_info" not in adata.uns[dendrogram_key]:
raise ValueError(
f"The given dendrogram key ({dendrogram_key!r}) does not contain "
"valid dendrogram information."
)

return dendrogram_key


def _plot_dendrogram(
dendro_ax: Axes,
adata: AnnData,
groupby: str,
groupby: str | Sequence[str] | None,
*,
axis_name: Literal["obs", "var"] = "obs",
dendrogram_key: str | None = None,
orientation: Literal["top", "bottom", "left", "right"] = "right",
remove_labels: bool = True,
ticks: Collection[float] | None = None,
):
) -> None:
"""\
Plots a dendrogram on the given ax using the precomputed dendrogram
information stored in `.uns[dendrogram_key]`
"""

dendrogram_key = _get_dendrogram_key(adata, dendrogram_key, groupby)
dendrogram_key = _get_dendrogram_key(
dendrogram_key, groupby, axis_name=axis_name, adata=adata
)

def translate_pos(pos_list, new_ticks, old_ticks):
"""\
Expand Down
8 changes: 5 additions & 3 deletions scanpy/plotting/_baseplot_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ def savefig(self, filename: str, bbox_inches: str | None = "tight", **kwargs):
self.make_figure()
plt.savefig(filename, bbox_inches=bbox_inches, **kwargs)

def _reorder_categories_after_dendrogram(self, dendrogram) -> None:
def _reorder_categories_after_dendrogram(self, dendrogram_key: str | None) -> None:
"""\
Function used by plotting functions that need to reorder the the groupby
observations based on the dendrogram results.
Expand All @@ -883,9 +883,11 @@ def _format_first_three_categories(_categories):
_categories = _categories[:3] + ["etc."]
return ", ".join(_categories)

key = _get_dendrogram_key(self.adata, dendrogram, self.groupby)
dendrogram_key = _get_dendrogram_key(
dendrogram_key, self.groupby, axis_name="obs", adata=self.adata
)

dendro_info = self.adata.uns[key]
dendro_info = self.adata.uns[dendrogram_key]
if self.groupby != dendro_info["groupby"]:
raise ValueError(
"Incompatible observations. The precomputed dendrogram contains "
Expand Down
39 changes: 39 additions & 0 deletions scanpy/tests/test_dendrogram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from __future__ import annotations

import pytest

import scanpy as sc
from scanpy.testing._helpers.data import pbmc68k_reduced

n_neighbors = 5
key = "test"


@pytest.mark.parametrize(
("groupby", "dendrogram_key"),
[
pytest.param(None, "dendrogram_obs", id="obs"),
pytest.param("bulk_labels", "dendrogram_bulk_labels", id="bulk_labels"),
pytest.param(
["bulk_labels", "phase"],
"dendrogram_bulk_labels_phase",
id="bulk_labels+phase",
),
],
)
@pytest.mark.parametrize(
"key_added", [None, "custom_key"], ids=["derived", "custom_key"]
)
def test_dendrogram_key_added(groupby, dendrogram_key, key_added):
adata = pbmc68k_reduced()
sc.tl.dendrogram(adata, groupby=groupby, key_added=key_added, use_rep="X_pca")

if key_added is None:
key_added = dendrogram_key
assert key_added in adata.uns


def test_dendrogram_var_names():
adata = pbmc68k_reduced()
sc.tl.dendrogram(adata, var_names=adata.var_names[:10], axis=1)
assert len(adata.uns["dendrogram_var"]["categories_ordered"]) == 10
24 changes: 0 additions & 24 deletions scanpy/tests/test_dendrogram_key_added.py

This file was deleted.

Loading