|
79 | 79 | shadedata = np.percentile(data, (25, 75), axis=0) # dark shading |
80 | 80 |
|
81 | 81 | # %% |
82 | | -import ultraplot as uplt |
83 | 82 | import numpy as np |
84 | 83 |
|
| 84 | +import ultraplot as uplt |
| 85 | + |
85 | 86 | # Loop through "vertical" and "horizontal" versions |
86 | 87 | varray = [[1], [2], [3]] |
87 | 88 | harray = [[1, 1], [2, 3], [2, 3]] |
|
164 | 165 | # with the same keywords used for :ref:`on-the-fly error bars <ug_errorbars>`. |
165 | 166 |
|
166 | 167 | # %% |
167 | | -import ultraplot as uplt |
168 | 168 | import numpy as np |
169 | 169 | import pandas as pd |
170 | 170 |
|
| 171 | +import ultraplot as uplt |
| 172 | + |
171 | 173 | # Sample data |
172 | 174 | N = 500 |
173 | 175 | state = np.random.RandomState(51423) |
|
221 | 223 | # will use the same algorithm for kernel density estimation as the `kde` commands. |
222 | 224 |
|
223 | 225 | # %% |
224 | | -import ultraplot as uplt |
225 | 226 | import numpy as np |
226 | 227 |
|
| 228 | +import ultraplot as uplt |
| 229 | + |
227 | 230 | # Sample data |
228 | 231 | M, N = 300, 3 |
229 | 232 | state = np.random.RandomState(51423) |
|
244 | 247 | ) |
245 | 248 |
|
246 | 249 | # %% |
247 | | -import ultraplot as uplt |
248 | 250 | import numpy as np |
249 | 251 |
|
| 252 | +import ultraplot as uplt |
| 253 | + |
250 | 254 | # Sample data |
251 | 255 | N = 500 |
252 | 256 | state = np.random.RandomState(51423) |
|
284 | 288 | px = ax.panel("t", space=0) |
285 | 289 | px.hist(x, bins, color=color, fill=True, ec="k") |
286 | 290 | px.format(grid=False, ylocator=[], title=title, titleloc="l") |
| 291 | + |
| 292 | + |
| 293 | +# %% [raw] raw_mimetype="text/restructuredtext" |
| 294 | +# .. _ug_ridgeline: |
| 295 | +# |
| 296 | +# Ridgeline plots |
| 297 | +# --------------- |
| 298 | +# |
| 299 | +# Ridgeline plots (also known as joyplots) visualize distributions of multiple |
| 300 | +# datasets as stacked, overlapping density curves. They are useful for comparing |
| 301 | +# distributions across categories or over time. UltraPlot provides |
| 302 | +# :func:`~ultraplot.axes.PlotAxes.ridgeline` and :func:`~ultraplot.axes.PlotAxes.ridgelineh` |
| 303 | +# for creating vertical and horizontal ridgeline plots. |
| 304 | +# |
| 305 | +# Ridgeline plots support two display modes: smooth kernel density estimation (KDE) |
| 306 | +# by default, or histograms with the `hist` keyword. They also support two positioning |
| 307 | +# modes: categorical positioning with evenly-spaced ridges (traditional joyplots), |
| 308 | +# or continuous positioning where ridges are anchored to specific physical coordinates |
| 309 | +# (useful for scientific plots like depth profiles or time series). |
| 310 | + |
| 311 | +# %% |
| 312 | +import numpy as np |
| 313 | + |
| 314 | +import ultraplot as uplt |
| 315 | + |
| 316 | +# Sample data with different distributions |
| 317 | +state = np.random.RandomState(51423) |
| 318 | +data = [state.normal(i, 1, 500) for i in range(5)] |
| 319 | +labels = [f"Distribution {i+1}" for i in range(5)] |
| 320 | + |
| 321 | +# Create figure with two subplots |
| 322 | +fig, axs = uplt.subplots(ncols=2, figsize=(10, 5)) |
| 323 | +axs.format( |
| 324 | + abc="A.", abcloc="ul", grid=False, suptitle="Ridgeline plots: KDE vs Histogram" |
| 325 | +) |
| 326 | + |
| 327 | +# KDE ridgeline (default) |
| 328 | +axs[0].ridgeline( |
| 329 | + data, labels=labels, overlap=0.6, cmap="viridis", alpha=0.7, linewidth=1.5 |
| 330 | +) |
| 331 | +axs[0].format(title="Kernel Density Estimation", xlabel="Value") |
| 332 | + |
| 333 | +# Histogram ridgeline |
| 334 | +axs[1].ridgeline( |
| 335 | + data, |
| 336 | + labels=labels, |
| 337 | + overlap=0.6, |
| 338 | + cmap="plasma", |
| 339 | + alpha=0.7, |
| 340 | + hist=True, |
| 341 | + bins=20, |
| 342 | + linewidth=1.5, |
| 343 | +) |
| 344 | +axs[1].format(title="Histogram", xlabel="Value") |
| 345 | + |
| 346 | +# %% |
| 347 | +import numpy as np |
| 348 | + |
| 349 | +import ultraplot as uplt |
| 350 | + |
| 351 | +# Sample data |
| 352 | +state = np.random.RandomState(51423) |
| 353 | +data1 = [state.normal(i * 0.5, 1, 400) for i in range(6)] |
| 354 | +data2 = [state.normal(i, 0.8, 400) for i in range(4)] |
| 355 | +labels1 = [f"Group {i+1}" for i in range(6)] |
| 356 | +labels2 = ["Alpha", "Beta", "Gamma", "Delta"] |
| 357 | + |
| 358 | +# Create figure with vertical and horizontal orientations |
| 359 | +fig, axs = uplt.subplots(ncols=2, figsize=(10, 5)) |
| 360 | +axs.format(abc="A.", abcloc="ul", grid=False, suptitle="Ridgeline plot orientations") |
| 361 | + |
| 362 | +# Vertical ridgeline (default - ridges are horizontal) |
| 363 | +axs[0].ridgeline( |
| 364 | + data1, labels=labels1, overlap=0.7, cmap="coolwarm", alpha=0.8, linewidth=2 |
| 365 | +) |
| 366 | +axs[0].format(title="Vertical (ridgeline)", xlabel="Value") |
| 367 | + |
| 368 | +# Horizontal ridgeline (ridges are vertical) |
| 369 | +axs[1].ridgelineh( |
| 370 | + data2, labels=labels2, overlap=0.6, facecolor="skyblue", alpha=0.7, linewidth=1.5 |
| 371 | +) |
| 372 | +axs[1].format(title="Horizontal (ridgelineh)", ylabel="Value") |
| 373 | + |
| 374 | + |
| 375 | +# %% [raw] raw_mimetype="text/restructuredtext" |
| 376 | +# .. _ug_ridgeline_continuous: |
| 377 | +# |
| 378 | +# Continuous positioning |
| 379 | +# ^^^^^^^^^^^^^^^^^^^^^^ |
| 380 | +# |
| 381 | +# For scientific applications, ridgeline plots can use continuous (coordinate-based) |
| 382 | +# positioning where each ridge is anchored to a specific numerical coordinate along |
| 383 | +# the axis. This is useful for visualizing how distributions change with physical |
| 384 | +# variables like depth, time, altitude, or redshift. Use the `positions` parameter |
| 385 | +# to specify coordinates, and optionally the `height` parameter to control ridge height |
| 386 | +# in axis units. |
| 387 | + |
| 388 | +# %% |
| 389 | +import numpy as np |
| 390 | + |
| 391 | +import ultraplot as uplt |
| 392 | + |
| 393 | +# Simulate ocean temperature data at different depths |
| 394 | +state = np.random.RandomState(51423) |
| 395 | +depths = [0, 10, 25, 50, 100] # meters |
| 396 | +mean_temps = [25, 22, 18, 12, 8] # decreasing with depth |
| 397 | +data = [state.normal(temp, 2, 400) for temp in mean_temps] |
| 398 | +labels = ["Surface", "10m", "25m", "50m", "100m"] |
| 399 | + |
| 400 | +fig, ax = uplt.subplots(figsize=(8, 6)) |
| 401 | +ax.ridgeline( |
| 402 | + data, |
| 403 | + labels=labels, |
| 404 | + positions=depths, |
| 405 | + height=8, # height in axis units |
| 406 | + cmap="coolwarm", |
| 407 | + alpha=0.75, |
| 408 | + linewidth=2, |
| 409 | +) |
| 410 | +ax.format( |
| 411 | + title="Ocean Temperature Distribution by Depth", |
| 412 | + xlabel="Temperature (°C)", |
| 413 | + ylabel="Depth (m)", |
| 414 | + yreverse=True, # depth increases downward |
| 415 | + grid=True, |
| 416 | + gridcolor="gray5", |
| 417 | + gridalpha=0.3, |
| 418 | +) |
| 419 | + |
| 420 | +# %% |
| 421 | +import numpy as np |
| 422 | + |
| 423 | +import ultraplot as uplt |
| 424 | + |
| 425 | +# Simulate climate data over time |
| 426 | +state = np.random.RandomState(51423) |
| 427 | +years = [1950, 1970, 1990, 2010, 2030] |
| 428 | +mean_temps = [14.0, 14.2, 14.5, 15.0, 15.5] # warming trend |
| 429 | +data = [state.normal(temp, 0.8, 500) for temp in mean_temps] |
| 430 | + |
| 431 | +fig, axs = uplt.subplots(ncols=2, figsize=(11, 5)) |
| 432 | +axs.format(abc="A.", abcloc="ul", suptitle="Categorical vs Continuous positioning") |
| 433 | + |
| 434 | +# Categorical positioning (default) |
| 435 | +axs[0].ridgeline( |
| 436 | + data, labels=[str(y) for y in years], overlap=0.6, cmap="fire", alpha=0.7 |
| 437 | +) |
| 438 | +axs[0].format( |
| 439 | + title="Categorical (traditional joyplot)", xlabel="Temperature (°C)", grid=False |
| 440 | +) |
| 441 | + |
| 442 | +# Continuous positioning |
| 443 | +axs[1].ridgeline( |
| 444 | + data, |
| 445 | + labels=[str(y) for y in years], |
| 446 | + positions=years, |
| 447 | + height=15, # height in year units |
| 448 | + cmap="fire", |
| 449 | + alpha=0.7, |
| 450 | +) |
| 451 | +axs[1].format( |
| 452 | + title="Continuous (scientific)", |
| 453 | + xlabel="Temperature (°C)", |
| 454 | + ylabel="Year", |
| 455 | + grid=True, |
| 456 | + gridcolor="gray5", |
| 457 | + gridalpha=0.3, |
| 458 | +) |
0 commit comments