Source code for adctoolbox.aout.plot_rearranged_error_by_value

"""Visualization for value-binned error analysis."""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpecFromSubplotSpec

[docs] def plot_rearranged_error_by_value(results: dict, axes=None, ax=None, title: str = None): """ Plot Mean Error (INL) and RMS Error (Noise) vs Bin Index. Creates a comprehensive visualization showing: - Top panel: Scatter of raw error vs bin index with mean error overlay - Bottom panel: RMS error vs bin index as bar chart Parameters ---------- results : dict Dictionary from rearrange_error_by_value(). axes : tuple or array, optional Tuple of (ax1, ax2) for top and bottom panels. ax : matplotlib.axes.Axes, optional Single axis to split into 2 panels. title : str, optional Test setup description for title. """ # --- 1. Extract Data (Using new simplified keys) --- error = results.get('error', np.array([])) bin_indices = results.get('bin_indices', np.array([])) error_mean = results['error_mean'] error_rms = results['error_rms'] bin_centers = results['bin_centers'] n_bins = results['n_bins'] if len(bin_indices) == 0: return # --- 2. Axes Management --- if axes is not None: # Support both tuple (ax1, ax2) and numpy array [ax1, ax2] # This makes it compatible with axes = plt.subplots(2, 1)[1] ax1, ax2 = axes if isinstance(axes, (tuple, list)) else axes.flatten() else: # Single axis (or None), get current axis and split it if ax is None: ax = plt.gca() # Split single axis into 2 rows fig = ax.get_figure() if hasattr(ax, 'get_subplotspec') and ax.get_subplotspec(): gs = GridSpecFromSubplotSpec(2, 1, subplot_spec=ax.get_subplotspec(), hspace=0.35) ax.remove() # Remove original placeholder axis ax1 = fig.add_subplot(gs[0]) ax2 = fig.add_subplot(gs[1]) else: # Fallback for manual positioning pos = ax.get_position() ax.remove() ax1 = fig.add_axes([pos.x0, pos.y0 + pos.height/2, pos.width, pos.height/2]) ax2 = fig.add_axes([pos.x0, pos.y0, pos.width, pos.height/2]) # ====================================================================== # Top Panel: Scatter of error vs bin index with mean error overlay # ====================================================================== if len(error) > 0: # Scatter plot: High transparency, rasterized for performance on large datasets ax1.scatter(bin_indices, error, alpha=0.2, s=1, color='red', rasterized=True, label='Raw Error') # Mean error line overlay (INL Profile) ax1.plot(bin_centers, error_mean, 'b-', linewidth=1.5, label='Mean Error (INL)') # Set axis limits ax1.set_xlim([-0.5, n_bins - 0.5]) # Smart Y-limits y_min, y_max = np.min(error), np.max(error) y_range = y_max - y_min margin = y_range * 0.1 if y_range != 0 else 1.0 ax1.set_ylim([y_min - margin, y_max + margin]) ax1.set_ylabel('Error') if title: ax1.set_title(title) else: ax1.set_title('Signal and Error vs Value') ax1.grid(True, alpha=0.3) ax1.legend(loc='upper right', fontsize=8) # Hide x-labels for top plot to avoid clutter ax1.set_xticklabels([]) # ====================================================================== # Bottom Panel: RMS Error Bar Chart (Noise Profile) # ====================================================================== if len(bin_centers) > 0: # Bar chart ax2.bar(bin_centers, error_rms, width=0.9, color='skyblue', alpha=0.8, edgecolor='darkblue', linewidth=0.3) # Set axis limits ax2.set_xlim([-0.5, n_bins - 0.5]) ax2.set_ylim([0, np.nanmax(error_rms) * 1.15]) ax2.set_xlabel('Bin Index') ax2.set_ylabel('RMS Error') ax2.set_title('RMS Error vs Value') ax2.grid(True, alpha=0.3, axis='y') # Tight layout if we created the figure structure ourselves if ax is None: plt.tight_layout()