Source code for Modules.FunctionalBoxplot.functional_boxplot

import numpy as np
import matplotlib.pyplot as plt
from .functional_boxplot_stats import functional_boxplot_summary_statistics
from .functional_boxplot_mesh import functional_boxplot_mesh
from .functional_boxplot_vis import visualize_functional_boxplot
from uvisbox.Core.CommonInterface import BoxplotStyleConfig


[docs] def functional_boxplot(data, method='fbd', vmin=0, vmax=1, boxplot_style=None, ax=None): """ Create a functional band depth boxplot with multiple percentile bands. This function computes functional band depths, plots bands in descending percentile order (largest to smallest for proper layering), and highlights the median curve. Parameters: ----------- data : np.ndarray 2D array of shape (N, D) where N is the number of curves and D is the number of points per curve. method : str, optional Method for computing band depth. Options are: - 'fbd': functional band depth (default) - 'mfbd': modified functional band depth boxplot_style : BoxplotStyleConfig, optional Configuration for the boxplot visualization including percentiles, colormap, and median/outlier styling. If None, uses default configuration. ax : matplotlib.axes.Axes, optional Matplotlib axes to plot on. If None, creates a new figure. Returns: -------- ax : matplotlib.axes.Axes The matplotlib axes object with the plot. Raises: ------- ValueError If data is not 2D or if method is invalid. Notes: ------ - Input data is not modified (computation happens on a copy) - Bands are plotted from largest to smallest percentile for proper visual layering - The median curve is the curve with the highest band depth value - Outliers are curves beyond the largest percentile - Curve depths are always computed internally Examples: --------- >>> import numpy as np >>> from uvisbox.Modules.FunctionalBoxplot import functional_boxplot >>> from uvisbox.Core.CommonInterface import BoxplotStyleConfig >>> >>> # Generate synthetic functional data >>> t = np.linspace(0, 1, 100) >>> data = np.array([np.sin(2*np.pi*t) + 0.2*np.random.randn(100) for _ in range(50)]) >>> >>> # Basic usage with default settings >>> ax = functional_boxplot(data) >>> >>> # Custom styling >>> style = BoxplotStyleConfig( ... percentiles=[10, 50, 90], ... percentile_colormap='plasma', ... show_median=True, ... show_outliers=True ... ) >>> ax = functional_boxplot(data, boxplot_style=style) >>> >>> # Plot on existing axes >>> import matplotlib.pyplot as plt >>> fig, ax = plt.subplots(figsize=(12, 6)) >>> functional_boxplot(data, ax=ax) >>> plt.show() """ # Use default config if none provided if boxplot_style is None: boxplot_style = BoxplotStyleConfig() # Validate input data if not isinstance(data, np.ndarray): data = np.array(data) if data.ndim != 2: raise ValueError( f"Input data must be a 2D array of shape (N, D). Got {data.ndim}D array.") # Pipeline: Stats -> Mesh -> Vis # Step 1: Compute summary statistics stats = functional_boxplot_summary_statistics( data, method=method, boxplot_style=boxplot_style) # Step 2: Process through mesh (identity function for functional boxplot) mesh_data = functional_boxplot_mesh(stats) # Step 3: Visualize ax = visualize_functional_boxplot( mesh_data, vmin=vmin, vmax=vmax, boxplot_style=boxplot_style, ax=ax) return ax