Commit 1c0a42e
authored
Add ridgeline plot feature (#451)
* Add ridgeline plot feature with histogram support
Implements ridgeline plots (also known as joyplots) for visualizing
distributions of multiple datasets as stacked, overlapping density curves.
Features:
- Support for both vertical (traditional) and horizontal orientations
- Kernel density estimation (KDE) for smooth curves
- Histogram mode for binned bar charts (hist=True)
- Customizable overlap between ridges
- Color specification via colormap or custom colors
- Integration with UltraPlot's color cycle
- Transparent error handling for invalid distributions
- Follows UltraPlot's docstring snippet manager pattern
Methods added:
- ridgeline(): Create vertical ridgeline plots
- ridgelineh(): Create horizontal ridgeline plots
- _apply_ridgeline(): Internal implementation
Tests added:
- test_ridgeline_basic: Basic KDE functionality
- test_ridgeline_colormap: Colormap support
- test_ridgeline_horizontal: Horizontal orientation
- test_ridgeline_custom_colors: Custom color specification
- test_ridgeline_histogram: Histogram mode
- test_ridgeline_histogram_colormap: Histogram with colormap
- test_ridgeline_comparison_kde_vs_hist: KDE vs histogram comparison
- test_ridgeline_empty_data: Error handling for empty data
- test_ridgeline_label_mismatch: Error handling for label mismatch
Docstrings registered with snippet manager following UltraPlot conventions.
* Fix ridgeline plot outline to exclude baseline
The ridge outlines now only trace the top curve of each distribution,
not the baseline. This is achieved by:
- Using fill_between/fill_betweenx with edgecolor='none'
- Drawing a separate plot() line on top for the outline
- Proper z-ordering to ensure outline appears above fill
This creates cleaner ridgeline plots where the baseline doesn't have
a visible edge line connecting the endpoints.
* Improve z-ordering for ridgeline plots
Implements explicit z-ordering to ensure proper layering:
- Each ridge i gets: fill at base+i*2, outline at base+i*2+1
- Later ridges appear on top of earlier ridges
- Outline always appears on top of its corresponding fill
- Base zorder defaults to 2 (above grid/axes elements)
- User can override base zorder via zorder parameter
This ensures clean visual layering even with high overlap values
and when other plot elements are present (e.g., grids).
* Fix z-ordering: lower ridges now correctly appear in front
Reversed the z-order assignment so that visually lower ridges
(smaller index, closer to viewer) have higher z-order values.
Z-order formula: fill_zorder = base + (n_ridges - i - 1) * 2
This ensures proper visual layering where:
- Ridge 0 (bottom, front) has highest z-order
- Ridge n-1 (top, back) has lowest z-order
This prevents ridges from incorrectly popping in front of others
when overlap is high, maintaining the correct visual depth.
* Add kde_kw parameter for flexible KDE control
Replaced explicit bandwidth/weights parameters with a more flexible
kde_kw dictionary that passes all kwargs to scipy.stats.gaussian_kde.
Features:
- kde_kw: dict parameter for passing any KDE arguments (bw_method, weights, etc.)
- points: int parameter to control number of evaluation points (default 200)
- More maintainable and extensible than exposing individual parameters
- Follows UltraPlot's convention of using *_kw parameters
Example usage:
- Custom bandwidth: kde_kw={'bw_method': 0.5}
- With weights: kde_kw={'weights': weight_array}
- Silverman method: kde_kw={'bw_method': 'silverman'}
- Smoother curves: points=500
Tests added:
- test_ridgeline_kde_kw: Tests various kde_kw configurations
- test_ridgeline_points: Tests points parameter
* Add continuous coordinate-based positioning for scientific ridgeline plots
Implements two distinct positioning modes for ridgeline plots:
1. Categorical Positioning (default): Evenly-spaced ridges with discrete labels
- Uses overlap parameter to control spacing
- Traditional 'joyplot' aesthetic
2. Continuous Positioning: Ridges anchored to specific Y-coordinates
- Enabled by providing 'positions' parameter
- 'height' parameter controls ridge height in Y-axis units
- Essential for scientific plots where Y-axis represents physical variables
- Supports: time series, depth profiles, redshift distributions, etc.
Parameters:
- positions: Array of Y-coordinates for each ridge
- height: Ridge height in Y-axis units (auto-determined if not provided)
Scientific use cases:
- Ocean temperature profiles vs depth
- Galaxy distributions vs redshift
- Climate data over time
- Atmospheric profiles vs altitude
- Any data where the vertical axis has physical meaning
Tests added:
- test_ridgeline_continuous_positioning: Visual test of continuous mode
- test_ridgeline_continuous_vs_categorical: Side-by-side comparison
- test_ridgeline_continuous_errors: Error handling validation
- test_ridgeline_continuous_auto_height: Auto height calculation
* Add user guide documentation for ridgeline plots and fix deprecated API
- Add comprehensive ridgeline plot examples to docs/stats.py
- Include examples for KDE vs histogram modes
- Demonstrate categorical vs continuous positioning for scientific use cases
- Replace deprecated mcm.get_cmap() with constructor.Colormap()
- All 15 ridgeline tests still passing1 parent d7ec9ea commit 1c0a42e
3 files changed
Lines changed: 977 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
83 | 82 | | |
84 | 83 | | |
| 84 | + | |
| 85 | + | |
85 | 86 | | |
86 | 87 | | |
87 | 88 | | |
| |||
164 | 165 | | |
165 | 166 | | |
166 | 167 | | |
167 | | - | |
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
| 171 | + | |
| 172 | + | |
171 | 173 | | |
172 | 174 | | |
173 | 175 | | |
| |||
221 | 223 | | |
222 | 224 | | |
223 | 225 | | |
224 | | - | |
225 | 226 | | |
226 | 227 | | |
| 228 | + | |
| 229 | + | |
227 | 230 | | |
228 | 231 | | |
229 | 232 | | |
| |||
244 | 247 | | |
245 | 248 | | |
246 | 249 | | |
247 | | - | |
248 | 250 | | |
249 | 251 | | |
| 252 | + | |
| 253 | + | |
250 | 254 | | |
251 | 255 | | |
252 | 256 | | |
| |||
284 | 288 | | |
285 | 289 | | |
286 | 290 | | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
0 commit comments