Skip to content

Commit

Permalink
Merge PR #260 (Prevent subplots from overlapping in 6-panel plots)
Browse files Browse the repository at this point in the history
This merge brings PR #260 (Prevent subplots from overlapping in
6-panel plots; Prevent colorbar labels from overlapping, by @yantosca)
into the GCPy 1.4.0 development stream.

This fixes a few issues with the 6-panel plots (as used in benchmarking),
where the plots from each row were overlapping into the plots from the
row below it.  These issues were fixed by adjusting the spacing between
the plot and colorbar, and also by adjusting the space between subplots
manually.  Also, several plot attributes are now stored in a style sheet
rather than being hardwired in code.

Signed-off-by: Bob Yantosca <[email protected]>
  • Loading branch information
yantosca committed Sep 20, 2023
2 parents 7acc06d + dc7c99a commit 7de951b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Added `ENCODING = "UTF-8"` to `gcpy/constants.py`
- Added statement `from dask.array import Array as DaskArray` in `gcpy plot.py`
- Added SLURM run script `gcpy/benchmark/benchmark_slurm.sh`
- Added `gcpy/gcpy_plot_style` style sheet for title and label default settings

### Changed
- Simplified the Github issues templates into two options: `new-feature-or-discussion.md` and `question-issue.md`
Expand Down Expand Up @@ -59,11 +60,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Rewrote `Regridding.rst` page; Confirmed that regridding examples work properly
- Now allow `plot_val` to be of type `dask.array.Array` in `plot.py` routines `six_plot` and `single_panel`
- Now add `if` statements to turn of `Parallel()` commands when `n_jobs==1`.
- Do not hardwire fontsize in `gcpy/plot.py`; get defaults from `gcpy_plot_style`

### Fixed
- Generalized test for GCHP or GCClassic restart file in `regrid_restart_file.py`
- Fixed bug in transport tracer benchmark mass conservation table file write
- Routine `create_display_name` now splits on only the first `_` in species & diag names
- Prevent plot panels from overlapping in six-panel plots
- Prevent colorbar tick labels from overlapping in dynamic-range ratio plots

### Removed
- Removed `gchp_is_pre_13_1` arguments & code from benchmarking routines
Expand Down
15 changes: 15 additions & 0 deletions gcpy/gcpy_plot_style
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ======================================================================
# Customizable style sheet to set plot parameters such as
# font sizes of axes labels, tick marks, etc.
#
# Default values will be applied for settings not explicitly listed
# below. For more information, see the Matplotlib documentation at:
# https://matplotlib.org/stable/users/explain/customizing.html
# ======================================================================

figure.titlesize : 25 # Top-of-plot title fontsize
figure.autolayout : false # Don't use tight_layout()
axes.titlesize : medium # Subplot title size
axes.titlelocation : center # Subplot title location
axes.titleweight : medium # Subplot title weight
axes.labelsize : small # Subplot X and Y label size
65 changes: 46 additions & 19 deletions gcpy/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
delimiter=' ')
WhGrYlRd = mcolors.ListedColormap(_rgb_WhGrYlRd / 255.0)

# Use a style sheet to control font sizes
style_sheet = os.path.join(os.path.dirname(__file__), "gcpy_plot_style")
plt.style.use(style_sheet)


