Repository navigation
Conversation
This was referenced Jul 31, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5689 +/- ##
==========================================
+ Coverage 98.15% 98.19% +0.04%
==========================================
Files 341 343 +2
Lines 33902 34592 +690
==========================================
+ Hits 33275 33969 +694
+ Misses 627 623 -4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
2 of 3 tasks
aabills
force-pushed
the
ufv-3-plotting
branch
from
September 3, 2026 19:31
e70d618 to
c6ca5bf
Compare
Add VTKQuickPlot, QuickPlot/dynamic_plot hooks, the vtk optional extra, and headless OSMesa CI setup for GIF export. Extracted from the unstructured finite-volume stack. Co-authored-by: Cursor <cursoragent@cursor.com>
Every panel was built from the FIRST spatial variable's mesh, so a 3-domain variable (e.g. electrolyte concentration) plotted alongside a 5-domain one was painted onto the larger grid: all values shifted by the leading domains' cell count, rendering electrolyte data on current-collector tabs. Build each panel's grid from that variable's own mesh, and make _set_cell/point_scalars raise on a length mismatch so this bug class errors instead of drawing a wrong picture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The regular visualisation grid, mid-plane slices, quiver sampling and slice-plane positions used to live on the unstructured processed variables; the spatial-method PR now ships them as pure point interpolators. Add pybamm.plotting.unstructured_plot_grid with plot_grid, default_slice_positions, midplane_slices and quiver_data, and have QuickPlot own the grid and slice positions per plotted variable (the slice sliders update QuickPlot state). Meshes expose `vertices`, not `nodes`; fix plot_vtk and its test stand-ins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aabills
force-pushed
the
ufv-3-plotting
branch
from
September 5, 2026 00:27
c6ca5bf to
fcd4290
Compare
The CI matrix installs extras unlocked (prebuilt-solver-wheel mode uses uv pip install), so it picked up VTK 9.7.0, where the legacy AddActor2D name no longer exists. AddViewProp is the underlying method in every supported VTK. Lock VTK 9.7.0 so local environments test the same version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
matplotlib 3.11 (which the unlocked CI matrix installs) emits a PendingDeprecationWarning for Colormap.set_bad, and the test suite treats warnings as errors. with_extremes(bad=...) has been available since 3.4. Lock matplotlib 3.11.1 so local runs see what CI sees. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tests for dynamic_plot(backend="vtk"), the on-screen render window, the matplotlib-less lookup-table fallback, QuickPlot's 3D "tight" limits path and the wireframe helper's 3D guard. The interactive-only lines in VTKQuickPlot.dynamic_plot (interactor.Start and the render inside the slider callback) cannot run headless and are marked no cover, as QuickPlot already does for plt.show. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… window Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… numbers
VTK's automatic major ticks piled a dozen labels onto short or stretched
axes ("0.060.080.100.12") and the through-cell axis became a smear under
the 100x display stretch. Set three explicit labels per axis, print the
range of any axis thinner than 5% of the largest in its title instead of
ticks, drop the "(x10^-6)" label scaling, and format scalar-bar values
with %.4g so "1.27e+03" is no longer clipped to "1.27e+" and "303." loses
its dangling point. Slightly smaller axis and panel-title fonts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only unstructured-mesh scalars and 0D time series are plottable; vector fields and structured spatial variables used to fall through to the 0D chart path, crashing or silently plotting mesh node 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ScikitFemSubMesh3D stores coordinates as nodes, not vertices, so the FEM path of VTKQuickPlot only worked against test fakes. The node-data fixture now mirrors the real mesh. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The VTK branch re-passed output_variables by keyword next to *args, so the positional form raised TypeError; unknown backends now raise OptionError instead of silently using matplotlib. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Slice position and axis ranges came from the first variable's mesh, so a panel on a sub-domain mesh was cut and labelled against the wrong extents. 2D meshes now map their (x, z) columns explicitly instead of indexing a missing third column. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The OSMesa packages and default window class were wired only into the reusable workflow, so the periodic matrix ran the unit suite without them. The env default now lives in noxfile.py for headless Linux, and the periodic workflow installs the same system packages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Off-screen Linux no longer hard-codes the OSMesa window class, which crashed desktops without libOSMesa; headless hosts select it through VTK_DEFAULT_OPENGL_WINDOW instead. save_gif's PIL import is now an optional-dependency import backed by the vtk extra. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The 2D quiver, unstructured pcolormesh and 3D slice blocks were pasted into both methods; they now live in one helper each. The pcolormesh helper also replaces the previous frame's artists instead of stacking them, and the fixed-limits scan uses a single comprehension pair. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The plot_surface panels and the y/z slice sliders used raw metres with unit-less labels while every other panel honoured spatial_unit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace the unused _is_unstructured_spatial_variable helper with
_variable_kind and use it both to classify requested variables and to
filter default_quick_plot_variables, instead of plotting the model's
first variable key ("Time [s]" for every battery model).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A misspelled key or plot_type (e.g. "Slice") used to fall through to the default 3D pipeline without any error. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The chart axis range now comes from the finite samples, matching the spatial panels, and the time/value columns are transferred with numpy_to_vtk instead of a per-value InsertNextValue loop. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- variable_limits="fixed" (the default) now spans the vector magnitude over every time and cell instead of silently behaving as "tight" - the static 2D mesh wireframe is drawn once per figure (zorder above the QuadMesh) rather than rebuilt on every slider update - the 3D error message only points at VTKQuickPlot for node-centred unstructured variables, which is what it accepts Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…h NumPy 2 pybamm needs numpy>=2.0.0, so the previous >=9.0.0 bound admitted VTK wheels whose numpy bridge fails at import. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ngelog Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A model's `default_quick_plot_variables` may group several names onto one QuickPlot axis, so `_default_output_variables` was indexing the solution with a list and dying with `TypeError: unhashable type: 'list'` — e.g. any `VTKQuickPlot(solution)` on a Thevenin, lead-acid or `basic_splitOCVR` solution. Flatten the groups first; VTK draws one panel per variable anyway. An empty per-variable options list passed every other validation check but left the variable with no panel, and `dynamic_plot` then divided by a zero panel column count. Reject it where the other malformed options are rejected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dules `_get_spatial_var` returns early for every unstructured variable through the display-grid lookup above, so the unstructured classes in the `second` dimension's isinstance check could never be reached — and neither class carries the `second_dim_pts` the branch reads. Leave `ProcessedVariable2DFVM`, which is the only class that gets there. `plot_vtk` and `unstructured_plot_grid` were missing from the plotting package's `__all__`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov's one patch miss on this PR: a vector field whose magnitude is zero everywhere leaves `float(np.nanmax(magnitude))` at 0, and the (0, 0) range would paint every arrow the same colour, so the limits fall back to (0, 1). Give `_triangle_vector_solution` a `values` argument and assert the fallback; the test fails if the guard is removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e path. The bullet had landed under the released v26.8.0.0 section. The time slider updated each panel twice and read cell data through a private helper the public call already covers. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Without interpolate_time the panels show the nearest stored time, but the time text and chart markers used the raw slider value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ipywidgets' default step of 0.1 display units left a metre-unit slice slider snapping between its two ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The slice camera only moved the axis_idx component of ResetCamera's default +z position, so x- and y-slices were viewed ~59 degrees off their normal. Place the camera at the focal point offset along the normal only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Slice panels drew their cube axes around the cut geometry but labelled them with the whole mesh's range, so a slice covering part of a non-box domain showed wrong coordinates. Derive the physical ranges from the drawn bounds divided by the panel scale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A point exactly on a boundary triangle makes that triangle's solid angle +-2*pi (+-pi on an edge) with the sign set by round-off. On axis-aligned faces the round-off happened to vanish, but on a rotated mesh ~half the surface points came back outside, so plots showed NaN gaps along the boundary. Inflate the boundary by 1e-9 of the mesh span along the vertex normals, keeping the surface closed, and classify with the 2*pi midpoint again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Casting to float32 collapsed fields with a small spread on a large offset (e.g. 298.15 K + 2e-5 K) onto a couple of colours while the colour bar, computed in float64, showed the full range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VTKQuickPlot is the 3D path. QuickPlot keeps 2D unstructured scalar and vector-field plotting and now raises for any 3D variable, pointing unstructured ones to VTKQuickPlot. Removes the mid-plane slice panels, 3D quiver panels, the slice sliders, and their sampling helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QuickPlot's multiple-solution error is 2D-only again after dropping matplotlib 3D support, so the test matches main's message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
aabills
added a commit
that referenced
this pull request
Sep 28, 2026
aabills
added a commit
that referenced
this pull request
Sep 28, 2026
* Release v26.9.0.0 and pybammsolvers v0.10.0 Update CHANGELOG.md and CITATION.cff for v26.9.0.0. Merge the stray second Breaking changes block into the first, drop the citation of the unmerged #5782, and move the #5688 and #5630 entries out of v26.8.0.0, which was tagged before they merged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cite #5690 for the VTK plotting changelog entry #5689 was closed unmerged; its VTK plotting work landed through #5690. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
VTKQuickPlot: interactive VTK rendering of 2D/3D unstructured-mesh variables with slices, a time slider and GIF export, plus abackend="vtk"switch inpybamm.dynamic_plot.QuickPlotsupport for unstructured scalar, vector-field and 3D variables (display-grid sampling, mid-plane slices with slice sliders, quiver panels).vtkextra (included inall); headless OSMesa/EGL setup for Linux and Windows CI.Stack
#5686, #5687 and #5688 are merged. This PR → #5690 (unstructured DFN models) → #5691 (deprecate
Magnitude, optional cleanup).Test plan
test_plot_vtk.py,test_unstructured_plot_grid.py,test_unstructured_submesh.pyand the QuickPlot tests pass locallycreate_giffailures)🤖 Generated with Claude Code