Skip to content

Commit

Permalink
Expand batch plots to support processing by level (#157)
Browse files Browse the repository at this point in the history
* Ref #152

Add level components, streamline level, channel, scan.

* Ref #152

Rm unnecessary yaxis pseudo-data.

* Revert "Ref #152"

This reverts commit 40b5a49.

* Ref #152
Reduce marker psuedo data to single variable.

* Ref #156

Update figure_driver to parse level in addition to channel.

* Ref #156

Eliminate pycode complaints.

* Ref #156

Add title mod variable for channel/level.

* Ref #156

Make requested changes.

* Ref #156

Fix no plots for datasets with no channels.

* Ref #156

Fix code review items.
  • Loading branch information
EdwardSafford-NOAA authored Sep 25, 2023
1 parent a09c852 commit 3cdabcc
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 33 deletions.
61 changes: 41 additions & 20 deletions src/eva/data/data_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ def add_variable_to_collection(self, collection_name, group_name, variable_name,

# ----------------------------------------------------------------------------------------------

def get_variable_data_array(self, collection_name, group_name, variable_name, channels=None):
def get_variable_data_array(self, collection_name, group_name, variable_name,
channels=None, levels=None):

"""
Retrieve a specific variable (as a DataArray) from a collection.
Expand All @@ -179,6 +180,7 @@ def get_variable_data_array(self, collection_name, group_name, variable_name, ch
group_name (str): Name of the group where the variable belongs.
variable_name (str): Name of the variable.
channels (int or list[int]): Indices of channels to select (optional).
levels (int or list[int]): Indices of levels to select (optional).
Returns:
DataArray: The selected variable as an xarray DataArray.
Expand All @@ -188,31 +190,49 @@ def get_variable_data_array(self, collection_name, group_name, variable_name, ch
"""

group_variable_name = group_name + '::' + variable_name

data_array = self._collections[collection_name][group_variable_name]

if channels is None:
if channels is None and levels is None:
return data_array
elif isinstance(channels, int) or not any(not isinstance(c, int) for c in channels):
# Channel must be a dimension if it will be used for selection
if 'Channel' not in list(self._collections[collection_name].dims):
self.logger.abort(f'In get_variable_data_array channels is provided but ' +
f'Channel is not a dimension in Dataset')
# Make sure it is a list
channels_sel = []
channels_sel.append(channels)

# Create a new DataArray with the requested channels
data_array_channels = data_array.sel(Channel=channels_sel)
return data_array_channels

else:
self.logger.abort('In get_variable_data_array channels is neither none or list of ' +
'integers')
if channels is not None:
if isinstance(channels, int) or not any(not isinstance(c, int) for c in channels):
# Channel must be a dimension if it will be used for selection
if 'Channel' not in list(self._collections[collection_name].dims):
self.logger.abort(f'In get_variable_data_array channels is provided but ' +
f'Channel is not a dimension in Dataset')
# Make sure it is a list
channels_sel = []
channels_sel.append(channels)

# Create a new DataArray with the requested channels
data_array_channels = data_array.sel(Channel=channels_sel)
return data_array_channels
else:
self.logger.abort('In get_variable_data_array channels is neither none ' +
'nor a list of integers')

elif levels is not None:
if isinstance(levels, int) or not any(not isinstance(lev, int) for lev in levels):
# Level must be a dimension if it will be used for selection
if 'Level' not in list(self._collections[collection_name].dims):
self.logger.abort(f'In get_variable_data_array levels is provided but ' +
f'Level is not a dimension in Dataset')
# Make sure it is a list
levels_sel = []
levels_sel.append(levels)

# Create a new DataArray with the requested channels
data_array_levels = data_array.sel(Level=levels_sel)
return data_array_levels
else:
self.logger.abort('In get_variable_data_array levels is neither none ' +
'nor a list of integers')

# ----------------------------------------------------------------------------------------------

def get_variable_data(self, collection_name, group_name, variable_name, channels=None):
def get_variable_data(self, collection_name, group_name, variable_name,
channels=None, levels=None):

"""
Retrieve the data of a specific variable from a collection.
Expand All @@ -222,13 +242,14 @@ def get_variable_data(self, collection_name, group_name, variable_name, channels
group_name (str): Name of the group where the variable belongs.
variable_name (str): Name of the variable.
channels (int or list[int]): Indices of channels to select (optional).
levels (int or list[int]): Indices of levels to select (optional).
Returns:
ndarray: The selected variable data as a NumPy array.
"""

variable_array = self.get_variable_data_array(collection_name, group_name, variable_name,
channels)
channels, levels)

# Extract the actual data array
variable_data = variable_array.data
Expand Down
11 changes: 7 additions & 4 deletions src/eva/plotting/emcpy/diagnostics/line_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ def __init__(self, config, logger, dataobj):
logger.abort('In Scatter comparison the first variable \'var1\' does not appear to ' +
'be in the required format of collection::group::variable.')

# Optionally get the channel to plot
# Optionally get the channel|level to plot
channel = None
if 'channel' in config:
channel = config.get('channel')
level = None
if 'level' in config:
level = config.get('level')

xdata = dataobj.get_variable_data(var0_cgv[0], var0_cgv[1], var0_cgv[2], channel)
ydata = dataobj.get_variable_data(var1_cgv[0], var1_cgv[1], var1_cgv[2], channel)
xdata = dataobj.get_variable_data(var0_cgv[0], var0_cgv[1], var0_cgv[2], channel, level)
ydata = dataobj.get_variable_data(var1_cgv[0], var1_cgv[1], var1_cgv[2], channel, level)

# see if we need to slice data
xdata = slice_var_from_str(config['x'], xdata, logger)
Expand Down Expand Up @@ -93,7 +96,7 @@ def __init__(self, config, logger, dataobj):
layer_schema = config.get('schema', os.path.join(return_eva_path(), 'plotting',
'emcpy', 'defaults', 'line_plot.yaml'))
config = get_schema(layer_schema, config, logger)
delvars = ['x', 'y', 'type', 'schema', 'channel']
delvars = ['x', 'y', 'type', 'schema', 'channel', 'level']
for d in delvars:
config.pop(d, None)
self.plotobj = update_object(self.plotobj, config, logger)
Expand Down
33 changes: 24 additions & 9 deletions src/eva/plotting/emcpy/plot_tools/figure_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,40 @@ def figure_driver(config, data_collections, timing, logger):
if batch_conf:
# Get potential variables
variables = batch_conf.get('variables', [])
# Get list of channels

# Get list of channels and load step variables
channels_str_or_list = batch_conf.get('channels', [])
channels = parse_channel_list(channels_str_or_list, logger)

step_vars = channels if channels else ['none']
step_var_name = 'channel'
title_fill = ' Ch. '

# Get list of levels, conditionally override step variables
levels_str_or_list = batch_conf.get('levels', [])
levels = parse_channel_list(levels_str_or_list, logger)
if levels:
step_vars = levels
step_var_name = 'level'
title_fill = ' Lev. '

# Set some fake values to ensure the loops are entered
if variables == []:
if not variables:
logger.abort("Batch Figure must provide variables, even if with channels")
if channels == []:
channels = ['none']

# Loop over variables and channels
for variable in variables:
for channel in channels:
for step_var in step_vars:
batch_conf_this = {}
batch_conf_this['variable'] = variable

# Version to be used in titles
batch_conf_this['variable_title'] = variable.replace('_', ' ').title()
channel_str = str(channel)
if channel_str != 'none':
batch_conf_this['channel'] = channel_str
var_title = batch_conf_this['variable_title'] + ' Ch. ' + channel_str

step_var_str = str(step_var)
if step_var_str != 'none':
batch_conf_this[step_var_name] = step_var_str
var_title = batch_conf_this['variable_title'] + title_fill + step_var_str
batch_conf_this['variable_title'] = var_title

# Replace templated variables in figure and plots config
Expand All @@ -100,6 +113,7 @@ def figure_driver(config, data_collections, timing, logger):
# Make plot
make_figure(figure_conf_fill, plots_conf_fill,
dynamic_options_conf_fill, data_collections, logger)

else:
# make just one figure per configuration
make_figure(figure_conf, plots_conf, dynamic_options_conf, data_collections, logger)
Expand Down Expand Up @@ -175,6 +189,7 @@ def make_figure(figure_conf, plots, dynamic_options, data_collections, logger):
stats_helper(logger, plotobj, data_collections, value)

plot_list.append(plotobj)

# create figure
fig = CreateFigure(nrows=figure_conf['layout'][0],
ncols=figure_conf['layout'][1],
Expand Down

0 comments on commit 3cdabcc

Please sign in to comment.