Skip to content

Commit

Permalink
Use config options to set arrow width and spacing
Browse files Browse the repository at this point in the history
  • Loading branch information
xylar committed Mar 5, 2025
1 parent 371406d commit 6757b32
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 66 deletions.
10 changes: 7 additions & 3 deletions mpas_analysis/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -1576,9 +1576,13 @@ normArgsResult = {'vmin': -100, 'vmax': 200.}
contourLevelsResult = np.arange(-100., 201.0, 10.)
contourThicknessResult = 0.5
contourColorResult = black
# Add arrows to contour lines
# whether to include arrows on the contour lines showing the direction of flow
arrowsOnContourResult = True
# The spacing (in meters) between arrows on contours in projection plots
# (None to disable)
arrowSpacingResult = 8e5
# The width (in meters) of arrows on contours in projection plots (None to
# disable)
arrowWidthResult = 1.5e4

# colormap for differences
colormapNameDifference = cmo.balance
# whether the colormap is indexed or continuous
Expand Down
26 changes: 17 additions & 9 deletions mpas_analysis/polar_regions.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -626,14 +626,18 @@ colormapTypeResult = continuous
normTypeResult = symLog
# A dictionary with keywords for the norm
normArgsResult = {'linthresh': 30., 'linscale': 0.5, 'vmin': -150., 'vmax': 150.}
colorbarTicksResult = [-100.,-40., -20., -10., 0., 10., 20., 40., 100.]
colorbarTicksResult = [-150., -100.,-60., -40., -20., -10., 0., 10., 20., 40., 60., 100., 150.]
# Adding contour lines to the figure
contourLevelsResult = np.arange(-150., 150.1, 10.)
contourThicknessResult = 0.5
contourColorResult = black
# Add arrows to contour lines
# whether to include arrows on the contour lines showing the direction of flow
arrowsOnContourResult = True
# The spacing (in meters) between arrows on contours in projection plots
# (None to disable)
arrowSpacingResult = 8e5
# The width (in meters) of arrows on contours in projection plots (None to
# disable)
arrowWidthResult = 1.5e4

# colormap for differences
colormapNameDifference = cmo.balance
# whether the colormap is indexed or continuous
Expand Down Expand Up @@ -661,14 +665,18 @@ colormapTypeResult = continuous
normTypeResult = symLog
# A dictionary with keywords for the norm
normArgsResult = {'linthresh': 1., 'linscale': 0.5, 'vmin': -20., 'vmax': 20.}
colorbarTicksResult = [-20., -10.,-4., -2., -1., 0., 1., 2., 4., 10., 20.]
colorbarTicksResult = [-20., -10.,-4., -2., -1., -0.5, 0., 0.5, 1., 2., 4., 10., 20.]
# Adding contour lines to the figure
contourLevelsResult = np.arange(-5., 5.1, 0.5)
contourLevelsResult = np.arange(-20., 20.1, 0.5)
contourThicknessResult = 0.5
contourColorResult = black
# Add arrows to contour lines
# whether to include arrows on the contour lines showing the direction of flow
arrowsOnContourResult = True
# The spacing (in meters) between arrows on contours in projection plots
# (None to disable)
arrowSpacingResult = 8e4
# The width (in meters) of arrows on contours in projection plots (None to
# disable)
arrowWidthResult = 1.5e3

# colormap for differences
colormapNameDifference = cmo.balance
# whether the colormap is indexed or continuous
Expand Down
44 changes: 23 additions & 21 deletions mpas_analysis/shared/plot/climatology_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def plot_polar_comparison(
# -------
# Xylar Asay-Davis, Milena Veneziani

def do_subplot(ax, field, title, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, arrows):
def _do_subplot(ax, field, title, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, **kwargs):
"""
Make a subplot within the figure.
"""
Expand Down Expand Up @@ -230,14 +230,14 @@ def do_subplot(ax, field, title, colormap, norm, levels, ticks, contours,
plotProjection))

