Skip to content

Commit

Permalink
Fix some plot warnings (scverse#2844)
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep authored Feb 9, 2024
1 parent dd6cf81 commit e78f4a3
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 83 deletions.
1 change: 1 addition & 0 deletions docs/release-notes/1.10.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* Fix testing package build {pr}`2468` {smaller}`P Angerer`
* Fix setting `sc.settings.verbosity` in some cases {pr}`2605` {smaller}`P Angerer`
* Fix all remaining pandas warnings {pr}`2789` {smaller}`P Angerer`
* Fix some annoying plotting warnings around violin plots {pr}`2844` {smaller}`P Angerer`

```{rubric} Ecosystem
```
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ filterwarnings = [
"error:The provided callable.* is currently using:FutureWarning",
"error:The behavior of DataFrame concatenation with empty or all-NA entries is deprecated:FutureWarning",
"error:A value is trying to be set on a copy of a slice from a DataFrame",
"error:No data for colormapping provided via 'c'",
"error:\\n*The `scale` parameter has been renamed and will be removed",
"error:\\n*Passing `palette` without assigning `hue` is deprecated",
"error:\\n*Setting a gradient palette using color= is deprecated",
]

[tool.coverage.run]
Expand Down
3 changes: 2 additions & 1 deletion scanpy/plotting/_anndata.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ def violin(
f"but is of dtype {adata.obs[groupby].dtype}."
)
_utils.add_colors_for_categorical_sample_annotation(adata, groupby)
kwds["hue"] = groupby
kwds["palette"] = dict(
zip(obs_df[groupby].cat.categories, adata.uns[f"{groupby}_colors"])
)
Expand Down Expand Up @@ -909,7 +910,7 @@ def violin(
data=obs_tidy,
order=order,
orient="vertical",
scale=scale,
density_norm=scale,
ax=ax,
**kwds,
)
Expand Down
14 changes: 3 additions & 11 deletions scanpy/plotting/_dotplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,7 @@ def _mainplot(self, ax):
if self.are_axes_swapped:
_size_df = _size_df.T
_color_df = _color_df.T
self.cmap = self.kwds.get("cmap", self.cmap)
if "cmap" in self.kwds:
del self.kwds["cmap"]
self.cmap = self.kwds.pop("cmap", self.cmap)

normalize, dot_min, dot_max = self._dotplot(
_size_df,
Expand Down Expand Up @@ -627,7 +625,7 @@ def _dotplot(
y_label: str | None = None,
dot_max: float | None = None,
dot_min: float | None = None,
standard_scale: Literal["var", "group"] = None,
standard_scale: Literal["var", "group"] | None = None,
smallest_dot: float | None = 0.0,
largest_dot: float | None = 200,
size_exponent: float | None = 2,
Expand Down Expand Up @@ -737,9 +735,7 @@ def _dotplot(
x = x.flatten() + 0.5
frac = dot_size.values.flatten()
mean_flat = dot_color.values.flatten()
cmap = plt.get_cmap(kwds.get("cmap", cmap))
if "cmap" in kwds:
del kwds["cmap"]
cmap = plt.get_cmap(cmap)
if dot_max is None:
dot_max = np.ceil(max(frac) * 10) / 10
else:
Expand Down Expand Up @@ -786,11 +782,9 @@ def _dotplot(
kwds = fix_kwds(
kwds,
s=size,
cmap=cmap,
linewidth=edge_lw,
facecolor="none",
edgecolor=edge_color,
norm=normalize,
)
dot_ax.scatter(x, y, **kwds)
else:
Expand All @@ -801,11 +795,9 @@ def _dotplot(
kwds = fix_kwds(
kwds,
s=size,
cmap=cmap,
color=color,
linewidth=edge_lw,
edgecolor=edge_color,
norm=normalize,
)

dot_ax.scatter(x, y, **kwds)
Expand Down
67 changes: 46 additions & 21 deletions scanpy/plotting/_stacked_violin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING, Literal

import numpy as np
Expand All @@ -13,7 +14,13 @@
from .._utils import _doc_params
from ._baseplot_class import BasePlot, _VarNames, doc_common_groupby_plot_args
from ._docs import doc_common_plot_args, doc_show_save_ax, doc_vboundnorm
from ._utils import _AxesSubplot, check_colornorm, make_grid_spec, savefig_or_show
from ._utils import (
_AxesSubplot,
_deprecated_scale,
check_colornorm,
make_grid_spec,
savefig_or_show,
)

if TYPE_CHECKING:
from collections.abc import (
Expand Down Expand Up @@ -52,7 +59,7 @@ class StackedViolin(BasePlot):
Order in which to show the categories. Note: if `dendrogram=True`
the categories order will be given by the dendrogram and `order`
will be ignored.
scale
density_norm
The method used to scale the width of each violin.
If 'width' (the default), each violin will have the same width.
If 'area', each violin will have the same area.
Expand Down Expand Up @@ -108,7 +115,7 @@ class StackedViolin(BasePlot):
DEFAULT_JITTER_SIZE = 1
DEFAULT_LINE_WIDTH = 0.2
DEFAULT_ROW_PALETTE = None
DEFAULT_SCALE = "width"
DEFAULT_DENSITY_NORM: Literal["area", "count", "width"] = "width"
DEFAULT_PLOT_YTICKLABELS = False
DEFAULT_YLIM = None
DEFAULT_PLOT_X_PADDING = 0.5 # a unit is the distance between two x-axis ticks
Expand All @@ -131,6 +138,18 @@ class StackedViolin(BasePlot):
# None will draw unadorned violins.
DEFAULT_INNER = None

def __getattribute__(self, name: str) -> object:
"""Called unconditionally when accessing an instance attribute"""
# If the user has set the deprecated version on the class,
# and our code accesses the new version from the instance,
# return the user-specified version instead and warn.
# This is done because class properties are hard to do.
if name == "DEFAULT_DENSITY_NORM" and hasattr(self, "DEFAULT_SCALE"):
msg = "Don’t set DEFAULT_SCALE, use DEFAULT_DENSITY_NORM instead"
warnings.warn(msg, FutureWarning)
return object.__getattribute__(self, "DEFAULT_SCALE")
return object.__getattribute__(self, name)

@old_positionals(
"use_raw",
"log",
Expand Down Expand Up @@ -224,7 +243,7 @@ def __init__(
self.kwds.setdefault("cut", self.DEFAULT_CUT)
self.kwds.setdefault("inner", self.DEFAULT_INNER)
self.kwds.setdefault("linewidth", self.DEFAULT_LINE_WIDTH)
self.kwds.setdefault("scale", self.DEFAULT_SCALE)
self.kwds.setdefault("density_norm", self.DEFAULT_DENSITY_NORM)

@old_positionals(
"cmap",
Expand All @@ -233,7 +252,7 @@ def __init__(
"jitter_size",
"linewidth",
"row_palette",
"scale",
"density_norm",
"yticklabels",
"ylim",
"x_padding",
Expand All @@ -248,11 +267,13 @@ def style(
jitter_size: int | None = DEFAULT_JITTER_SIZE,
linewidth: float | None = DEFAULT_LINE_WIDTH,
row_palette: str | None = DEFAULT_ROW_PALETTE,
scale: Literal["area", "count", "width"] | None = DEFAULT_SCALE,
density_norm: Literal["area", "count", "width"] = DEFAULT_DENSITY_NORM,
yticklabels: bool | None = DEFAULT_PLOT_YTICKLABELS,
ylim: tuple[float, float] | None = DEFAULT_YLIM,
x_padding: float | None = DEFAULT_PLOT_X_PADDING,
y_padding: float | None = DEFAULT_PLOT_Y_PADDING,
# deprecated
scale: Literal["area", "count", "width"] | None = None,
):
r"""\
Modifies plot visual parameters
Expand All @@ -277,7 +298,7 @@ def style(
(see :func:`~seaborn.color_palette`).
Alternatively, a single color name or hex value can be passed,
e.g. `'red'` or `'#cc33ff'`.
scale
density_norm
The method used to scale the width of each violin.
If 'width' (the default), each violin will have the same width.
If 'area', each violin will have the same area.
Expand Down Expand Up @@ -338,8 +359,14 @@ def style(
self.plot_y_padding = y_padding
if linewidth != self.kwds["linewidth"] and linewidth != self.DEFAULT_LINE_WIDTH:
self.kwds["linewidth"] = linewidth
if scale != self.kwds["scale"] and scale != self.DEFAULT_SCALE:
self.kwds["scale"] = scale
density_norm = _deprecated_scale(
density_norm, scale, default=self.DEFAULT_DENSITY_NORM
)
if (
density_norm != self.kwds["density_norm"]
and density_norm != self.DEFAULT_DENSITY_NORM
):
self.kwds["density_norm"] = density_norm

return self

Expand Down Expand Up @@ -367,9 +394,7 @@ def _mainplot(self, ax):
if self.are_axes_swapped:
_color_df = _color_df.T

cmap = plt.get_cmap(self.kwds.get("cmap", self.cmap))
if "cmap" in self.kwds:
del self.kwds["cmap"]
cmap = plt.get_cmap(self.kwds.pop("cmap", self.cmap))
normalize = check_colornorm(
self.vboundnorm.vmin,
self.vboundnorm.vmax,
Expand Down Expand Up @@ -418,9 +443,7 @@ def _make_rows_of_violinplots(
):
import seaborn as sns # Slow import, only import if called

row_palette = self.kwds.get("color", self.row_palette)
if "color" in self.kwds:
del self.kwds["color"]
row_palette = self.kwds.pop("color", self.row_palette)
if row_palette is not None:
if is_color_like(row_palette):
row_colors = [row_palette] * _color_df.shape[0]
Expand Down Expand Up @@ -484,10 +507,9 @@ def _make_rows_of_violinplots(
row_ax = fig.add_subplot(gs[idx + 1, 1:-1])
axs_list.append(row_ax)

if row_colors[idx] is None:
palette_colors = colormap_array[idx, :]
else:
palette_colors = None
palette_colors = (
list(colormap_array[idx, :]) if row_colors[idx] is None else None
)

if not self.are_axes_swapped:
x = "genes"
Expand All @@ -506,6 +528,9 @@ def _make_rows_of_violinplots(
data=_df,
orient="vertical",
ax=row_ax,
# use a single `color`` if row_colors[idx] is defined
# else use the palette
hue=None if palette_colors is None else x,
palette=palette_colors,
color=row_colors[idx],
**self.kwds,
Expand Down Expand Up @@ -630,7 +655,7 @@ def stacked_violin(
stripplot: bool = StackedViolin.DEFAULT_STRIPPLOT,
jitter: float | bool = StackedViolin.DEFAULT_JITTER,
size: int = StackedViolin.DEFAULT_JITTER_SIZE,
scale: Literal["area", "count", "width"] = StackedViolin.DEFAULT_SCALE,
scale: Literal["area", "count", "width"] = StackedViolin.DEFAULT_DENSITY_NORM,
yticklabels: bool | None = StackedViolin.DEFAULT_PLOT_YTICKLABELS,
order: Sequence[str] | None = None,
swap_axes: bool = False,
Expand Down Expand Up @@ -779,7 +804,7 @@ def stacked_violin(
jitter=jitter,
jitter_size=size,
row_palette=row_palette,
scale=kwds.get("scale", scale),
density_norm=kwds.get("density_norm", scale),
yticklabels=yticklabels,
linewidth=kwds.get("linewidth", StackedViolin.DEFAULT_LINE_WIDTH),
).legend(title=colorbar_title)
Expand Down
15 changes: 10 additions & 5 deletions scanpy/plotting/_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
doc_vbound_percentile,
)
from .._utils import (
_deprecated_scale,
savefig_or_show,
timeseries,
timeseries_as_heatmap,
Expand Down Expand Up @@ -1176,7 +1177,7 @@ def rank_genes_groups_matrixplot(
"use_raw",
"key",
"split",
"scale",
"density_norm",
"strip",
"jitter",
"size",
Expand All @@ -1195,13 +1196,15 @@ def rank_genes_groups_violin(
use_raw: bool | None = None,
key: str | None = None,
split: bool = True,
scale: str = "width",
density_norm: Literal["area", "count", "width"] = "width",
strip: bool = True,
jitter: int | float | bool = True,
size: int = 1,
ax: Axes | None = None,
show: bool | None = None,
save: bool | None = None,
# deprecated
scale: Literal["area", "count", "width"] | None = None,
):
"""\
Plot ranking of genes for all tested comparisons.
Expand All @@ -1225,7 +1228,7 @@ def rank_genes_groups_violin(
was used in :func:`~scanpy.tl.rank_genes_groups`.
split
Whether to split the violins or not.
scale
density_norm
See :func:`~seaborn.violinplot`.
strip
Show a strip plot on top of the violin plot.
Expand All @@ -1244,6 +1247,8 @@ def rank_genes_groups_violin(
groups_names = adata.uns[key]["names"].dtype.names if groups is None else groups
if isinstance(groups_names, str):
groups_names = [groups_names]
density_norm = _deprecated_scale(density_norm, scale, default="width")
del scale
axs = []
for group_name in groups_names:
if gene_names is None:
Expand Down Expand Up @@ -1274,7 +1279,7 @@ def rank_genes_groups_violin(
hue_order=hue_order,
hue="hue",
split=split,
scale=scale,
density_norm=density_norm,
orient="vertical",
ax=ax,
)
Expand All @@ -1287,7 +1292,7 @@ def rank_genes_groups_violin(
dodge=True,
hue_order=hue_order,
jitter=jitter,
color="black",
palette="dark:black",
size=size,
ax=_ax,
)
Expand Down
Loading

0 comments on commit e78f4a3

Please sign in to comment.