From c94385569509daf610fe5e539890e28c611f2928 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Thu, 22 Oct 2026 21:55:00 +0100 Subject: [PATCH 1/7] Replace deprecated matplotlib set_over & set_under case --- cfplot/blockfill.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cfplot/blockfill.py b/cfplot/blockfill.py index 5d1e88f4..91d71d73 100644 --- a/cfplot/blockfill.py +++ b/cfplot/blockfill.py @@ -63,19 +63,20 @@ def _bfill( colmap = get_colour_scale_map() cmap = matplotlib.colors.ListedColormap(colmap) fill_colors = list(colmap) - if plotvars.levels_extend in ["min", "both"]: - cmap.set_under(plotvars.cs[0]) - if plotvars.levels_extend in ["max", "both"]: - cmap.set_over(plotvars.cs[-1]) - under_index = None - over_index = None + extremes = {} if plotvars.levels_extend in ["min", "both"]: + extremes["under"] = plotvars.cs[0] under_index = len(fill_colors) fill_colors.append(plotvars.cs[0]) if plotvars.levels_extend in ["max", "both"]: + extremes["over"] = plotvars.cs[-1] over_index = len(fill_colors) fill_colors.append(plotvars.cs[-1]) + + if extremes: + cmap = cmap.with_extremes(**extremes) + else: cols = single_fill_color cmap = matplotlib.colors.ListedColormap(cols) From f384bd54550e666e76c6caeef2adb1a9ed47a47d Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Thu, 22 Oct 2026 22:43:22 +0100 Subject: [PATCH 2/7] Replace rest of deprecated matplotlib set_over & set_under cases --- cfplot/blockfill.py | 4 ++-- cfplot/colorbar.py | 8 ++++++-- cfplot/colour/colour.py | 8 ++++++-- cfplot/contour.py | 8 ++++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/cfplot/blockfill.py b/cfplot/blockfill.py index 91d71d73..846bcada 100644 --- a/cfplot/blockfill.py +++ b/cfplot/blockfill.py @@ -448,10 +448,10 @@ def _bfill_ugrid( levs = deepcopy(np.array(clevs)) - if plotvars.levels_extend == "min" or plotvars.levels_extend == "both": + if plotvars.levels_extend in ("min", "both"): levs = np.concatenate([[-1e20], levs]) ilevs_max = np.size(levs) - if plotvars.levels_extend == "max" or plotvars.levels_extend == "both": + if plotvars.levels_extend in ("max", "both"): levs = np.concatenate([levs, [1e20]]) else: ilevs_max = ilevs_max - 1 diff --git a/cfplot/colorbar.py b/cfplot/colorbar.py index 7a1a1fab..9a4e0011 100644 --- a/cfplot/colorbar.py +++ b/cfplot/colorbar.py @@ -204,15 +204,19 @@ def cbar( ) boundaries = levs.astype(float) + extremes = {} if extend in ("both", "min"): - cmap.set_under(plotvars.cs[0]) + extremes["under"] = plotvars.cs[0] boundaries = np.insert(boundaries, 0, boundaries[0] - 1) if extend in ("both", "max"): - cmap.set_over(plotvars.cs[-1]) + extremes["over"] = plotvars.cs[-1] boundaries = np.insert( boundaries, len(boundaries), boundaries[-1] + 1 ) + if extremes: + cmap = cmap.with_extremes(**extremes) + if not isinstance(levs, list): lbot = None diff --git a/cfplot/colour/colour.py b/cfplot/colour/colour.py index df36efff..40cfb909 100644 --- a/cfplot/colour/colour.py +++ b/cfplot/colour/colour.py @@ -668,15 +668,19 @@ def cbar( # Add colorbar extensions if definded by levs. Using boundaries[0]-1 # for the lower and boundaries[-1]+1 is just for the colorbar and # has no meaning for the plot. + extremes = {} if extend in ("both", "min"): - cmap.set_under(plotvars.cs[0]) + extremes["under"] = plotvars.cs[0] boundaries = np.insert(boundaries, 0, boundaries[0] - 1) if extend in ("both", "max"): - cmap.set_over(plotvars.cs[-1]) + extremes["over"] = plotvars.cs[-1] boundaries = np.insert( boundaries, len(boundaries), boundaries[-1] + 1 ) + if extremes: + cmap = cmap.with_extremes(**extremes) + if not isinstance(levs, list): lbot = None diff --git a/cfplot/contour.py b/cfplot/contour.py index 84a9f2b6..f4266017 100644 --- a/cfplot/contour.py +++ b/cfplot/contour.py @@ -469,10 +469,14 @@ def get_cmap(self) -> matplotlib.colors.ListedColormap: colmap = get_colour_scale_map() cmap = matplotlib.colors.ListedColormap(colmap) + extremes = {} if scale.levels_extend == "min" or scale.levels_extend == "both": - cmap.set_under(scale.cs[0]) + extremes["under"] = plotvars.cs[0] if scale.levels_extend == "max" or scale.levels_extend == "both": - cmap.set_over(scale.cs[-1]) + extremes["over"] = plotvars.cs[-1] + + if extremes: + cmap = cmap.with_extremes(**extremes) return cmap From ad2b82d74e14b152088f1666529d01016747b325 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Thu, 22 Oct 2026 23:56:35 +0100 Subject: [PATCH 3/7] Update trajectory logic to prevent shapely linestrings warning + lint --- cfplot/__init__.py | 2 +- cfplot/trajectory.py | 68 ++++++++++++++----- .../integration/test_contour_plot_examples.py | 2 +- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/cfplot/__init__.py b/cfplot/__init__.py index 12329314..d9076e61 100644 --- a/cfplot/__init__.py +++ b/cfplot/__init__.py @@ -21,7 +21,7 @@ from .vector import vect __author__ = "Andy Heaps, Sadie Bartholomew, Bryan Lawrence" -__maintainer__ ="Sadie Bartholomew" +__maintainer__ = "Sadie Bartholomew" __date__ = "2026-10-09" diff --git a/cfplot/trajectory.py b/cfplot/trajectory.py index 61825a53..da858aa8 100644 --- a/cfplot/trajectory.py +++ b/cfplot/trajectory.py @@ -20,6 +20,29 @@ from .state import plotvars +def _trajectory_segments(x, y): + """Yield contiguous segments of finite, unmasked coordinates.""" + x = np.ma.asarray(x, dtype=float) + y = np.ma.asarray(y, dtype=float) + + x_data = x.filled(np.nan) + y_data = y.filled(np.nan) + + valid = ( + ~np.ma.getmaskarray(x) + & ~np.ma.getmaskarray(y) + & np.isfinite(x_data) + & np.isfinite(y_data) + ) + + edges = np.diff(np.r_[False, valid, False].astype(int)) + starts = np.flatnonzero(edges == 1) + stops = np.flatnonzero(edges == -1) + + for start, stop in zip(starts, stops): + yield start, stop, x_data[start:stop], y_data[start:stop] + + def traj( f=None, title=None, @@ -305,22 +328,35 @@ def traj( print("plotting markers") if legend_lines is False: - mymap.plot( - xpts, - ypts, - color=linecolor, - linewidth=plot_linewidth, - linestyle=linestyle, - marker=marker, - markevery=markevery, - markersize=plot_markersize, - markerfacecolor=markerfacecolor, - markeredgecolor=markeredgecolor, - markeredgewidth=markeredgewidth, - zorder=zorder, - clip_on=True, - transform=ccrs.PlateCarree(), - ) + for start, stop, x_segment, y_segment in _trajectory_segments( + xpts, ypts + ): + segment_markevery = markevery + if ( + isinstance(markevery, (int, np.integer)) + and markevery > 0 + ): + segment_markevery = np.flatnonzero( + np.arange(start, stop) % markevery == 0 + ) + segment_markevery -= start + + mymap.plot( + x_segment, + y_segment, + color=linecolor, + linewidth=plot_linewidth, + linestyle=linestyle, + marker=marker, + markevery=segment_markevery, + markersize=plot_markersize, + markerfacecolor=markerfacecolor, + markeredgecolor=markeredgecolor, + markeredgewidth=markeredgewidth, + zorder=zorder, + clip_on=True, + transform=ccrs.PlateCarree(), + ) else: line_xpts = xpts.compressed() line_ypts = ypts.compressed() diff --git a/tests/integration/test_contour_plot_examples.py b/tests/integration/test_contour_plot_examples.py index 65ed132f..a44c78f1 100644 --- a/tests/integration/test_contour_plot_examples.py +++ b/tests/integration/test_contour_plot_examples.py @@ -104,7 +104,7 @@ def _assert_reference_match_strict(generated: Path, reference: Path) -> None: result = mpl_compare.compare_images( str(reference), str(generated), - tol=0., + tol=0.0, in_decorator=True, ) if result is not None: From 9240b09f1564ac3d3394d876f8cc79d7a2c71f7e Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Fri, 23 Oct 2026 00:00:49 +0100 Subject: [PATCH 4/7] Update Changelog for fix to Issue #72 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51dfa008..a0c25e70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,12 @@ of being developed elsewhere. ### Version `3.5.X`, first released 2026-10-09 -#### Version `3.5.0`, release 2026-10-09 +#### Version `3.5.1`, released 2026-??-?? + +* Update code to prevent deprecation-related warnings + (https://github.com/NCAS-CMS/cf-plot/issues/72) + +#### Version `3.5.0`, released 2026-10-09 * Modularise and refactor the codebase, which has no user-facing implications except that functionality is available via sub-modules as well as at the top-level From 9ef4b83e120a8d0e343f5608d08ecbf733839e50 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Fri, 23 Oct 2026 00:59:45 +0100 Subject: [PATCH 5/7] Add step to image comp. workflow to store gen'd plots for 1 week --- .github/workflows/run-image-comparison.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/run-image-comparison.yml b/.github/workflows/run-image-comparison.yml index a23f9a60..4f54820a 100644 --- a/.github/workflows/run-image-comparison.yml +++ b/.github/workflows/run-image-comparison.yml @@ -57,3 +57,12 @@ jobs: - name: Notify about a completed run if: success() run: echo "Image comparison testing completed successfully on ${{ matrix.os }}." + + - name: Upload generated images and diffs + if: always() + uses: actions/upload-artifact@v4 + with: + name: image-comparison-results-${{ runner.os }} + path: generated-example-images-cont/ + if-no-files-found: warn + retention-days: 7 From 040560dddd0d0925db2ff45aacd56a9408de4376 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Fri, 23 Oct 2026 01:26:20 +0100 Subject: [PATCH 6/7] Add missing directory to image comparison store of gen'd imags --- .github/workflows/run-image-comparison.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-image-comparison.yml b/.github/workflows/run-image-comparison.yml index 4f54820a..082fc566 100644 --- a/.github/workflows/run-image-comparison.yml +++ b/.github/workflows/run-image-comparison.yml @@ -63,6 +63,8 @@ jobs: uses: actions/upload-artifact@v4 with: name: image-comparison-results-${{ runner.os }} - path: generated-example-images-cont/ + path: | + generated-example-images-adv/ + generated-example-images-cont/ if-no-files-found: warn retention-days: 7 From 3a348276930e1d8dc4d9c4c69700574d384e5a50 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Fri, 23 Oct 2026 01:34:52 +0100 Subject: [PATCH 7/7] Add fix paths to directories in image comparison store of gen'd imags --- .github/workflows/run-image-comparison.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-image-comparison.yml b/.github/workflows/run-image-comparison.yml index 082fc566..cc255ef9 100644 --- a/.github/workflows/run-image-comparison.yml +++ b/.github/workflows/run-image-comparison.yml @@ -64,7 +64,7 @@ jobs: with: name: image-comparison-results-${{ runner.os }} path: | - generated-example-images-adv/ - generated-example-images-cont/ + main/generated-example-images-adv/ + main/generated-example-images-cont/ if-no-files-found: warn retention-days: 7