Skip to content

Commit

Permalink
Close figures after saving, and refactor plotting code
Browse files Browse the repository at this point in the history
Refactors the plotting code to use the explicit (object-oriented)
matplotlib API. Figures are explicitly closed, preventing memory
leaking. Also added a super-title to the postage stamp plots, so
the diagnostic title is there too.

Fixes #481
  • Loading branch information
jfrost-mo committed Apr 11, 2024
1 parent eed9efa commit 6cfef8b
Showing 1 changed file with 30 additions and 22 deletions.
52 changes: 30 additions & 22 deletions src/CSET/operators/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import fcntl
import importlib.resources
import itertools
import json
import logging
import math
Expand Down Expand Up @@ -138,32 +139,33 @@ def _plot_and_save_contour_plot(
"""
# Setup plot details, size, resolution, etc.
fig = plt.figure(figsize=(15, 15), facecolor="w", edgecolor="k")

cmap = mpl.colormaps["viridis"]
axes = fig.subplots()

# Filled contour plot of the field.
iplt.contourf(cube, cmap=cmap)
axes = fig.gca()
cmap = mpl.colormaps["viridis"]
iplt.contourf(cube, cmap=cmap, axes=axes)

# Add coastlines.
axes.coastlines(resolution="10m")

# Add title.
plt.title(title, fontsize=16)
axes.set_title(title, fontsize=16)

# Add colour bar.
cbar = plt.colorbar()
cbar = fig.colorbar()
cbar.set_label(label=f"{cube.name()} ({cube.units})", size=20)

# Save plot.
fig.savefig(filename, bbox_inches="tight", dpi=150)
logging.info("Saved contour plot to %s", filename)
plt.close(fig)


def _plot_and_save_postage_stamp_contour_plot(
cube: iris.cube.Cube,
filename: str,
stamp_coordinate: str,
title: str,
**kwargs,
):
"""Plot postage stamp contour plots from an ensemble.
Expand All @@ -185,24 +187,29 @@ def _plot_and_save_postage_stamp_contour_plot(
# Use the smallest square grid that will fit the members.
grid_size = int(math.ceil(math.sqrt(len(cube.coord(stamp_coordinate).points))))

plt.figure(figsize=(10, 10))
# Make a subplot for each member.
subplot = 1
for member in cube.slices_over(stamp_coordinate):
plt.subplot(grid_size, grid_size, subplot)
plot = iplt.contourf(member)
plt.title(f"Member #{member.coord(stamp_coordinate).points[0]}")
plt.axis("off")
plt.gca().coastlines()
subplot += 1
fig = plt.figure(figsize=(10, 10))
# Make a subplot for each member. This returns a 2D array, which we turn
# into a 1D iterable.
axes = itertools.chain.from_iterable(
fig.subplots(grid_size, grid_size, squeeze=False)
)
for ax, member in zip(axes, cube.slices_over(stamp_coordinate)):
plot = iplt.contourf(member, axes=ax)
ax.set_title(f"Member #{member.coord(stamp_coordinate).points[0]}")
ax.set_axis_off()
ax.coastlines()

# Put the shared colorbar in its own axes.
colorbar_axes = plt.gcf().add_axes([0.15, 0.07, 0.7, 0.03])
colorbar = plt.colorbar(plot, colorbar_axes, orientation="horizontal")
colorbar_axes = fig.add_axes([0.15, 0.07, 0.7, 0.03])
colorbar = fig.colorbar(plot, colorbar_axes, orientation="horizontal")
colorbar.set_label(f"{cube.name()} / {cube.units}")

plt.savefig(filename, bbox_inches="tight", dpi=150)
# Overall figure title.
fig.suptitle(title)

fig.savefig(filename, bbox_inches="tight", dpi=150)
logging.info("Saved contour postage stamp plot to %s", filename)
plt.close(fig)


def _plot_and_save_line_series(
Expand All @@ -222,10 +229,10 @@ def _plot_and_save_line_series(
Plot title.
"""
fig = plt.figure(figsize=(8, 8), facecolor="w", edgecolor="k")
iplt.plot(coord, cube, "o-")
ax = fig.subplots()
iplt.plot(coord, cube, "o-", axes=ax)

# Add some labels and tweak the style.
ax = fig.gca()
ax.set(
xlabel=f"{coord.name()} / {coord.units}",
ylabel=f"{cube.name()} / {cube.units}",
Expand All @@ -238,6 +245,7 @@ def _plot_and_save_line_series(
# Save plot.
fig.savefig(filename, bbox_inches="tight", dpi=150)
logging.info("Saved line plot to %s", filename)
plt.close(fig)


####################
Expand Down Expand Up @@ -387,7 +395,7 @@ def postage_stamp_contour_plot(
except iris.exceptions.CoordinateNotFoundError as err:
raise ValueError(f"Cube must have a {coordinate} coordinate.") from err

_plot_and_save_postage_stamp_contour_plot(cube, filename, coordinate)
_plot_and_save_postage_stamp_contour_plot(cube, filename, coordinate, title="")
_make_plot_html_page([filename])
return cube

Expand Down

0 comments on commit 6cfef8b

Please # to comment.