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
180 changes: 176 additions & 4 deletions docs/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@
shadedata = np.percentile(data, (25, 75), axis=0) # dark shading

# %%
import ultraplot as uplt
import numpy as np

import ultraplot as uplt

# Loop through "vertical" and "horizontal" versions
varray = [[1], [2], [3]]
harray = [[1, 1], [2, 3], [2, 3]]
Expand Down Expand Up @@ -164,10 +165,11 @@
# with the same keywords used for :ref:`on-the-fly error bars <ug_errorbars>`.

# %%
import ultraplot as uplt
import numpy as np
import pandas as pd

import ultraplot as uplt

# Sample data
N = 500
state = np.random.RandomState(51423)
Expand Down Expand Up @@ -221,9 +223,10 @@
# will use the same algorithm for kernel density estimation as the `kde` commands.

# %%
import ultraplot as uplt
import numpy as np

import ultraplot as uplt

# Sample data
M, N = 300, 3
state = np.random.RandomState(51423)
Expand All @@ -244,9 +247,10 @@
)

# %%
import ultraplot as uplt
import numpy as np

import ultraplot as uplt

# Sample data
N = 500
state = np.random.RandomState(51423)
Expand Down Expand Up @@ -284,3 +288,171 @@
px = ax.panel("t", space=0)
px.hist(x, bins, color=color, fill=True, ec="k")
px.format(grid=False, ylocator=[], title=title, titleloc="l")


# %% [raw] raw_mimetype="text/restructuredtext"
# .. _ug_ridgeline:
#
# Ridgeline plots
# ---------------
#
# Ridgeline plots (also known as joyplots) visualize distributions of multiple
# datasets as stacked, overlapping density curves. They are useful for comparing
# distributions across categories or over time. UltraPlot provides
# :func:`~ultraplot.axes.PlotAxes.ridgeline` and :func:`~ultraplot.axes.PlotAxes.ridgelineh`
# for creating vertical and horizontal ridgeline plots.
#
# Ridgeline plots support two display modes: smooth kernel density estimation (KDE)
# by default, or histograms with the `hist` keyword. They also support two positioning
# modes: categorical positioning with evenly-spaced ridges (traditional joyplots),
# or continuous positioning where ridges are anchored to specific physical coordinates
# (useful for scientific plots like depth profiles or time series).

# %%
import numpy as np

import ultraplot as uplt

# 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)]

# Create figure with two subplots
fig, axs = uplt.subplots(ncols=2, figsize=(10, 5))
axs.format(
abc="A.", abcloc="ul", grid=False, suptitle="Ridgeline plots: KDE vs Histogram"
)

# KDE ridgeline (default)
axs[0].ridgeline(
data, labels=labels, overlap=0.6, cmap="viridis", alpha=0.7, linewidth=1.5
)
axs[0].format(title="Kernel Density Estimation", xlabel="Value")

# Histogram ridgeline
axs[1].ridgeline(
data,
labels=labels,
overlap=0.6,
cmap="plasma",
alpha=0.7,
hist=True,
bins=20,
linewidth=1.5,
)
axs[1].format(title="Histogram", xlabel="Value")

# %%
import numpy as np

import ultraplot as uplt

# Sample data
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)]
labels2 = ["Alpha", "Beta", "Gamma", "Delta"]

# Create figure with vertical and horizontal orientations
fig, axs = uplt.subplots(ncols=2, figsize=(10, 5))
axs.format(abc="A.", abcloc="ul", grid=False, suptitle="Ridgeline plot orientations")

# Vertical ridgeline (default - ridges are horizontal)
axs[0].ridgeline(
data1, labels=labels1, overlap=0.7, cmap="coolwarm", alpha=0.8, linewidth=2
)
axs[0].format(title="Vertical (ridgeline)", xlabel="Value")

# Horizontal ridgeline (ridges are vertical)
axs[1].ridgelineh(
data2, labels=labels2, overlap=0.6, facecolor="skyblue", alpha=0.7, linewidth=1.5
)
axs[1].format(title="Horizontal (ridgelineh)", ylabel="Value")


# %% [raw] raw_mimetype="text/restructuredtext"
# .. _ug_ridgeline_continuous:
#
# Continuous positioning
# ^^^^^^^^^^^^^^^^^^^^^^
#
# For scientific applications, ridgeline plots can use continuous (coordinate-based)
# positioning where each ridge is anchored to a specific numerical coordinate along
# the axis. This is useful for visualizing how distributions change with physical
# variables like depth, time, altitude, or redshift. Use the `positions` parameter
# to specify coordinates, and optionally the `height` parameter to control ridge height
# in axis units.

# %%
import numpy as np

import ultraplot as uplt

# Simulate ocean temperature data at different depths
state = np.random.RandomState(51423)
depths = [0, 10, 25, 50, 100] # meters
mean_temps = [25, 22, 18, 12, 8] # decreasing with depth
data = [state.normal(temp, 2, 400) for temp in mean_temps]
labels = ["Surface", "10m", "25m", "50m", "100m"]

fig, ax = uplt.subplots(figsize=(8, 6))
ax.ridgeline(
data,
labels=labels,
positions=depths,
height=8, # height in axis units
cmap="coolwarm",
alpha=0.75,
linewidth=2,
)
ax.format(
title="Ocean Temperature Distribution by Depth",
xlabel="Temperature (°C)",
ylabel="Depth (m)",
yreverse=True, # depth increases downward
grid=True,
gridcolor="gray5",
gridalpha=0.3,
)

# %%
import numpy as np

import ultraplot as uplt

# Simulate climate data over time
state = np.random.RandomState(51423)
years = [1950, 1970, 1990, 2010, 2030]
mean_temps = [14.0, 14.2, 14.5, 15.0, 15.5] # warming trend
data = [state.normal(temp, 0.8, 500) for temp in mean_temps]

fig, axs = uplt.subplots(ncols=2, figsize=(11, 5))
axs.format(abc="A.", abcloc="ul", suptitle="Categorical vs Continuous positioning")

# Categorical positioning (default)
axs[0].ridgeline(
data, labels=[str(y) for y in years], overlap=0.6, cmap="fire", alpha=0.7
)
axs[0].format(
title="Categorical (traditional joyplot)", xlabel="Temperature (°C)", grid=False
)

# Continuous positioning
axs[1].ridgeline(
data,
labels=[str(y) for y in years],
positions=years,
height=15, # height in year units
cmap="fire",
alpha=0.7,
)
axs[1].format(
title="Continuous (scientific)",
xlabel="Temperature (°C)",
ylabel="Year",
grid=True,
gridcolor="gray5",
gridalpha=0.3,
)
Loading