ax = plt.subplot(subplots[0], projection=projection)
do_subplot(ax=ax, field=modelArray, title=modelTitle, **dictModelRef)
_do_subplot(ax=ax, field=modelArray, title=modelTitle, **dictModelRef)

if refArray is not None:
ax = plt.subplot(subplots[1], projection=projection)
do_subplot(ax=ax, field=refArray, title=refTitle, **dictModelRef)
_do_subplot(ax=ax, field=refArray, title=refTitle, **dictModelRef)

ax = plt.subplot(subplots[2], projection=projection)
do_subplot(ax=ax, field=diffArray, title=diffTitle, **dictDiff)
_do_subplot(ax=ax, field=diffArray, title=diffTitle, **dictDiff)

fig.canvas.draw()
plt.tight_layout(pad=4.)
Expand Down Expand Up @@ -343,8 +343,8 @@ def plot_global_comparison(
# -------
# Xylar Asay-Davis, Milena Veneziani

def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, arrows):
def _plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, **kwargs):

ax.set_extent(extent, crs=projection)

Expand Down Expand Up @@ -428,16 +428,16 @@ def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,

axes = []
ax = plt.subplot(subplots[0], projection=projection)
plot_panel(ax, modelTitle, modelArray, **dictModelRef)
_plot_panel(ax, modelTitle, modelArray, **dictModelRef)
axes.append(ax)

if refArray is not None:
ax = plt.subplot(subplots[1], projection=projection)
plot_panel(ax, refTitle, refArray, **dictModelRef)
_plot_panel(ax, refTitle, refArray, **dictModelRef)
axes.append(ax)

ax = plt.subplot(subplots[2], projection=projection)
plot_panel(ax, diffTitle, diffArray, **dictDiff)
_plot_panel(ax, diffTitle, diffArray, **dictDiff)
axes.append(ax)

