Fix: harmonise visualize style -- axes, returns, attributes#1709
Conversation
- Add pypesto/visualize/_style.py with shared helpers get_ax and process_deprecated_kwarg. The latter is the canonical pattern for the visualization signature harmonization that follows. - Drop the module-level cmap global in sampling.py; inline at the single use site. - Rename par_indices → parameter_indices in sampling_parameter_traces, sampling_1d_marginals, and the internal get_data_to_plot. Public functions accept par_indices as a deprecated alias (DeprecationWarning).
- ax: canonicalize to `matplotlib.axes.Axes | None = None` everywhere (was `plt.Axes | None`, `matplotlib.axes.Axes` without `| None`, or untyped `ax=None` in profiles.py) - size: fix `tuple[float]` → `tuple[float, float]` in optimizer_convergence.py and waterfall_lowlevel; bare `tuple` → `tuple[float, float]` in optimizer_history_lowlevel - title/suptitle: `str = None` → `str | None = None` in sampling functions - Add `import matplotlib.axes` to waterfall.py, optimizer_convergence.py, optimizer_history.py, profiles.py
- switch remaining single-panel plotters and lowlevel helpers to the shared `get_ax` helper - remove ad hoc pyplot-based axes creation in favor of the shared path - ensure plots still fully configure passed-in axes, including labels and other axis-level metadata - make `projection_scatter_umap_original` explicitly accept and return an axes object - preserve backward compatibility for `optimization_run_properties_one_plot` by keeping positional argument order intact - keep tests broad and figure-focused, with targeted checks only where behavior actually changed
- `get_axes_array(axes, nrows, ncols, size)` — create or normalize a 2-D axes grid; raises on shape mismatch - `plot_diagonal_marginal(ax, values, diag_kind)` — KDE/hist marginal extracted from `optimization_scatter` so `sampling_scatter` can share it Functions updated: `optimization_scatter`, `sampling_scatter`, `sampling_1d_marginals`, `sampling_prediction_trajectories`, `visualize_estimated_observable_mapping`, `plot_linear_observable_mappings_from_pypesto_result`, `plot_splines_from_pypesto_result`, `plot_splines_from_inner_result`, `ensemble_scatter_lowlevel`, `projection_scatter_umap_original`, `optimization_run_properties_one_plot`. Also removes all `sns.set(style="ticks")` calls from `sampling.py` — these were the root cause of global matplotlib style mutations that made plots look inconsistent depending on call order.
`sampling_parameter_cis` accepted `alpha: Sequence[int]` (e.g. `[95]`) as a credibility level in integer percentages. This was mis-named (not matplotlib transparency) and used inconsistent units compared to every other CI parameter in the codebase (all others use 0–1 fractions).
`profiles` accepted only `ratio_min` (a likelihood-ratio threshold) to filter profile points. Users wanting to cut off at a standard confidence level had to call `chi2_quantile_to_ratio` manually first. New additive kwarg `confidence_level: float | None = None` — pass e.g. `confidence_level=0.95` and it is converted to the equivalent `ratio_min` via `chi2_quantile_to_ratio`. The two parameters are mutually exclusive; passing both raises `ValueError`. `ratio_min` is unchanged and keeps its existing meaning and default.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1709 +/- ##
============================================
- Coverage 83.99% 55.87% -28.12%
============================================
Files 164 164
Lines 14492 14636 +144
============================================
- Hits 12172 8178 -3994
- Misses 2320 6458 +4138 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
PaulJonasJost
left a comment
There was a problem hiding this comment.
Some great ideas among this. Not entirely sure what the big picture is, you want to move towards with this initial PR as the AI summary hints here. Would perhaps be important to discuss this once in the near future.
- move shared visualize helpers from _style.py into misc.py - add hide_unused_axes and reuse it across plotting functions that trim unused subplot panels - switch internal figure creation to constrained layout and stop forcing tight_layout afterwards - keep deprecated-kwarg handling with _UNSET-based detection of omitted vs explicit None - update observable mapping axes preparation to use the shared helpers - move helper tests from test_style.py to test_misc.py - move close_fig to test/conftest.py and ensure figure cleanup also happens on test failure
|
Thank you a lot for all the comments! |
Didn't check everything in all details, but my points have been addressed, thanks. |
vwiela
left a comment
There was a problem hiding this comment.
Looks better for me now and with the style and further changes incoming, good for me to merge this.
PaulJonasJost
left a comment
There was a problem hiding this comment.
Also did not check every detail. Have you considered the pair plot in matplotlib that I sent you? Might be much less code and not require specific code to plot the diagonal.
I've taken a close look at this. It would be possible to use the All of the rest of the code that I've added are additions to the visualisation itself like
So with this in mind, I wouldn't use "scatter_matrix" as it would just introduce an external function we would need to rely on for a simple part of the code we can have there manually allowing easier bug-fixing or changing. |
This PR lays the foundation for a coherent pyPESTO visualization API. It primarily normalizes the contracts that callers depend on, so that downstream style work can be applied uniformly, with a few small review-driven follow-up changes to helper placement, layout handling, and observable-mapping axes handling.
What changed
Shared helpers in
pypesto/visualize/misc.pyShared helpers used by all plotters:
get_ax(ax, size)— returns the provided axes or creates a new figure/axes pairget_axes_array(axes, nrows, ncols, size)— returns the provided 2-D array or creates a new subplot grid; validates shape if an existing array is passedplot_diagonal_marginal(ax, values, diag_kind)— shared KDE/histogram for scatter-matrix diagonalsprocess_deprecated_kwarg(...)— generic rename shim withDeprecationWarningmake_grid_shape(n_panels)— shared near-square subplot-grid helperType hints (all visualize files)
tuple→tuple[float, float]forsizeparametersax: Axes = None→ax: Axes | None = Nonethroughout-> matplotlib.axes.Axesand-> np.ndarrayreturn annotations where missingSingle-panel ax contract
All single-panel public functions now accept
ax: matplotlib.axes.Axes | Noneand returnmatplotlib.axes.Axes.Multi-panel axes grid contract
All multi-panel public functions now accept
axes: np.ndarray | Noneand return a 2-Dnp.ndarrayofAxes.optimization_scatterrewritten from seaborn PairGrid to pure matplotlib: per-panel KDE diagonals, fval-encoded viridis_r colorbar, correctlb_full/ub_full[parameter_indices[i]]bound indexing.sampling_parameter_cis:alpha→confidence_levelsalpha: Sequence[int](integer percentages, e.g.[95, 68])confidence_levels: Sequence[float](fractions, e.g.[0.95, 0.68])alphakept as a deprecated kwarg; auto-converts withDeprecationWarningprofiles:confidence_levelconvenience parameterNew optional
confidence_level: float | None = Nonealongsideratio_min; converts viachi2_quantile_to_ratio.Layout handling
Where figures are created internally, they now use constrained layout instead of forcing
tight_layout()afterward.Tests
test/visualize/test_style.pytotest/visualize/test_misc.pyclose_figmoved totest/conftest.pyso it can be reused across visualization testsWhat this PR does NOT touch
rcParamsmodel_fit.py,ordinal_categories.pyinternals