cubevis 0.5.14__py3-none-any.whl → 0.5.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cubevis might be problematic. Click here for more details.
- cubevis/__version__.py +1 -1
- cubevis/private/apps/__init__.py +5 -1
- cubevis/private/apps/_createmask.py +6 -6
- cubevis/private/apps/_createregion.py +5 -5
- {cubevis-0.5.14.dist-info → cubevis-0.5.16.dist-info}/METADATA +1 -1
- {cubevis-0.5.14.dist-info → cubevis-0.5.16.dist-info}/RECORD +8 -28
- cubevis/data/measurement_set/__init__.py +0 -7
- cubevis/data/measurement_set/_ms_data.py +0 -178
- cubevis/data/measurement_set/processing_set/__init__.py +0 -30
- cubevis/data/measurement_set/processing_set/_ps_concat.py +0 -98
- cubevis/data/measurement_set/processing_set/_ps_coords.py +0 -78
- cubevis/data/measurement_set/processing_set/_ps_data.py +0 -213
- cubevis/data/measurement_set/processing_set/_ps_io.py +0 -55
- cubevis/data/measurement_set/processing_set/_ps_raster_data.py +0 -154
- cubevis/data/measurement_set/processing_set/_ps_select.py +0 -91
- cubevis/data/measurement_set/processing_set/_ps_stats.py +0 -218
- cubevis/data/measurement_set/processing_set/_xds_data.py +0 -149
- cubevis/plot/__init__.py +0 -1
- cubevis/plot/ms_plot/__init__.py +0 -29
- cubevis/plot/ms_plot/_ms_plot.py +0 -242
- cubevis/plot/ms_plot/_ms_plot_constants.py +0 -22
- cubevis/plot/ms_plot/_ms_plot_selectors.py +0 -348
- cubevis/plot/ms_plot/_raster_plot.py +0 -292
- cubevis/plot/ms_plot/_raster_plot_inputs.py +0 -116
- cubevis/plot/ms_plot/_xds_plot_axes.py +0 -110
- cubevis/private/apps/_ms_raster.py +0 -815
- {cubevis-0.5.14.dist-info → cubevis-0.5.16.dist-info}/WHEEL +0 -0
- {cubevis-0.5.14.dist-info → cubevis-0.5.16.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,815 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
Implementation of the ``MsRaster`` application for measurement set raster plotting and editing
|
|
3
|
-
'''
|
|
4
|
-
|
|
5
|
-
import time
|
|
6
|
-
|
|
7
|
-
from bokeh.models.formatters import NumeralTickFormatter
|
|
8
|
-
import holoviews as hv
|
|
9
|
-
import numpy as np
|
|
10
|
-
import panel as pn
|
|
11
|
-
from pandas import to_datetime
|
|
12
|
-
|
|
13
|
-
from cubevis.bokeh.format import get_time_formatter
|
|
14
|
-
from cubevis.bokeh.state._palette import available_palettes
|
|
15
|
-
from cubevis.plot.ms_plot._ms_plot import MsPlot
|
|
16
|
-
from cubevis.plot.ms_plot._ms_plot_constants import VIS_AXIS_OPTIONS, SPECTRUM_AXIS_OPTIONS
|
|
17
|
-
from cubevis.plot.ms_plot._ms_plot_selectors import (file_selector, title_selector, style_selector, axis_selector,
|
|
18
|
-
aggregation_selector, iteration_selector, selection_selector, plot_starter)
|
|
19
|
-
from cubevis.plot.ms_plot._raster_plot_inputs import check_inputs
|
|
20
|
-
from cubevis.plot.ms_plot._raster_plot import RasterPlot
|
|
21
|
-
|
|
22
|
-
class MsRaster(MsPlot):
|
|
23
|
-
'''
|
|
24
|
-
Plot MeasurementSet data as raster plot.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
ms (str): path to MSv2 (.ms) or MSv4 (.zarr) file. Required when show_gui=False.
|
|
28
|
-
log_level (str): logging threshold. Options include 'debug', 'info', 'warning', 'error', 'critical'. Default 'info'.
|
|
29
|
-
show_gui (bool): whether to launch the interactive GUI in a browser tab. Default False.
|
|
30
|
-
|
|
31
|
-
Example:
|
|
32
|
-
from cubevis.plots import MsRaster
|
|
33
|
-
msr = MsRaster(ms='myvis.ms')
|
|
34
|
-
msr.summary()
|
|
35
|
-
msr.set_style_params(unflagged_cmap='Plasma', flagged_cmap='Greys', show_colorbar=True)
|
|
36
|
-
msr.plot(x_axis='frequency', y_axis='time', vis_axis='amp', data_group='base')
|
|
37
|
-
msr.show()
|
|
38
|
-
msr.save() # saves as {ms name}_raster.png
|
|
39
|
-
'''
|
|
40
|
-
|
|
41
|
-
def __init__(self, ms=None, log_level="info", show_gui=False):
|
|
42
|
-
super().__init__(ms, log_level, show_gui, "MsRaster")
|
|
43
|
-
self._raster_plot = RasterPlot()
|
|
44
|
-
|
|
45
|
-
# Calculations for color limits
|
|
46
|
-
self._spw_stats = {}
|
|
47
|
-
self._spw_color_limits = {}
|
|
48
|
-
|
|
49
|
-
if show_gui:
|
|
50
|
-
# GUI based on panel widgets
|
|
51
|
-
self._gui_layout = None
|
|
52
|
-
|
|
53
|
-
# Check if plot inputs changed and new plot is needed.
|
|
54
|
-
# GUI can change subparams which do not change plot
|
|
55
|
-
self._last_plot_inputs = None
|
|
56
|
-
self._last_style_inputs = None
|
|
57
|
-
# Last plot when no new plot created (plot inputs same) or is iter Layout plot (opened in tab)
|
|
58
|
-
self._last_gui_plot = None
|
|
59
|
-
|
|
60
|
-
# Return plot for gui DynamicMap:
|
|
61
|
-
# Empty plot when ms not set or plot fails
|
|
62
|
-
self._empty_plot = self._create_empty_plot()
|
|
63
|
-
|
|
64
|
-
# Set default style and plot inputs to use when launching gui
|
|
65
|
-
self.set_style_params()
|
|
66
|
-
self.plot()
|
|
67
|
-
self._launch_gui()
|
|
68
|
-
|
|
69
|
-
# Set filename TextInput to input ms to trigger plot
|
|
70
|
-
if 'ms' in self._ms_info and self._ms_info['ms']:
|
|
71
|
-
self._set_filename([self._ms_info['ms']]) # function expects list
|
|
72
|
-
|
|
73
|
-
def colormaps(self):
|
|
74
|
-
''' List available colormap (Bokeh palettes). '''
|
|
75
|
-
return available_palettes()
|
|
76
|
-
|
|
77
|
-
def set_style_params(self, unflagged_cmap='Viridis', flagged_cmap='Reds', show_colorbar=True, show_flagged_colorbar=True):
|
|
78
|
-
'''
|
|
79
|
-
Set styling parameters for the plot, such as colormaps and whether to show colorbar.
|
|
80
|
-
Placeholder for future styling such as fonts.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
unflagged_cmap (str): colormap to use for unflagged data.
|
|
84
|
-
flagged_cmap (str): colormap to use for flagged data.
|
|
85
|
-
show_colorbar (bool): Whether to show colorbar with plot. Default True.
|
|
86
|
-
'''
|
|
87
|
-
cmaps = self.colormaps()
|
|
88
|
-
if unflagged_cmap not in cmaps:
|
|
89
|
-
raise ValueError(f"{unflagged_cmap} not in colormaps list: {cmaps}")
|
|
90
|
-
if flagged_cmap not in cmaps:
|
|
91
|
-
raise ValueError(f"{flagged_cmap} not in colormaps list: {cmaps}")
|
|
92
|
-
self._raster_plot.set_style_params(unflagged_cmap, flagged_cmap, show_colorbar, show_flagged_colorbar)
|
|
93
|
-
|
|
94
|
-
# pylint: disable=too-many-arguments, too-many-positional-arguments, too-many-locals, unused-argument
|
|
95
|
-
def plot(self, x_axis='baseline', y_axis='time', vis_axis='amp', selection=None, aggregator=None, agg_axis=None,
|
|
96
|
-
iter_axis=None, iter_range=None, subplots=None, color_mode=None, color_range=None, title=None, clear_plots=True):
|
|
97
|
-
'''
|
|
98
|
-
Create a raster plot of vis_axis data in the data_group after applying selection.
|
|
99
|
-
Plot axes include data dimensions (time, baseline/antenna, frequency, polarization).
|
|
100
|
-
Dimensions not set as plot axes can be selected, else the first value will be used, unless aggregated.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
x_axis (str): Plot x-axis. Default 'baseline' ('antenna_name' for spectrum data).
|
|
104
|
-
y_axis (str): Plot y-axis. Default 'time'.
|
|
105
|
-
vis_axis (str): Complex visibility component to plot (amp, phase, real, imag). Default 'amp'.
|
|
106
|
-
Call data_groups() to see options.
|
|
107
|
-
selection (dict): selected data to plot. Options include:
|
|
108
|
-
ProcessingSet selection: by summary column names. Call summary() to see options.
|
|
109
|
-
'query': for pandas query of summary() columns.
|
|
110
|
-
Default: select first spw (by id).
|
|
111
|
-
MeasurementSet selection:
|
|
112
|
-
'data_group': name for correlated data, flags, weights, and uvw. Default value 'base'.
|
|
113
|
-
Use data_groups() to get data group names.
|
|
114
|
-
Dimensions:
|
|
115
|
-
Visibility dimensions: 'baseline' 'time', 'frequency', 'polarization'
|
|
116
|
-
Spectrum dimensions: 'antenna_name', 'time', 'frequency', 'polarization'
|
|
117
|
-
Default value is index 0 (after user selection) for non-axis dimensions unless aggregated.
|
|
118
|
-
Use antennas() to get antenna names. Select 'baseline' as "<name1> & <name2>".
|
|
119
|
-
Use summary() to list frequencies and polarizations.
|
|
120
|
-
TODO: how to select time?
|
|
121
|
-
aggregator (str): reduction for rasterization. Default None.
|
|
122
|
-
Options include 'max', 'mean', 'min', 'std', 'sum', 'var'.
|
|
123
|
-
agg_axis (str, list): which dimension to apply aggregator across. Default None.
|
|
124
|
-
Options include one or more dimensions.
|
|
125
|
-
If agg_axis is None and aggregator is set, aggregates over all non-axis dimensions.
|
|
126
|
-
If one agg_axis is selected, the non-agg dimension will be selected.
|
|
127
|
-
iter_axis (str): dimension over which to iterate values (using iter_range).
|
|
128
|
-
iter_range (tuple): (start, end) inclusive index values for iteration plots.
|
|
129
|
-
Default (0, 0) (first iteration only). Use (0, -1) for all iterations.
|
|
130
|
-
If subplots is a grid, the range is limited by the grid size.
|
|
131
|
-
If subplots is a single plot, all iteration plots in the range can be saved using export_range in save().
|
|
132
|
-
subplots (None, tuple): set a grid of (rows, columns). None = (1, 1) for single plot.
|
|
133
|
-
Use with iter_axis and iter_range, or clear_plots=False.
|
|
134
|
-
If used in multiple calls, the last subplots tuple will be used to determine grid to show or save.
|
|
135
|
-
color_mode (None, str): Whether to limit range of colorbar. Default None (no limit).
|
|
136
|
-
Options include None (use data limits), 'auto' (calculate limits for amplitude), and 'manual' (use range in color_range).
|
|
137
|
-
'auto' is equivalent to None if vis_axis is not 'amp'.
|
|
138
|
-
When subplots is set, the 'auto' or 'manual' range will be used for all plots.
|
|
139
|
-
color_range (tuple): (min, max) of colorbar to use if color_mode is 'manual'.
|
|
140
|
-
title (str): Plot title, default None (no title)
|
|
141
|
-
Set title='ms' to generate title from ms name and iter_axis value, if any.
|
|
142
|
-
clear_plots (bool): whether to clear list of plots. Default True.
|
|
143
|
-
|
|
144
|
-
If not show_gui and plotting is successful, use show() or save() to view/save the plot only.
|
|
145
|
-
'''
|
|
146
|
-
inputs = locals() # collect arguments into dict (not unused as pylint complains!)
|
|
147
|
-
|
|
148
|
-
start = time.time()
|
|
149
|
-
|
|
150
|
-
# Clear for new plot
|
|
151
|
-
self._reset_plot(clear_plots)
|
|
152
|
-
|
|
153
|
-
# Get data dimensions if valid MS is set to check input axes
|
|
154
|
-
if 'data_dims' in self._ms_info:
|
|
155
|
-
data_dims = self._ms_info['data_dims']
|
|
156
|
-
if 'baseline_id' in data_dims:
|
|
157
|
-
data_dims.remove('baseline_id')
|
|
158
|
-
data_dims.append('baseline')
|
|
159
|
-
inputs['data_dims'] = data_dims
|
|
160
|
-
|
|
161
|
-
# Validate input arguments; data dims needed to check input and rename baseline dimension
|
|
162
|
-
check_inputs(inputs)
|
|
163
|
-
self._plot_inputs = inputs
|
|
164
|
-
|
|
165
|
-
# Copy user selection dict; selection will be modified for plot
|
|
166
|
-
if inputs['selection']:
|
|
167
|
-
self._plot_inputs['selection'] = inputs['selection'].copy()
|
|
168
|
-
|
|
169
|
-
if not self._show_gui:
|
|
170
|
-
# Cannot plot if no MS
|
|
171
|
-
if not self._data or not self._data.is_valid():
|
|
172
|
-
raise RuntimeError("Cannot plot MS: input MS path is invalid or missing.")
|
|
173
|
-
|
|
174
|
-
# Create raster plot and add to plot list
|
|
175
|
-
try:
|
|
176
|
-
if self._plot_inputs['iter_axis']:
|
|
177
|
-
self._do_iter_plot(self._plot_inputs)
|
|
178
|
-
else:
|
|
179
|
-
plot = self._do_plot(self._plot_inputs)
|
|
180
|
-
self._plots.append(plot)
|
|
181
|
-
except RuntimeError as e:
|
|
182
|
-
error = f"Plot failed: {str(e)}"
|
|
183
|
-
super()._notify(error, "error", 0)
|
|
184
|
-
|
|
185
|
-
self._logger.debug("Plot elapsed time: %.2fs.", time.time() - start)
|
|
186
|
-
# pylint: enable=too-many-arguments, too-many-positional-arguments, too-many-locals, unused-argument
|
|
187
|
-
|
|
188
|
-
def save(self, filename='', fmt='auto', width=900, height=600):
|
|
189
|
-
'''
|
|
190
|
-
Save plot to file.
|
|
191
|
-
|
|
192
|
-
Args:
|
|
193
|
-
filename (str): Name of file to save. Default '': the plot will be saved as {ms}_raster.{ext}.
|
|
194
|
-
If fmt is not set for extension, plot will be saved as .png.
|
|
195
|
-
fmt (str): Format of file to save ('png', 'svg', 'html', or 'gif').
|
|
196
|
-
Default 'auto': inferred from filename extension.
|
|
197
|
-
width (int): width of exported plot.
|
|
198
|
-
height (int): height of exported plot.
|
|
199
|
-
|
|
200
|
-
If iteration plots were created:
|
|
201
|
-
If subplots is a grid, the layout plot will be saved to a single file.
|
|
202
|
-
If subplots is a single plot, iteration plots will be saved individually,
|
|
203
|
-
with a plot index appended to the filename: {filename}_{index}.{ext}.
|
|
204
|
-
'''
|
|
205
|
-
if not filename:
|
|
206
|
-
filename = f"{self._ms_info['basename']}_raster.png"
|
|
207
|
-
super().save(filename, fmt, width, height)
|
|
208
|
-
|
|
209
|
-
def _do_plot(self, plot_inputs):
|
|
210
|
-
''' Create plot using plot inputs '''
|
|
211
|
-
if not self._plot_init:
|
|
212
|
-
self._init_plot(plot_inputs)
|
|
213
|
-
|
|
214
|
-
# Select vis_axis data to plot and update selection; returns xarray Dataset
|
|
215
|
-
raster_data = self._data.get_raster_data(plot_inputs)
|
|
216
|
-
|
|
217
|
-
# Add params needed for plot: auto color range and ms name
|
|
218
|
-
self._set_auto_color_range(plot_inputs) # set calculated limits if auto mode
|
|
219
|
-
ms_name = self._ms_info['basename'] # for title
|
|
220
|
-
self._raster_plot.set_plot_params(raster_data, plot_inputs, ms_name)
|
|
221
|
-
|
|
222
|
-
# Make plot. Add data min/max if GUI is shown to update color limits range.
|
|
223
|
-
return self._raster_plot.raster_plot(raster_data, self._logger, self._show_gui)
|
|
224
|
-
|
|
225
|
-
def _do_iter_plot(self, plot_inputs):
|
|
226
|
-
''' Create one plot per iteration value in iter_range which fits into subplots '''
|
|
227
|
-
# Default (0, 0) (first iteration only). Use (0, -1) for all iterations.
|
|
228
|
-
# If subplots is a grid, end iteration index is limited by the grid size.
|
|
229
|
-
# If subplots is a single plot, all iteration plots in the range can be saved using export_range in save().
|
|
230
|
-
iter_axis = plot_inputs['iter_axis']
|
|
231
|
-
iter_range = plot_inputs['iter_range']
|
|
232
|
-
subplots = plot_inputs['subplots']
|
|
233
|
-
|
|
234
|
-
iter_range = (0, 0) if iter_range is None else iter_range
|
|
235
|
-
start_idx, end_idx = iter_range
|
|
236
|
-
|
|
237
|
-
# Init plot before getting iter values
|
|
238
|
-
self._init_plot(plot_inputs)
|
|
239
|
-
|
|
240
|
-
iter_values = self._data.get_dimension_values(iter_axis)
|
|
241
|
-
n_iter = len(iter_values)
|
|
242
|
-
|
|
243
|
-
if start_idx >= n_iter:
|
|
244
|
-
raise IndexError(f"iter_range start {start_idx} is greater than number of iterations {n_iter}")
|
|
245
|
-
end_idx = n_iter if (end_idx == -1 or end_idx >= n_iter) else end_idx + 1
|
|
246
|
-
num_iter_plots = end_idx - start_idx
|
|
247
|
-
|
|
248
|
-
# Plot the minimum of iter range or subplots number of plots
|
|
249
|
-
num_subplots = np.prod(subplots) if subplots else 1
|
|
250
|
-
num_iter_plots = min(num_iter_plots, num_subplots) if num_subplots > 1 else num_iter_plots
|
|
251
|
-
end_idx = start_idx + num_iter_plots
|
|
252
|
-
|
|
253
|
-
for i in range(start_idx, end_idx):
|
|
254
|
-
# Select iteration value and make plot
|
|
255
|
-
value = iter_values[i]
|
|
256
|
-
self._logger.info("Plot %s iteration index %s value %s", iter_axis, i, value)
|
|
257
|
-
plot_inputs['selection'][iter_axis] = value
|
|
258
|
-
try:
|
|
259
|
-
plot = self._do_plot(plot_inputs)
|
|
260
|
-
self._plots.append(plot)
|
|
261
|
-
except RuntimeError as e:
|
|
262
|
-
self._logger.info("Iteration plot for value %s failed: %s", str(value), str(e))
|
|
263
|
-
continue
|
|
264
|
-
|
|
265
|
-
def _init_plot(self, plot_inputs):
|
|
266
|
-
''' Apply automatic selection '''
|
|
267
|
-
# Apply user + data_group selection, then select first spw
|
|
268
|
-
# Set data group and name of its correlated data
|
|
269
|
-
self._set_data_group(plot_inputs)
|
|
270
|
-
|
|
271
|
-
# Do selection and add spw
|
|
272
|
-
self._data.select_data(plot_inputs['selection'])
|
|
273
|
-
self._select_first_spw(plot_inputs)
|
|
274
|
-
|
|
275
|
-
# Clear automatic or iter selection of unplotted dimensions
|
|
276
|
-
if 'dim_selection' in self._plot_inputs:
|
|
277
|
-
del self._plot_inputs['dim_selection']
|
|
278
|
-
|
|
279
|
-
self._plot_init = True
|
|
280
|
-
|
|
281
|
-
# Print data info for spw selection
|
|
282
|
-
self._logger.info("Plotting %s msv4 datasets.", self._data.get_num_ms())
|
|
283
|
-
self._logger.info("Maximum dimensions for selected spw: %s", self._data.get_max_data_dims())
|
|
284
|
-
|
|
285
|
-
def _select_first_spw(self, plot_inputs):
|
|
286
|
-
''' Determine first spw if not in user selection '''
|
|
287
|
-
if 'spw_name' not in plot_inputs['selection']:
|
|
288
|
-
first_spw = self._data.get_first_spw()
|
|
289
|
-
self._data.select_data({'spw_name': first_spw})
|
|
290
|
-
plot_inputs['selection']['spw_name'] = first_spw
|
|
291
|
-
|
|
292
|
-
def _set_auto_color_range(self, plot_inputs):
|
|
293
|
-
''' Calculate stats for color limits for non-gui amplitude plots. '''
|
|
294
|
-
color_mode = plot_inputs['color_mode']
|
|
295
|
-
color_limits = None
|
|
296
|
-
|
|
297
|
-
if color_mode == 'auto':
|
|
298
|
-
if plot_inputs['vis_axis']=='amp' and not plot_inputs['aggregator']:
|
|
299
|
-
# For amplitude, limit colorbar range using stored per-spw ms stats
|
|
300
|
-
spw_name = plot_inputs['selection']['spw_name']
|
|
301
|
-
if spw_name in self._spw_color_limits:
|
|
302
|
-
color_limits = self._spw_color_limits[spw_name]
|
|
303
|
-
else:
|
|
304
|
-
# Select spw name and data group only
|
|
305
|
-
spw_data_selection = {'spw_name': spw_name, 'data_group_name': plot_inputs['selection']['data_group_name']}
|
|
306
|
-
color_limits = self._calc_amp_color_limits(spw_data_selection)
|
|
307
|
-
self._spw_color_limits[spw_name] = color_limits
|
|
308
|
-
plot_inputs['auto_color_range'] = color_limits
|
|
309
|
-
|
|
310
|
-
if color_limits:
|
|
311
|
-
self._logger.info("Setting amplitude color range: (%.4f, %.4f).", color_limits[0], color_limits[1])
|
|
312
|
-
elif color_mode is None:
|
|
313
|
-
self._logger.info("Autoscale color range")
|
|
314
|
-
else:
|
|
315
|
-
self._logger.info("Using manual color range: %s", plot_inputs['color_range'])
|
|
316
|
-
|
|
317
|
-
def _calc_amp_color_limits(self, selection):
|
|
318
|
-
# Calculate colorbar limits from amplitude stats for unflagged data in selected spw
|
|
319
|
-
self._logger.info("Calculating stats for colorbar limits.")
|
|
320
|
-
start = time.time()
|
|
321
|
-
|
|
322
|
-
ms_stats = self._data.get_vis_stats(selection, 'amp')
|
|
323
|
-
self._spw_stats['spw_name'] = ms_stats
|
|
324
|
-
if not ms_stats:
|
|
325
|
-
return None # autoscale
|
|
326
|
-
|
|
327
|
-
min_val, max_val, mean, std = ms_stats
|
|
328
|
-
|
|
329
|
-
data_min = min(0.0, min_val)
|
|
330
|
-
clip_min = max(data_min, mean - (3.0 * std))
|
|
331
|
-
data_max = max(0.0, max_val)
|
|
332
|
-
clip_max = min(data_max, mean + (3.0 * std))
|
|
333
|
-
|
|
334
|
-
if clip_min == 0.0 and clip_max == 0.0:
|
|
335
|
-
color_limits = None # flagged data only
|
|
336
|
-
else:
|
|
337
|
-
color_limits = (clip_min, clip_max)
|
|
338
|
-
self._logger.debug("Stats elapsed time: %.2fs.", time.time() - start)
|
|
339
|
-
return color_limits
|
|
340
|
-
|
|
341
|
-
def _reset_plot(self, clear_plots=True):
|
|
342
|
-
''' Reset any plot settings for a new plot '''
|
|
343
|
-
# Clear plot list
|
|
344
|
-
if clear_plots:
|
|
345
|
-
super().clear_plots()
|
|
346
|
-
|
|
347
|
-
# Reset selection in data and dim selection in plot inputs
|
|
348
|
-
super().clear_selection()
|
|
349
|
-
|
|
350
|
-
# Reset params set for last plot
|
|
351
|
-
self._raster_plot.reset_plot_params()
|
|
352
|
-
|
|
353
|
-
self._plot_init = False
|
|
354
|
-
|
|
355
|
-
def _set_data_group(self, plot_inputs):
|
|
356
|
-
''' Add base data_group to plot inputs selection if not in user selection '''
|
|
357
|
-
if 'selection' not in plot_inputs or not plot_inputs['selection']:
|
|
358
|
-
plot_inputs['selection'] = {}
|
|
359
|
-
|
|
360
|
-
data_group = 'base'
|
|
361
|
-
if 'data_group' in plot_inputs['selection']:
|
|
362
|
-
data_group = plot_inputs['selection'].pop('data_group')
|
|
363
|
-
plot_inputs['selection']['data_group_name'] = data_group
|
|
364
|
-
|
|
365
|
-
if self._data and self._data.is_valid():
|
|
366
|
-
plot_inputs['correlated_data'] = self._data.get_correlated_data(data_group)
|
|
367
|
-
|
|
368
|
-
### -----------------------------------------------------------------------
|
|
369
|
-
### Interactive GUI
|
|
370
|
-
### -----------------------------------------------------------------------
|
|
371
|
-
def _launch_gui(self):
|
|
372
|
-
''' Use Holoviz Panel to create a dashboard for plot inputs. '''
|
|
373
|
-
# Select MS
|
|
374
|
-
file_selectors = file_selector('Path to MeasurementSet (ms or zarr) for plot', '~' , self._set_filename)
|
|
375
|
-
|
|
376
|
-
# Select style - colormaps, colorbar, color limits
|
|
377
|
-
style_selectors = style_selector(self._set_style_params, self._set_color_range)
|
|
378
|
-
|
|
379
|
-
# Set title
|
|
380
|
-
title_input = title_selector(self._set_title)
|
|
381
|
-
|
|
382
|
-
# Select x, y, and vis axis
|
|
383
|
-
x_axis = self._plot_inputs['x_axis']
|
|
384
|
-
y_axis = self._plot_inputs['y_axis']
|
|
385
|
-
data_dims = self._ms_info['data_dims'] if 'data_dims' in self._ms_info else None
|
|
386
|
-
axis_selectors = axis_selector(x_axis, y_axis, data_dims, True, self._set_axes)
|
|
387
|
-
|
|
388
|
-
# Select from ProcessingSet and MeasurementSet
|
|
389
|
-
selection_selectors = selection_selector(self._set_ps_selection)
|
|
390
|
-
|
|
391
|
-
# Generic axis options, updated when ms is set
|
|
392
|
-
axis_options = data_dims if data_dims else []
|
|
393
|
-
|
|
394
|
-
# Select aggregator and axes to aggregate
|
|
395
|
-
agg_selectors = aggregation_selector(axis_options, self._set_aggregation)
|
|
396
|
-
|
|
397
|
-
# Select iter_axis and iter value or range
|
|
398
|
-
iter_selectors = iteration_selector(axis_options, self._set_iter_values, self._set_iteration)
|
|
399
|
-
|
|
400
|
-
# Put user input widgets in accordion with only one card active at a time
|
|
401
|
-
selectors = pn.Accordion(
|
|
402
|
-
("Select file", file_selectors), # [0]
|
|
403
|
-
("Plot style", style_selectors), # [1]
|
|
404
|
-
("Plot axes", axis_selectors), # [2]
|
|
405
|
-
("Selection", selection_selectors), # [3]
|
|
406
|
-
("Aggregation", agg_selectors), # [4]
|
|
407
|
-
("Iteration", iter_selectors), # [5]
|
|
408
|
-
("Plot title", title_input), # [6]
|
|
409
|
-
)
|
|
410
|
-
selectors.toggle = True
|
|
411
|
-
|
|
412
|
-
# Plot button and spinner while plotting
|
|
413
|
-
init_plot = plot_starter(self._update_plot_spinner)
|
|
414
|
-
|
|
415
|
-
# Connect plot to filename and selector widgets
|
|
416
|
-
dmap = hv.DynamicMap(
|
|
417
|
-
pn.bind(
|
|
418
|
-
self._update_plot,
|
|
419
|
-
ms=file_selectors[0][0],
|
|
420
|
-
do_plot=init_plot[0],
|
|
421
|
-
),
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
# Layout plot and input widgets in a row
|
|
425
|
-
self._gui_layout = pn.Row(
|
|
426
|
-
pn.Column( # [0]
|
|
427
|
-
dmap,
|
|
428
|
-
sizing_mode='stretch_width',
|
|
429
|
-
),
|
|
430
|
-
pn.Spacer(width=10), # [1]
|
|
431
|
-
pn.Column( # [2]
|
|
432
|
-
pn.Spacer(height=25), # [0]
|
|
433
|
-
selectors, # [1]
|
|
434
|
-
init_plot, # [2]
|
|
435
|
-
width_policy='min',
|
|
436
|
-
width=400,
|
|
437
|
-
sizing_mode='stretch_height',
|
|
438
|
-
),
|
|
439
|
-
sizing_mode='stretch_height',
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
# Show gui
|
|
443
|
-
# print("gui layout:", self._gui_layout) # for debugging
|
|
444
|
-
self._gui_layout.show(title=self._app_name, threaded=True)
|
|
445
|
-
|
|
446
|
-
###
|
|
447
|
-
### Main callback to create plot
|
|
448
|
-
###
|
|
449
|
-
def _update_plot(self, ms, do_plot):
|
|
450
|
-
''' Create plot with inputs from GUI. Must return plot, even if empty plot, for DynamicMap. '''
|
|
451
|
-
if self._toast:
|
|
452
|
-
self._toast.destroy()
|
|
453
|
-
|
|
454
|
-
self._get_selector("selectors").active = []
|
|
455
|
-
if not ms:
|
|
456
|
-
# Launched GUI with no MS
|
|
457
|
-
return self._empty_plot
|
|
458
|
-
|
|
459
|
-
# If not first plot, user has to click Plot button (do_plot=True).
|
|
460
|
-
first_plot = not self._last_gui_plot
|
|
461
|
-
if not do_plot and not first_plot:
|
|
462
|
-
# Not ready to update plot yet, return last plot.
|
|
463
|
-
return self._last_gui_plot
|
|
464
|
-
|
|
465
|
-
if (self._set_ms(ms) or first_plot) and self._data and self._data.is_valid():
|
|
466
|
-
# New MS set and is valid
|
|
467
|
-
self._plot_inputs['selection'] = None
|
|
468
|
-
self._update_gui_axis_options()
|
|
469
|
-
|
|
470
|
-
# Add ms path to detect change and make new plot
|
|
471
|
-
self._plot_inputs['ms'] = ms
|
|
472
|
-
|
|
473
|
-
# Do new plot or resend last plot
|
|
474
|
-
self._reset_plot()
|
|
475
|
-
gui_plot = None
|
|
476
|
-
|
|
477
|
-
style_inputs = self._raster_plot.get_plot_params()['style']
|
|
478
|
-
if self._inputs_changed(style_inputs):
|
|
479
|
-
# First plot or changed plot
|
|
480
|
-
try:
|
|
481
|
-
# Check inputs from GUI then plot
|
|
482
|
-
self._plot_inputs['data_dims'] = self._ms_info['data_dims']
|
|
483
|
-
check_inputs(self._plot_inputs)
|
|
484
|
-
gui_plot = self._do_gui_plot()
|
|
485
|
-
except (ValueError, TypeError) as e:
|
|
486
|
-
# Clear plot, inputs invalid
|
|
487
|
-
self._notify(str(e), 'error', 0)
|
|
488
|
-
gui_plot = self._empty_plot
|
|
489
|
-
except RuntimeError as e:
|
|
490
|
-
# Clear plot, plot failed
|
|
491
|
-
self._notify(str(e), 'error', 0)
|
|
492
|
-
gui_plot = self._empty_plot
|
|
493
|
-
else:
|
|
494
|
-
# Subparam values changed but not applied to plot
|
|
495
|
-
gui_plot = self._last_gui_plot
|
|
496
|
-
|
|
497
|
-
# Save inputs to see if changed
|
|
498
|
-
self._last_plot_inputs = self._plot_inputs.copy()
|
|
499
|
-
self._last_style_inputs = style_inputs.copy()
|
|
500
|
-
self._last_plot_inputs['selection'] = self._plot_inputs['selection'].copy()
|
|
501
|
-
if first_plot and not do_plot:
|
|
502
|
-
self._plot_inputs['selection'].clear()
|
|
503
|
-
|
|
504
|
-
# Save plot if no new plot
|
|
505
|
-
self._last_gui_plot = gui_plot
|
|
506
|
-
|
|
507
|
-
# Change plot button and stop spinner
|
|
508
|
-
self._update_plot_status(False)
|
|
509
|
-
self._update_plot_spinner(False)
|
|
510
|
-
|
|
511
|
-
return gui_plot
|
|
512
|
-
|
|
513
|
-
def _inputs_changed(self, style_inputs):
|
|
514
|
-
''' Check if inputs changed and need new plot '''
|
|
515
|
-
if not self._last_plot_inputs:
|
|
516
|
-
return True
|
|
517
|
-
|
|
518
|
-
# Cannot use plot_inputs == self._plot_inputs until selection in GUI.
|
|
519
|
-
# Check inputs one by one
|
|
520
|
-
for key in self._plot_inputs:
|
|
521
|
-
if not self._values_equal(self._plot_inputs[key], self._last_plot_inputs[key]):
|
|
522
|
-
return True
|
|
523
|
-
|
|
524
|
-
for key in style_inputs:
|
|
525
|
-
if not self._values_equal(style_inputs[key], self._last_style_inputs[key]):
|
|
526
|
-
return True
|
|
527
|
-
return False
|
|
528
|
-
|
|
529
|
-
def _values_equal(self, val1, val2):
|
|
530
|
-
if val1 and val2: # both set
|
|
531
|
-
return val1 == val2
|
|
532
|
-
|
|
533
|
-
if not val1 and not val2: # both None
|
|
534
|
-
return True
|
|
535
|
-
|
|
536
|
-
return False # one set and other is None
|
|
537
|
-
|
|
538
|
-
###
|
|
539
|
-
### Create plot for DynamicMap
|
|
540
|
-
###
|
|
541
|
-
def _do_gui_plot(self):
|
|
542
|
-
''' Create plot based on gui plot inputs '''
|
|
543
|
-
if self._data and self._data.is_valid():
|
|
544
|
-
try:
|
|
545
|
-
if self._plot_inputs['iter_axis']:
|
|
546
|
-
# Make iter plot (possibly with subplots layout)
|
|
547
|
-
self._do_iter_plot(self._plot_inputs)
|
|
548
|
-
subplots = self._plot_inputs['subplots']
|
|
549
|
-
layout_plot, is_layout = super()._layout_plots(subplots)
|
|
550
|
-
|
|
551
|
-
if is_layout:
|
|
552
|
-
# Cannot show Layout in DynamicMap, show in new tab
|
|
553
|
-
super().show()
|
|
554
|
-
self._logger.info("Plot update complete")
|
|
555
|
-
return self._last_gui_plot
|
|
556
|
-
# Overlay raster plot for DynamicMap
|
|
557
|
-
self._logger.info("Plot update complete")
|
|
558
|
-
return layout_plot
|
|
559
|
-
|
|
560
|
-
# Make single Overlay raster plot for DynamicMap
|
|
561
|
-
plot = self._do_plot(self._plot_inputs)
|
|
562
|
-
plot_params = self._raster_plot.get_plot_params()
|
|
563
|
-
|
|
564
|
-
# Update color limits in gui with data range
|
|
565
|
-
self._update_color_range(plot_params)
|
|
566
|
-
|
|
567
|
-
# Update colorbar labels and limits
|
|
568
|
-
plot.QuadMesh.I = self._set_plot_colorbar(plot.QuadMesh.I, plot_params, "flagged")
|
|
569
|
-
plot.QuadMesh.II = self._set_plot_colorbar(plot.QuadMesh.II, plot_params, "unflagged")
|
|
570
|
-
|
|
571
|
-
self._logger.info("Plot update complete")
|
|
572
|
-
return plot.opts(
|
|
573
|
-
hv.opts.QuadMesh(tools=['hover'])
|
|
574
|
-
)
|
|
575
|
-
except RuntimeError as e:
|
|
576
|
-
error = f"Plot failed: {str(e)}"
|
|
577
|
-
super()._notify(error, "error", 0)
|
|
578
|
-
|
|
579
|
-
# Make single Overlay raster plot for DynamicMap
|
|
580
|
-
return self._empty_plot
|
|
581
|
-
|
|
582
|
-
def _create_empty_plot(self):
|
|
583
|
-
''' Create empty Overlay plot for DynamicMap with default color params and hover enabled '''
|
|
584
|
-
plot_params = self._raster_plot.get_plot_params()
|
|
585
|
-
plot = hv.Overlay(
|
|
586
|
-
hv.QuadMesh([]).opts(
|
|
587
|
-
colorbar=False,
|
|
588
|
-
cmap=plot_params['style']['flagged_cmap'],
|
|
589
|
-
responsive=True,
|
|
590
|
-
) * hv.QuadMesh([]).opts(
|
|
591
|
-
colorbar=plot_params['style']['show_colorbar'],
|
|
592
|
-
cmap=plot_params['style']['unflagged_cmap'],
|
|
593
|
-
responsive=True,
|
|
594
|
-
)
|
|
595
|
-
)
|
|
596
|
-
return plot.opts(
|
|
597
|
-
hv.opts.QuadMesh(tools=['hover'])
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
def _set_plot_colorbar(self, plot, plot_params, plot_type):
|
|
601
|
-
''' Update plot colorbar labels and limits
|
|
602
|
-
plot_type is "unflagged" or "flagged"
|
|
603
|
-
'''
|
|
604
|
-
# Update colorbar labels if shown, else hide
|
|
605
|
-
colorbar_key = plot_type + '_colorbar'
|
|
606
|
-
if plot_params['plot'][colorbar_key]:
|
|
607
|
-
c_label = plot_params['plot']['axis_labels']['c']['label']
|
|
608
|
-
cbar_title = "Flagged " + c_label if plot_type == "flagged" else c_label
|
|
609
|
-
|
|
610
|
-
plot = plot.opts(
|
|
611
|
-
colorbar=True,
|
|
612
|
-
backend_opts={
|
|
613
|
-
"colorbar.title": cbar_title,
|
|
614
|
-
}
|
|
615
|
-
)
|
|
616
|
-
else:
|
|
617
|
-
plot = plot.opts(
|
|
618
|
-
colorbar=False,
|
|
619
|
-
)
|
|
620
|
-
|
|
621
|
-
# Update plot color limits
|
|
622
|
-
color_limits = plot_params['plot']['color_limits']
|
|
623
|
-
if color_limits:
|
|
624
|
-
plot = plot.opts(
|
|
625
|
-
clim=color_limits,
|
|
626
|
-
)
|
|
627
|
-
|
|
628
|
-
return plot
|
|
629
|
-
|
|
630
|
-
def _update_color_range(self, plot_params):
|
|
631
|
-
''' Set the start/end range on the colorbar to min/max of plot data '''
|
|
632
|
-
if self._gui_layout and 'data' in plot_params and 'data_range' in plot_params['data']:
|
|
633
|
-
# Update range slider start and end to data min and max
|
|
634
|
-
data_range = plot_params['data']['data_range']
|
|
635
|
-
style_selectors = self._get_selector('style')
|
|
636
|
-
range_slider = style_selectors[3][1]
|
|
637
|
-
range_slider.start = data_range[0]
|
|
638
|
-
range_slider.end = data_range[1]
|
|
639
|
-
|
|
640
|
-
###
|
|
641
|
-
### Update widget options based on MS
|
|
642
|
-
###
|
|
643
|
-
def _get_selector(self, name):
|
|
644
|
-
''' Return selector group for name, for setting options '''
|
|
645
|
-
selectors = self._gui_layout[2][1]
|
|
646
|
-
selectors_index = {'file': 0, 'style': 1, 'axes': 2, 'selection': 3, 'agg': 4, 'iter': 5, 'title': 6}
|
|
647
|
-
if name == "selectors":
|
|
648
|
-
return selectors
|
|
649
|
-
return selectors[selectors_index[name]]
|
|
650
|
-
|
|
651
|
-
def _update_gui_axis_options(self):
|
|
652
|
-
''' Set gui options from ms data '''
|
|
653
|
-
if 'data_dims' in self._ms_info:
|
|
654
|
-
data_dims = self._ms_info['data_dims']
|
|
655
|
-
|
|
656
|
-
# Update options for x_axis and y_axis selectors
|
|
657
|
-
axis_selectors = self._get_selector('axes')
|
|
658
|
-
axis_selectors.objects[0][0].options = data_dims
|
|
659
|
-
axis_selectors.objects[0][1].options = data_dims
|
|
660
|
-
|
|
661
|
-
# Update options for vis_axis selector
|
|
662
|
-
if self._data.get_correlated_data('base') == 'SPECTRUM':
|
|
663
|
-
axis_selectors.objects[1].options = SPECTRUM_AXIS_OPTIONS
|
|
664
|
-
else:
|
|
665
|
-
axis_selectors.objects[1].options = VIS_AXIS_OPTIONS
|
|
666
|
-
|
|
667
|
-
# Update options for agg axes selector
|
|
668
|
-
agg_selectors = self._get_selector('agg')
|
|
669
|
-
agg_selectors[1].options = data_dims
|
|
670
|
-
|
|
671
|
-
# Update options for iteration axis selector
|
|
672
|
-
iter_selectors = self._get_selector('iter')
|
|
673
|
-
iter_axis_selector = iter_selectors[0][0]
|
|
674
|
-
iter_axis_selector.options = ['None']
|
|
675
|
-
iter_axis_selector.options.extend(data_dims)
|
|
676
|
-
|
|
677
|
-
###
|
|
678
|
-
### Callbacks for widgets which update other widgets
|
|
679
|
-
###
|
|
680
|
-
def _set_filename(self, filename):
|
|
681
|
-
''' Set filename in text box from file selector value (list) '''
|
|
682
|
-
if filename and self._gui_layout:
|
|
683
|
-
file_selectors = self._get_selector('file')
|
|
684
|
-
|
|
685
|
-
# Collapse FileSelector card
|
|
686
|
-
file_selectors[1].collapsed = True
|
|
687
|
-
|
|
688
|
-
# Change plot button color to indicate change unless ms path not set previously
|
|
689
|
-
filename_input = file_selectors[0][0]
|
|
690
|
-
if filename_input.value:
|
|
691
|
-
self._update_plot_status(True)
|
|
692
|
-
|
|
693
|
-
# Set filename from last file in file selector (triggers _update_plot())
|
|
694
|
-
#filename_input.width = len(filename[-1])
|
|
695
|
-
filename_input.value = filename[-1]
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
def _set_iter_values(self, iter_axis):
|
|
699
|
-
''' Set up player with values when iter_axis is selected '''
|
|
700
|
-
iter_axis = None if iter_axis == 'None' else iter_axis
|
|
701
|
-
if iter_axis and self._gui_layout:
|
|
702
|
-
iter_values = self._data.get_dimension_values(iter_axis)
|
|
703
|
-
if iter_values:
|
|
704
|
-
|
|
705
|
-
iter_selectors = self._get_selector('iter')
|
|
706
|
-
|
|
707
|
-
# Update value selector with values and select first value
|
|
708
|
-
iter_value_player = iter_selectors[1][0]
|
|
709
|
-
if iter_axis == 'time':
|
|
710
|
-
if isinstance(iter_values[0], float):
|
|
711
|
-
iter_values = self._get_datetime_values(iter_values)
|
|
712
|
-
iter_value_player.format = get_time_formatter()
|
|
713
|
-
elif iter_axis == 'frequency':
|
|
714
|
-
iter_value_player.format = NumeralTickFormatter(format='0,0.0000000')
|
|
715
|
-
|
|
716
|
-
iter_value_player.options = iter_values
|
|
717
|
-
iter_value_player.value = iter_values[0]
|
|
718
|
-
iter_value_player.show_value = True
|
|
719
|
-
|
|
720
|
-
# Update range inputs end values and select first
|
|
721
|
-
iter_range_inputs = iter_selectors[1][1]
|
|
722
|
-
last_iter_index = len(iter_values) - 1
|
|
723
|
-
# range start
|
|
724
|
-
iter_range_inputs[0][0].end = last_iter_index
|
|
725
|
-
iter_range_inputs[0][0].value = 0
|
|
726
|
-
# range end
|
|
727
|
-
iter_range_inputs[0][1].end = last_iter_index
|
|
728
|
-
iter_range_inputs[0][1].value = 0
|
|
729
|
-
|
|
730
|
-
def _get_datetime_values(self, float_times):
|
|
731
|
-
''' Return list of float time values as list of datetime values for gui options '''
|
|
732
|
-
time_attrs = self._data.get_dimension_attrs('time')
|
|
733
|
-
datetime_values = []
|
|
734
|
-
try:
|
|
735
|
-
datetime_values = to_datetime(float_times, unit=time_attrs['units'], origin=time_attrs['format'])
|
|
736
|
-
except TypeError:
|
|
737
|
-
datetime_values = to_datetime(float_times, unit=time_attrs['units'][0], origin=time_attrs['format'])
|
|
738
|
-
return list(datetime_values)
|
|
739
|
-
|
|
740
|
-
def _update_plot_spinner(self, plot_clicked):
|
|
741
|
-
''' Callback to start spinner when Plot button clicked. '''
|
|
742
|
-
if self._gui_layout:
|
|
743
|
-
# Start spinner
|
|
744
|
-
spinner = self._gui_layout[2][2][1]
|
|
745
|
-
spinner.value = plot_clicked
|
|
746
|
-
|
|
747
|
-
def _update_plot_status(self, inputs_changed):
|
|
748
|
-
''' Change button color when inputs change. '''
|
|
749
|
-
if self._gui_layout:
|
|
750
|
-
# Set button color
|
|
751
|
-
button = self._gui_layout[2][2][0]
|
|
752
|
-
button.button_style = 'solid' if inputs_changed else 'outline'
|
|
753
|
-
|
|
754
|
-
###
|
|
755
|
-
### Callbacks for widgets which update plot inputs
|
|
756
|
-
###
|
|
757
|
-
def _set_title(self, title):
|
|
758
|
-
''' Set title from gui text input '''
|
|
759
|
-
self._plot_inputs['title'] = title
|
|
760
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
761
|
-
|
|
762
|
-
def _set_style_params(self, unflagged_cmap, flagged_cmap, show_colorbar, show_flagged_colorbar):
|
|
763
|
-
self.set_style_params(unflagged_cmap, flagged_cmap, show_colorbar, show_flagged_colorbar)
|
|
764
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
765
|
-
|
|
766
|
-
def _set_color_range(self, color_mode, color_range):
|
|
767
|
-
''' Set style params from gui '''
|
|
768
|
-
color_mode = color_mode.split()[0]
|
|
769
|
-
color_mode = None if color_mode == 'No' else color_mode
|
|
770
|
-
self._plot_inputs['color_mode'] = color_mode
|
|
771
|
-
self._plot_inputs['color_range'] = color_range
|
|
772
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
773
|
-
|
|
774
|
-
def _set_axes(self, x_axis, y_axis, vis_axis):
|
|
775
|
-
''' Set plot axis params from gui '''
|
|
776
|
-
self._plot_inputs['x_axis'] = x_axis
|
|
777
|
-
self._plot_inputs['y_axis'] = y_axis
|
|
778
|
-
self._plot_inputs['vis_axis'] = vis_axis
|
|
779
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
780
|
-
|
|
781
|
-
def _set_aggregation(self, aggregator, agg_axes):
|
|
782
|
-
''' Set aggregation params from gui '''
|
|
783
|
-
aggregator = None if aggregator== 'None' else aggregator
|
|
784
|
-
self._plot_inputs['aggregator'] = aggregator
|
|
785
|
-
self._plot_inputs['agg_axis'] = agg_axes # ignored if aggregator not set
|
|
786
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
787
|
-
|
|
788
|
-
# pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
789
|
-
def _set_iteration(self, iter_axis, iter_value_type, iter_value, iter_start, iter_end, subplot_rows, subplot_columns):
|
|
790
|
-
''' Set iteration params from gui '''
|
|
791
|
-
iter_axis = None if iter_axis == 'None' else iter_axis
|
|
792
|
-
self._plot_inputs['iter_axis'] = iter_axis
|
|
793
|
-
self._plot_inputs['subplots'] = (subplot_rows, subplot_columns)
|
|
794
|
-
|
|
795
|
-
if iter_axis:
|
|
796
|
-
if iter_value_type == 'By Value':
|
|
797
|
-
# Use index of iter_value for tuple
|
|
798
|
-
if self._data and self._data.is_valid():
|
|
799
|
-
iter_values = self._data.get_dimension_values(iter_axis)
|
|
800
|
-
iter_index = iter_values.index(iter_value)
|
|
801
|
-
self._plot_inputs['iter_range'] = (iter_index, iter_index)
|
|
802
|
-
else:
|
|
803
|
-
# 'By Range': use range start and end values for tuple
|
|
804
|
-
self._plot_inputs['iter_range'] = (iter_start, iter_end)
|
|
805
|
-
else:
|
|
806
|
-
self._plot_inputs['iter_range'] = None
|
|
807
|
-
self._update_plot_status(True) # Change plot button to solid
|
|
808
|
-
# pylint: enable=too-many-arguments, too-many-positional-arguments
|
|
809
|
-
|
|
810
|
-
def _set_ps_selection(self, query):
|
|
811
|
-
''' Select ProcessingSet from gui using summary columns '''
|
|
812
|
-
if 'selection' not in self._plot_inputs or self._plot_inputs['selection'] is None:
|
|
813
|
-
self._plot_inputs['selection'] = {}
|
|
814
|
-
self._plot_inputs['selection']['query'] = query
|
|
815
|
-
self._update_plot_status(True) # Change plot button to solid
|