Source code for Modules.ContourBoxplot.contour_boxplot

import matplotlib.pyplot as plt
import numpy as np
from .contour_boxplot_stats import contour_boxplot_summary_statistics
from .contour_boxplot_mesh import contour_boxplot_mesh
from .contour_boxplot_vis import visualize_contour_boxplot
from uvisbox.Core.CommonInterface import BoxplotStyleConfig


[docs] def contour_boxplot(ensemble_images, isovalue, boxplot_style=None, ax=None, eps=0, workers=11, x_coords=None, y_coords=None): """ Create a contour boxplot visualization from an ensemble of scalar fields. This function processes ensemble images by extracting binary contours at a given isovalue, computing their band depths, and visualizing the uncertainty using band envelopes. Parameters: ----------- ensemble_images : np.ndarray 3D array of shape (n_ensemble, y_dim, x_dim) containing the ensemble scalar fields. isovalue : float Threshold value for creating binary images. Pixels with values < isovalue are set to 1. boxplot_style : BoxplotStyleConfig, optional Configuration for the boxplot visualization including percentiles, and median/outlier styling. If None, uses default configuration. The percentile_colormap is used for the band sum visualization. ax : matplotlib.axes.Axes, optional Matplotlib Axes object to plot on. If None, a new figure and axes will be created. eps : float, optional Epsilon tolerance for subset checks in band depth computation. With eps=0 (default), exact pixel-level containment is required, which can be too strict for continuously-varying rasterized contours. Values like 0.01-0.05 allow approximate containment. workers : int, optional Number of parallel workers for band depth computation. Default is 11. x_coords : np.ndarray, optional 1D array of x-axis coordinates defining the spatial domain. Length must match the image width. If None, pixel indices are used. y_coords : np.ndarray, optional 1D array of y-axis coordinates defining the spatial domain. Length must match the image height. If None, pixel indices are used. Returns: -------- ax : matplotlib.axes.Axes The Axes object with the contour boxplot visualization. Examples: --------- >>> # Basic usage with defaults >>> ensemble = np.random.randn(50, 100, 100) # 50 ensemble members >>> ax = contour_boxplot(ensemble, isovalue=0.5) >>> # Custom styling >>> from uvisbox.Core.CommonInterface import BoxplotStyleConfig >>> style = BoxplotStyleConfig( ... percentiles=[25, 50, 75], ... percentile_colormap='hot', ... show_median=True, ... show_outliers=True ... ) >>> ax = contour_boxplot(ensemble, isovalue=0.5, boxplot_style=style) """ # Use default config if none provided if boxplot_style is None: boxplot_style = BoxplotStyleConfig() # Make a copy and ensure correct shape (n_ensemble, y_dim, x_dim) ensemble_copy = np.array(ensemble_images, copy=True) if ensemble_copy.ndim != 3: raise ValueError(f"ensemble_images must be a 3D array of shape (n_ensemble, y, x). Got {ensemble_copy.ndim}D") # Pipeline: Stats -> Mesh -> Vis # Step 1: Compute summary statistics stats = contour_boxplot_summary_statistics( ensemble_copy, isovalue, boxplot_style=boxplot_style, eps=eps, workers=workers ) # Step 2: Process through mesh (aggregate bands) mesh_data = contour_boxplot_mesh(stats, x_coords=x_coords, y_coords=y_coords) # Step 3: Visualize ax = visualize_contour_boxplot( mesh_data, boxplot_style=boxplot_style, ax=ax ) return ax