def six_plot(
subplot,
Expand Down Expand Up @@ -224,13 +228,18 @@ def six_plot(
ll_plot_func=ll_plot_func,
**extra_plot_args)

# Control how close to the plot the colorbar will go
pad = 0.15
if "single_level" in plot_type:
pad = 0.025

# Define the colorbar for the plot
cbar = plt.colorbar(
plot,
ax=ax,
orientation="horizontal",
norm=norm,
pad=0.10
pad=pad
)
cbar.mappable.set_norm(norm)
cbar = colorbar_ticks_and_format(
Expand All @@ -246,6 +255,7 @@ def six_plot(
)
cbar.set_label(unit)


def compute_vmin_vmax_for_plot(
plot_val,
vmins,
Expand Down Expand Up @@ -364,6 +374,8 @@ def verbose_print(verbose, rowcol, vmin, vmax):
[np.abs(np.nanmin(plot_val)), np.abs(np.nanmax(plot_val))]
)
vmin = 1.0 / vmax
if vmin > vmax:
vmin, vmax = vmax, vmin
verbose_print(verbose, rowcol, vmin, vmax)
return vmin, vmax

Expand Down Expand Up @@ -503,10 +515,21 @@ def ref_equals_dev(array):
# Dynamic range ratio subplot
if subplot in "dyn_ratio":

# Set ticks manually and use ScalarFormatter for
# data in the range of 0.1 .. 10.0. Use avg(vmax,1)
# and avg(vmin,1) for the 2nd & 4th tick locations.
# Maybe find a better method later on.
# If the ratio is in the range 0.999 and 1.001, then
# place tickmarks at [vmin, 1, vmax]. This should help
# to avoid the tick labels from running together.
if vmin > 0.999 and vmax < 1.001:
pos = [vmin, 1.0, vmax]
cbar.set_ticks(pos)
cbar.formatter = mticker.ScalarFormatter()
cbar.formatter.set_useOffset(False)
cbar.minorticks_off()
return cbar

# If the ratio is in the range 0.1 .. 10.0, then place
# tickmarks [vmin, avg(vmin,1), 1, avg(vmax,1), vmax].
# This should be good enough for most cases. Perhaps
# think about implementing a better method later on.
if vmin > 0.1 and vmax < 10.0:
pos = [vmin, (vmin+1.0)/2.0, 1.0, (vmax+1.0)/2.0, vmax]
cbar.set_ticks(pos)
Expand Down Expand Up @@ -1422,7 +1445,6 @@ def get_extent_for_colors(ds, minlon, maxlon, minlat, maxlat):
plt.subplots_adjust(hspace=0.4)
# Give the figure a title
offset = 0.96
fontsize = 25
if "lev" in ds_ref.dims and "lev" in ds_dev.dims:
if ilev == 0:
levstr = "Surface"
Expand All @@ -1433,13 +1455,12 @@ def get_extent_for_colors(ds, minlon, maxlon, minlat, maxlat):
if extra_title_txt is not None:
figs.suptitle(
f"{varname}, {levstr} ({extra_title_txt})",
fontsize=fontsize,
y=offset,
)
else:
figs.suptitle(
f"{varname}, {levstr}",
fontsize=fontsize, y=offset
y=offset
)
elif (
"lat" in ds_ref.dims
Expand All @@ -1450,13 +1471,11 @@ def get_extent_for_colors(ds, minlon, maxlon, minlat, maxlat):
if extra_title_txt is not None:
figs.suptitle(
f"{varname} ({extra_title_txt})",
fontsize=fontsize,
y=offset,
)
else:
figs.suptitle(
f"{varname}",
fontsize=fontsize,
y=offset)
else:
print(f"Incorrect dimensions for {varname}!")
Expand Down Expand Up @@ -1661,6 +1680,7 @@ def get_extent_for_colors(ds, minlon, maxlon, minlat, maxlat):
**extra_plot_args
)


# ==============================================================
# Add this page of 6-panel plots to a PDF file
# ==============================================================
Expand Down Expand Up @@ -1783,8 +1803,8 @@ def compare_zonal_mean(
**extra_plot_args
):
"""
Create single-level 3x2 comparison zonal-mean plots for variables
common in two xarray Daatasets. Optionally save to PDF.
Creates 3x2 comparison zonal-mean plots for variables
common in two xarray Datasets. Optionally save to PDF.
Args:
refdata: xarray dataset
Expand Down Expand Up @@ -2506,21 +2526,28 @@ def createfig(ivar, temp_dir=''):
figs, ((ax0, ax1), (ax2, ax3), (ax4, ax5)) = plt.subplots(
3, 2, figsize=[12, 15.3]
)
# Ensure subplots don't overlap when invoking plt.show()
if not savepdf:
plt.subplots_adjust(hspace=0.4)
# Add extra adding so that plots don't bump into each other.
# For zonal mean plots, we need to leave extra padding at the
# left (for the Y-axis label) and at the bottom (for the colrobar).
plt.subplots_adjust(
left=0.10, # Fraction of page width, from left edge
right=0.925, # Fraction of page width, from left edge
bottom=0.05, # Fraction of page height, from bottom edge
wspace=0.25, # Horizontal spacing btw subplots (frac of width)
hspace=0.35 # Vertical spacing btw subplots (fract of height)
)
# Give the plot a title
offset = 0.96
fontsize = 25
if extra_title_txt is not None:
figs.suptitle(
f"{varname}, Zonal Mean ({extra_title_txt})",
fontsize=fontsize,
y=offset,
)
else:
figs.suptitle(f"{varname}, Zonal Mean",
fontsize=fontsize, y=offset)
figs.suptitle(
f"{varname}, Zonal Mean",
y=offset
)

# ==============================================================
# Set color map objects. Use gray for NaNs (no worries,
Expand Down

0 comments on commit 7de951b

Please sign in to comment.