_add_stats(modelArray, refArray, diffArray, Lats, axes)
Expand Down Expand Up @@ -543,7 +543,7 @@ def plot_projection_comparison(
# -------
# Xylar Asay-Davis

def add_arrow_to_line_2d(ax, poly, arrow_spacing=8e5, arrow_width=1.5e4):
def _add_arrow_to_line_2d(ax, poly, arrow_spacing, arrow_width):
"""
https://stackoverflow.com/a/27637925/7728169
Add arrows to a matplotlib.lines.Line2D at selected locations.
Expand All @@ -568,8 +568,8 @@ def add_arrow_to_line_2d(ax, poly, arrow_spacing=8e5, arrow_width=1.5e4):
arrows.append(p)
return arrows

def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, arrows):
def _plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
lineWidth, lineColor, arrowSpacing, arrowWidth):

title = limit_title(title, maxTitleLength)
ax.set_title(title, **plottitle_font)
Expand Down Expand Up @@ -611,10 +611,11 @@ def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
cs = ax.contour(x_center, y_center, array, levels=contours,
colors=lineColor, linewidths=lineWidth)
# add arrows to streamlines
if arrows is not None:
if arrowSpacing is not None and arrowWidth is not None:
for path in cs.get_paths():
for poly in path.to_polygons():
add_arrow_to_line_2d(ax, poly)
_add_arrow_to_line_2d(ax, poly, arrowSpacing,
arrowWidth)
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
Expand Down Expand Up @@ -677,7 +678,8 @@ def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
# set up land colormap
if not useCartopyCoastline:
colorList = [(0.8, 0.8, 0.8), (0.8, 0.8, 0.8)]
landColorMap = cols.LinearSegmentedColormap.from_list('land', colorList)
landColorMap = cols.LinearSegmentedColormap.from_list('land',
colorList)

# locations of centers for contour plots
xCenter = 0.5 * (x[1:] + x[0:-1])
Expand All @@ -688,14 +690,14 @@ def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
extent = [x[0], x[-1], y[0], y[-1]]

ax = plt.subplot(subplots[0], projection=projection)
plot_panel(ax, modelTitle, modelArray, **dictModelRef)
_plot_panel(ax, modelTitle, modelArray, **dictModelRef)

if refArray is not None:
ax = plt.subplot(subplots[1], projection=projection)
plot_panel(ax, refTitle, refArray, **dictModelRef)
_plot_panel(ax, refTitle, refArray, **dictModelRef)

ax = plt.subplot(subplots[2], projection=projection)
plot_panel(ax, diffTitle, diffArray, **dictDiff)
_plot_panel(ax, diffTitle, diffArray, **dictDiff)

if fileout is not None:
savefig(fileout, config)
Expand Down Expand Up @@ -791,7 +793,7 @@ def _add_land_lakes_coastline(ax, ice_shelves=True):
ax.add_feature(land_50m, zorder=2)
if ice_shelves:
ice_50m = cartopy.feature.NaturalEarthFeature(
'physical', 'antarctic_ice_shelves_polys', '50m', edgecolor='k',
facecolor='lightgray', linewidth=0.5)
'physical', 'antarctic_ice_shelves_polys', '50m',
edgecolor='k', facecolor='lightgray', linewidth=0.5)
ax.add_feature(ice_50m, zorder=3)
ax.add_feature(lakes_50m, zorder=4)
65 changes: 39 additions & 26 deletions mpas_analysis/shared/plot/colormap.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,19 @@ def setup_colormap(config, configSectionName, suffix=''):
'lineWidth' is the width of contour lines or ``None`` if not specified
'lineColor' is the color of contour lines or ``None`` if not specified
`arrowWidth` is the width of the arrows or ``None`` if not specified
`arrowSpacing` is the spacing between arrows or ``None`` if not
specified
"""
# Authors
# -------
# Xylar Asay-Davis, Milena Veneziani, Greg Streletz

register_custom_colormaps()

option = 'colormapType{}'.format(suffix)
option = f'colormapType{suffix}'
if config.has_option(configSectionName, option):
colormapType = config.get(configSectionName, option)
if colormapType == 'indexed':
Expand All @@ -88,35 +93,43 @@ def setup_colormap(config, configSectionName, suffix=''):
levels = None
ticks = None

option = 'contourLevels{}'.format(suffix)
contours = None
lineWidth = None
lineColor = None
arrowWidth = None
arrowSpacing = None

option = f'contourLevels{suffix}'
if config.has_option(configSectionName, option):
contours = config.getexpression(configSectionName,
option,
use_numpyfunc=True)
if isinstance(contours, str) and contours == 'none':
contours = None
else:
contours = None

option = 'contourThickness{}'.format(suffix)
option = f'contourThickness{suffix}'
if config.has_option(configSectionName, option):
lineWidth = config.getfloat(configSectionName, option)
else:
lineWidth = None

option = 'contourColor{}'.format(suffix)
option = f'contourColor{suffix}'
if config.has_option(configSectionName, option):
lineColor = config.get(configSectionName, option)
else:
lineColor = None
option = 'arrowsOnContour{}'.format(suffix)

option = f'arrowWidth{suffix}'
if config.has_option(configSectionName, option):
arrows = config.getboolean(configSectionName, option)
else:
arrows = None
arrowWidth = config.getexpression(configSectionName, option)
if isinstance(arrowWidth, str) and arrowWidth == 'None':
arrowWidth = None
option = f'arrowsSpacing{suffix}'
if config.has_option(configSectionName, option):
arrowSpacing = config.getexpression(configSectionName, option)
if isinstance(arrowSpacing, str) and arrowSpacing == 'None':
arrowSpacing = None

return {'colormap': colormap, 'norm': norm, 'levels': levels,
'ticks': ticks, 'contours': contours, 'lineWidth': lineWidth,
'lineColor': lineColor, 'arrows': arrows}
'lineColor': lineColor, 'arrowWidth': arrowWidth,
'arrowSpacing': arrowSpacing}


