Skip to content
Merged
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
Binary file added docs/_static/plot_types/raincloud.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions docs/examples/plot_types/13_raincloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
Raincloud plots
===============

These synthetic samples have exactly the same sample mean and standard
deviation, but different shapes. Half violins reveal the shapes, points show
the observations, and boxes show the median and interquartile range.
"""

import numpy as np

import ultraplot as uplt

# Fixed seeds make both the observations and the point positions reproducible.
rng = np.random.default_rng(42)
data = np.column_stack(
[
rng.normal(size=100),
rng.lognormal(mean=0, sigma=0.65, size=100),
np.r_[rng.normal(-1.2, 0.3, 50), rng.normal(1.2, 0.3, 50)],
]
)
data = (data - data.mean(axis=0)) / data.std(axis=0, ddof=1)
labels = ["Normal", "Right-skewed", "Bimodal"]
colors = ["#4477AA", "#228833", "#AA3377"]
limits = (np.floor(data.min()), np.ceil(data.max()))

fig, axs = uplt.subplots(ncols=2, refwidth=3.8, refaspect=1.1, share=False)

artists = axs[0].raincloud(
data,
labels=labels,
orientation="horizontal",
cycle=colors,
seed=7,
)
axs[0].format(
title="Horizontal raincloud",
xlabel="Standardised value",
yreverse=True,
xlim=limits,
grid=False,
)

axs[1].raincloud(data, labels=labels, cycle=colors, side="low", seed=7)
axs[1].format(
title="Vertical raincloud · cloud on low side",
ylabel="Standardised value",
ylim=limits,
grid=False,
)
axs.format(suptitle="Same mean and standard deviation, different distributions")
fig.show()
8 changes: 8 additions & 0 deletions docs/plot_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ The shape and spread of a sample.

:meth:`~ultraplot.axes.PlotAxes.ridgeline`

.. grid-item-card::
:img-top: _static/plot_types/raincloud.png
:text-align: center

:meth:`~ultraplot.axes.PlotAxes.raincloud`

:doc:`example </gallery/plot_types/13_raincloud>`

.. grid-item-card::
:img-top: _static/plot_types/errorbars.png
:text-align: center
Expand Down
26 changes: 24 additions & 2 deletions docs/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,28 @@


# %% [raw] raw_mimetype="text/restructuredtext"
# Raincloud plots
# ---------------
# :meth:`~ultraplot.axes.PlotAxes.raincloud` combines a half violin (the cloud), jittered
# observations (the rain), and a narrow boxplot. Columns of arrays and DataFrames represent
# distributions; a list of vectors also supports unequal sample sizes. Colours
# and positions are coordinated across components. Use ``orientation='horizontal'``
# to put values on the x axis, and ``cloud=False``, ``rain=False``, or ``box=False``
# to disable individual components. ``seed`` makes the jitter reproducible.
# Use ``legend='r'`` for a group legend, and ``data=table`` to look up a named
# input, e.g. ``ax.raincloud('samples', data={'samples': samples})``. Automatic
# pandas/xarray labels respect :rc:`autoformat`; explicit ``labels`` override them.
# Component dictionaries accept artist aliases and native options, e.g.
# ``rain_kw={'ms': 20, 'lw': 0.5}`` and
# ``box_kw={'medianprops': {'color': 'black', 'lw': 2}}``.
# Layout, visibility, jitter seed, and component appearance defaults live under
# ``raincloud.*`` rc settings. For example,
# ``uplt.rc['raincloud.rain.markersize'] = 20`` changes observation marker areas
# globally, or use ``uplt.rc.context`` to change defaults temporarily. Explicit
# arguments and component dictionary entries override the rc defaults.
# The boxplot describes sample spread, not uncertainty in an estimated mean.
# See the :ref:`sphx_glr_gallery_plot_types_13_raincloud.py` gallery example.
#
# .. _ug_ridgeline:
#
# Ridgeline plots
Expand All @@ -325,7 +347,7 @@
# Sample data with different distributions
state = np.random.RandomState(51423)
data = [state.normal(i, 1, 500) for i in range(5)]
labels = [f"Distribution {i+1}" for i in range(5)]
labels = [f"Distribution {i + 1}" for i in range(5)]

# Create figure with two subplots
fig, axs = uplt.subplots(ncols=2, figsize=(10, 5))
Expand Down Expand Up @@ -361,7 +383,7 @@
state = np.random.RandomState(51423)
data1 = [state.normal(i * 0.5, 1, 400) for i in range(6)]
data2 = [state.normal(i, 0.8, 400) for i in range(4)]
labels1 = [f"Group {i+1}" for i in range(6)]
labels1 = [f"Group {i + 1}" for i in range(6)]
labels2 = ["Alpha", "Beta", "Gamma", "Delta"]

# Create figure with vertical and horizontal orientations
Expand Down
21 changes: 20 additions & 1 deletion tools/cheatsheet/parts/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,18 @@ def icon_ridgeline(ax):
ax.ridgeline(data, overlap=0.6, cmap=ICON_SEQUENTIAL, lw=0.7)


def icon_raincloud(ax: uplt.PlotAxes) -> None:
data = np.random.default_rng(42).normal(size=(45, 3)) + [0, 0.7, -0.5]
ax.raincloud(
data,
orientation="horizontal",
color=ICON_LINE,
rain_kw={"ms": 3},
cloud_kw={"lw": 0.5},
box_kw={"lw": 0.7},
)


def icon_errorbars(ax):
ax.plot(
WAVE_X,
Expand Down Expand Up @@ -349,7 +361,7 @@ def icon_curved_quiver(ax):
linewidth=1.4,
arrowsize=1.2,
arrow_at_end=True,
scale = 3,
scale=3,
)


Expand Down Expand Up @@ -587,6 +599,13 @@ def icon_map_track(ax):
"violin": (icon_violin, None, SAME, None, "distribution"),
"beeswarm": (icon_beeswarm, None, NEW, None, "distribution"),
"ridgeline": (icon_ridgeline, None, NEW, None, "distribution"),
"raincloud": (
icon_raincloud,
None,
BETTER,
"violinplot + scatter + boxplot",
"distribution",
),
"errorbars": (
icon_errorbars,
None,
Expand Down
Loading
Loading