Skip to content

Commit

Permalink
Updating time_height_scatter and more of the tests in the timeseries …
Browse files Browse the repository at this point in the history
…test module (#779)

* ENH: Updating tests for plotting to increase coverage

* ENH: Adding in more tests.  In the process, I updated the time_height_scatter function to be more robust and mimic the other plotting functions in ACT.  Also updating all the images for the timeseries tests.

* ENH: Updating plot/test
  • Loading branch information
AdamTheisen authored Dec 21, 2023
1 parent ae1add8 commit 8656754
Show file tree
Hide file tree
Showing 27 changed files with 232 additions and 27 deletions.
125 changes: 100 additions & 25 deletions act/plotting/timeseriesdisplay.py
Original file line number Diff line number Diff line change
Expand Up @@ -1256,11 +1256,16 @@ def plot_time_height_xsection_from_1d_data(
def time_height_scatter(
self,
data_field=None,
alt_field='alt',
dsname=None,
cmap='rainbow',
alt_label=None,
alt_field='alt',
cb_label=None,
subplot_index=(0,),
plot_alt_field=False,
cb_friendly=False,
day_night_background=False,
set_title=None,
**kwargs,
):
"""
Expand All @@ -1273,20 +1278,28 @@ def time_height_scatter(
----------
data_field : str
Name of data field in the dataset to plot on second y-axis.
height_field : str
Name of height field in the dataset to plot on first y-axis.
alt_field : str
Variable to use for y-axis.
dsname : str or None
The name of the datastream to plot.
cmap : str
Colorbar color map to use.
alt_label : str
Altitude first y-axis label to use. If None, will try to use
long_name and units.
alt_field : str
Label for field in the dataset to plot on first y-axis.
cb_label : str
Colorbar label to use. If not set will try to use
long_name and units.
subplot_index : 1 or 2D tuple, list, or array
The index of the subplot to set the x range of.
plot_alt_field : boolean
Set to true to plot the altitude field on the secondary y-axis
cb_friendly : boolean
If set to True will use the Homeyer colormap
day_night_background : boolean
If set to True will plot the day_night_background
set_title : str
Title to set on the plot
**kwargs : keyword arguments
Any other keyword arguments that will be passed
into TimeSeriesDisplay.plot module when the figure
Expand All @@ -1302,6 +1315,20 @@ def time_height_scatter(
elif dsname is None:
dsname = list(self._ds.keys())[0]

# Set up or get current plot figure
if self.fig is None:
self.fig = plt.figure()

# Set up or get current axes
if self.axes is None:
self.axes = np.array([plt.axes()])
self.fig.add_axes(self.axes[0])

if cb_friendly:
cmap = 'HomeyerRainbow'

ax = self.axes[subplot_index]

# Get data and dimensions
data = self._ds[dsname][data_field]
altitude = self._ds[dsname][alt_field]
Expand All @@ -1322,26 +1349,70 @@ def time_height_scatter(
except KeyError:
cb_label = data_field

colorbar_map = mpl.colormaps.get_cmap(cmap)
self.fig.subplots_adjust(left=0.1, right=0.86, bottom=0.16, top=0.91)
ax1 = self.plot(alt_field, color='black', **kwargs)
ax1.set_ylabel(alt_label)
ax2 = ax1.twinx()
sc = ax2.scatter(xdata.values, data.values, c=data.values, marker='.', cmap=colorbar_map)
cbaxes = self.fig.add_axes(
[
self.fig.subplotpars.right + 0.02,
self.fig.subplotpars.bottom,
0.02,
self.fig.subplotpars.top - self.fig.subplotpars.bottom,
]
)
cbar = plt.colorbar(sc, cax=cbaxes)
ax2.set_ylim(cbar.mappable.get_clim())
if 'units' in data.attrs:
ytitle = ''.join(['(', data.attrs['units'], ')'])
else:
ytitle = data_field

# Set Title
if set_title is None:
if isinstance(self._ds[dsname].time.values[0], np.datetime64):
set_title = ' '.join(
[
dsname,
data_field,
'on',
dt_utils.numpy_to_arm_date(self._ds[dsname].time.values[0]),
]
)
else:
date_result = search(
r'\d{4}-\d{1,2}-\d{1,2}', self._ds[dsname].time.attrs['units']
)
if date_result is not None:
set_title = ' '.join([dsname, data_field, 'on', date_result.group(0)])
else:
set_title = ' '.join([dsname, data_field])

# Plot scatter data
sc = ax.scatter(xdata.values, data.values, c=data.values, cmap=cmap, **kwargs)

ax.set_title(set_title)
if plot_alt_field:
self.fig.subplots_adjust(left=0.1, right=0.8, bottom=0.15, top=0.925)
pad = 0.02 + (0.02 * len(str(int(np.nanmax(altitude.values)))))
cbar = self.fig.colorbar(sc, pad=pad, cmap=cmap)

ax2 = ax.twinx()
ax2.set_ylabel(alt_label)
ax2.scatter(xdata.values, altitude.values, color='black')
else:
cbar = self.fig.colorbar(sc, cmap=cmap)

if day_night_background is True:
self.day_night_background(subplot_index=subplot_index, dsname=dsname)
cbar.ax.set_ylabel(cb_label)
ax2.set_yticklabels([])

return self.axes[0]
# Set X Limit - We want the same time axes for all subplots
self.time_rng = [xdata.min().values, xdata.max().values]
self.set_xrng(self.time_rng, subplot_index)

# Set X Format
if len(subplot_index) == 1:
days = self.xrng[subplot_index, 1] - self.xrng[subplot_index, 0]
else:
days = (
self.xrng[subplot_index[0], subplot_index[1], 1]
- self.xrng[subplot_index[0], subplot_index[1], 0]
)
myFmt = common.get_date_format(days)
ax.xaxis.set_major_formatter(myFmt)
ax.set_xlabel('Time (UTC)')
ax.set_ylabel(ytitle)

self.axes[subplot_index] = ax

return self.axes[subplot_index]

def qc_flag_block_plot(
self,
Expand Down Expand Up @@ -1401,8 +1472,11 @@ def qc_flag_block_plot(
if cb_friendly:
color_lookup['Bad'] = (0.9285714285714286, 0.7130901016453677, 0.7130901016453677)
color_lookup['Incorrect'] = (0.9285714285714286, 0.7130901016453677, 0.7130901016453677)
color_lookup['Not Failing'] = (0.0, 0.4240129715562796, 0.4240129715562796),
color_lookup['Acceptable'] = (0.0, 0.4240129715562796, 0.4240129715562796),
color_lookup['Not Failing'] = (0.0, 0.4240129715562796, 0.4240129715562796)
color_lookup['Acceptable'] = (0.0, 0.4240129715562796, 0.4240129715562796)
color_lookup['Indeterminate'] = (1.0, 0.6470588235294118, 0.0)
color_lookup['Suspect'] = (1.0, 0.6470588235294118, 0.0)
color_lookup['Missing'] = (0.6627450980392157, 0.6627450980392157, 0.6627450980392157)

if assessment_color is not None:
for asses, color in assessment_color.items():
Expand Down Expand Up @@ -1520,6 +1594,7 @@ def qc_flag_block_plot(
yvalues = self._ds[dsname][dims[1]].values

cMap = mplcolors.ListedColormap(plot_colors)
print(plot_colors)
mesh = ax.pcolormesh(
xvalues,
yvalues,
Expand Down
Binary file modified act/tests/plotting/baseline/test_2D_timeseries_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_2d_as_1d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_add_nan_line.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_assessment_overplot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_assessment_overplot_multi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_barb_sounding_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_colorbar_labels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_fill_between.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_match_ylimits_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_multidataset_plot_dict.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_multidataset_plot_tuple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_plot_barbs_from_u_v.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_plot_barbs_from_u_v2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_qc_bar_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_qc_flag_block_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_time_height_scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_time_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_time_plot2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_timeseries_invert.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_xlim_correction_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified act/tests/plotting/baseline/test_y_axis_flag_meanings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
109 changes: 107 additions & 2 deletions act/tests/plotting/test_timeseriesdisplay.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ def test_errors():
display.plot_barbs_from_spd_dir('wdir_vec_mean', 'wspd_vec_mean')
with np.testing.assert_raises(ValueError):
display.plot_barbs_from_u_v('wdir_vec_mean', 'wspd_vec_mean')
with np.testing.assert_raises(ValueError):
display.plot_time_height_xsection_from_1d_data('wdir_vec_mean', 'wspd_vec_mean')
with np.testing.assert_raises(ValueError):
display.time_height_scatter('wdir_vec_mean')

del ds.attrs['_file_dates']

Expand Down Expand Up @@ -192,11 +196,30 @@ def test_barb_sounding_plot():


# Due to issues with pytest-mpl, for now we just test to see if it runs
@pytest.mark.mpl_image_compare(tolerance=30)
def test_time_height_scatter():
sonde_ds = act.io.arm.read_arm_netcdf(sample_files.EXAMPLE_SONDE1)

display = TimeSeriesDisplay({'sgpsondewnpnC1.b1': sonde_ds}, figsize=(7, 3))
display.time_height_scatter('tdry', day_night_background=False)
display.time_height_scatter('tdry', plot_alt_field=True)

sonde_ds.close()

try:
return display.fig
finally:
matplotlib.pyplot.close(display.fig)


# Due to issues with pytest-mpl, for now we just test to see if it runs
@pytest.mark.mpl_image_compare(tolerance=30)
def test_time_height_scatter2():
sonde_ds = act.io.arm.read_arm_netcdf(sample_files.EXAMPLE_SONDE1)

display = TimeSeriesDisplay({'sgpsondewnpnC1.b1': sonde_ds}, figsize=(7, 6), subplot_shape=(2,))
display.time_height_scatter('tdry', day_night_background=True, subplot_index=(0,),
cb_friendly=True, plot_alt_field=True)
display.time_height_scatter('rh', day_night_background=True, subplot_index=(1,), cb_friendly=True)

sonde_ds.close()

Expand Down Expand Up @@ -281,7 +304,7 @@ def test_qc_flag_block_plot():

display.plot('surface_albedo_mfr_narrowband_10m', force_line_plot=True, labels=True)

display.qc_flag_block_plot('surface_albedo_mfr_narrowband_10m', subplot_index=(1,))
display.qc_flag_block_plot('surface_albedo_mfr_narrowband_10m', subplot_index=(1,), cb_friendly=True)

ds.close()
del ds
Expand Down Expand Up @@ -389,6 +412,88 @@ def test_plot_barbs_from_u_v2():
matplotlib.pyplot.close(BarbDisplay.fig)


def test_plot_barbs_from_u_v3():
bins = list(np.linspace(0, 1, 10))
xbins = list(pd.date_range(pd.to_datetime('2020-01-01'), pd.to_datetime('2020-01-02'), 12))
y_data = np.full([len(xbins), len(bins)], 1.0)
x_data = np.full([len(xbins), len(bins)], 2.0)
pres = np.linspace(1000, 0, len(bins))
y_array = xr.DataArray(y_data, dims={'xbins': xbins, 'ybins': bins}, attrs={'units': 'm/s'})
x_array = xr.DataArray(x_data, dims={'xbins': xbins, 'ybins': bins}, attrs={'units': 'm/s'})
xbins = xr.DataArray(xbins, dims={'xbins': xbins})
ybins = xr.DataArray(bins, dims={'ybins': bins})
pres = xr.DataArray(pres, dims={'ybins': bins}, attrs={'units': 'hPa'})
fake_ds = xr.Dataset({'xbins': xbins, 'ybins': ybins, 'ydata': y_array, 'xdata': x_array, 'pres': pres})
BarbDisplay = TimeSeriesDisplay(fake_ds)
BarbDisplay.plot_barbs_from_u_v(
'xdata',
'ydata',
None,
set_title='test',
use_var_for_y='pres'
)
fake_ds.close()
try:
return BarbDisplay.fig
finally:
matplotlib.pyplot.close(BarbDisplay.fig)


def test_plot_barbs_from_u_v4():
bins = list(np.linspace(0, 1, 10))
xbins = [pd.to_datetime('2020-01-01')]
y_data = np.full([1], 1.0)
x_data = np.full([1], 2.0)
pres = np.linspace(1000, 0, len(bins))
y_array = xr.DataArray(y_data, dims={'xbins': xbins}, attrs={'units': 'm/s'})
x_array = xr.DataArray(x_data, dims={'xbins': xbins}, attrs={'units': 'm/s'})
xbins = xr.DataArray(xbins, dims={'xbins': xbins})
ybins = xr.DataArray(bins, dims={'ybins': bins})
pres = xr.DataArray(pres, dims={'ybins': bins}, attrs={'units': 'hPa'})
fake_ds = xr.Dataset({'xbins': xbins, 'ybins': ybins, 'ydata': y_array, 'xdata': x_array, 'pres': pres})
BarbDisplay = TimeSeriesDisplay(fake_ds)
BarbDisplay.plot_barbs_from_u_v(
'xdata',
'ydata',
None,
set_title='test',
use_var_for_y='pres',
cmap='jet'
)
fake_ds.close()
try:
return BarbDisplay.fig
finally:
matplotlib.pyplot.close(BarbDisplay.fig)


def test_plot_barbs_from_u_v5():
bins = list(np.linspace(0, 1, 10))
xbins = [pd.to_datetime('2020-01-01')]
y_data = np.full([1], 1.0)
x_data = np.full([1], 2.0)
pres = np.linspace(1000, 0, len(bins))
y_array = xr.DataArray(y_data, dims={'xbins': xbins}, attrs={'units': 'm/s'})
x_array = xr.DataArray(x_data, dims={'xbins': xbins}, attrs={'units': 'm/s'})
xbins = xr.DataArray(xbins, dims={'xbins': xbins})
ybins = xr.DataArray(bins, dims={'ybins': bins})
pres = xr.DataArray(pres, dims={'ybins': bins}, attrs={'units': 'hPa'})
fake_ds = xr.Dataset({'xbins': xbins, 'ybins': ybins, 'ydata': y_array, 'xdata': x_array, 'pres': pres})
BarbDisplay = TimeSeriesDisplay(fake_ds)
BarbDisplay.plot_barbs_from_u_v(
'xdata',
'ydata',
None,
set_title='test',
use_var_for_y='pres',
)
fake_ds.close()
try:
return BarbDisplay.fig
finally:
matplotlib.pyplot.close(BarbDisplay.fig)


@pytest.mark.mpl_image_compare(tolerance=30)
def test_2D_timeseries_plot():
ds = act.io.arm.read_arm_netcdf(sample_files.EXAMPLE_CEIL1)
Expand Down
25 changes: 25 additions & 0 deletions examples/plotting/plot_time_height_scatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Time-Height Scatter Plot
------------------------
This will show how to use the time-height scatter
plot function that's part of the TimeSeries Display.
"""

import os
from arm_test_data import DATASETS
import matplotlib.pyplot as plt
import act
from act.tests import sample_files

# Read in radiosonde data
ds = act.io.arm.read_arm_netcdf(sample_files.EXAMPLE_SONDE1)

# Create scatter plots of the sonde data
display = act.plotting.TimeSeriesDisplay(ds, figsize=(7, 6), subplot_shape=(2,))
display.time_height_scatter('tdry', plot_alt_field=True, subplot_index=(0,))
display.time_height_scatter('rh', subplot_index=(1,), cb_friendly=True, day_night_background=True)
plt.tight_layout()
ds.close()

plt.show()

0 comments on commit 8656754

Please sign in to comment.