def register_custom_colormaps():
Expand Down Expand Up @@ -354,12 +367,12 @@ def _setup_colormap_and_norm(config, configSectionName, suffix=''):
register_custom_colormaps()

colormap = plt.get_cmap(config.get(configSectionName,
'colormapName{}'.format(suffix)))
f'colormapName{suffix}'))

normType = config.get(configSectionName, 'normType{}'.format(suffix))
normType = config.get(configSectionName, f'normType{suffix}')

kwargs = config.getexpression(configSectionName,
'normArgs{}'.format(suffix))
f'normArgs{suffix}')

if normType == 'symLog':
norm = cols.SymLogNorm(**kwargs)
Expand All @@ -368,12 +381,12 @@ def _setup_colormap_and_norm(config, configSectionName, suffix=''):
elif normType == 'linear':
norm = cols.Normalize(**kwargs)
else:
raise ValueError('Unsupported norm type {} in section {}'.format(
normType, configSectionName))
raise ValueError(f'Unsupported norm type {normType} in section '
f'{configSectionName}')

try:
ticks = config.getexpression(
configSectionName, 'colorbarTicks{}'.format(suffix),
configSectionName, f'colorbarTicks{suffix}',
use_numpyfunc=True)
except configparser.NoOptionError:
ticks = None
Expand Down Expand Up @@ -413,15 +426,15 @@ def _setup_indexed_colormap(config, configSectionName, suffix=''):
# Xylar Asay-Davis, Milena Veneziani, Greg Streletz

colormap = plt.get_cmap(config.get(configSectionName,
'colormapName{}'.format(suffix)))
f'colormapName{suffix}'))

indices = config.getexpression(configSectionName,
'colormapIndices{}'.format(suffix),
f'colormapIndices{suffix}',
use_numpyfunc=True)

try:
levels = config.getexpression(
configSectionName, 'colorbarLevels{}'.format(suffix),
configSectionName, f'colorbarLevels{suffix}',
use_numpyfunc=True)
except configparser.NoOptionError:
levels = None
Expand All @@ -440,15 +453,15 @@ def _setup_indexed_colormap(config, configSectionName, suffix=''):
raise ValueError('length mismatch between indices and '
'colorbarLevels')
colormap = cols.ListedColormap(colormap(indices),
'colormapName{}'.format(suffix))
f'colormapName{suffix}')
colormap.set_under(underColor)
colormap.set_over(overColor)

norm = cols.BoundaryNorm(levels, colormap.N)

try:
ticks = config.getexpression(
configSectionName, 'colorbarTicks{}'.format(suffix),
configSectionName, f'colorbarTicks{suffix}',
use_numpyfunc=True)
except configparser.NoOptionError:
ticks = levels
Expand Down
14 changes: 7 additions & 7 deletions mpas_analysis/shared/plot/vertical_section.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,15 +938,15 @@ def plot_vertical_section(
if colormapDict['levels'] is None:

plotHandle = plt.tripcolor(maskedTriangulation, fieldMasked,
cmap=colormapDict['colormap'],
norm=colormapDict['norm'],
rasterized=True, shading='gouraud')
cmap=colormapDict['colormap'],
norm=colormapDict['norm'],
rasterized=True, shading='gouraud')
else:
plotHandle = plt.tricontourf(maskedTriangulation, fieldMasked,
cmap=colormapDict['colormap'],
norm=colormapDict['norm'],
levels=colormapDict['levels'],
extend='both')
cmap=colormapDict['colormap'],
norm=colormapDict['norm'],
levels=colormapDict['levels'],
extend='both')

cbar = plt.colorbar(plotHandle,
orientation='vertical',
Expand Down

0 comments on commit 6757b32

Please sign in to comment.