vidavis 0.0.13__py3-none-any.whl → 0.0.15__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.
- vidavis/__version__.py +1 -1
- vidavis/apps/_ms_raster.py +237 -396
- vidavis/data/measurement_set/processing_set/_ps_coords.py +4 -0
- vidavis/data/measurement_set/processing_set/_ps_raster_data.py +6 -3
- vidavis/data/measurement_set/processing_set/_ps_select.py +1 -1
- vidavis/plot/ms_plot/_locate_points.py +90 -8
- vidavis/plot/ms_plot/_ms_plot.py +196 -74
- vidavis/plot/ms_plot/_ms_plot_selectors.py +18 -11
- vidavis/plot/ms_plot/_plot_inputs.py +1 -1
- vidavis/plot/ms_plot/_raster_plot.py +2 -6
- vidavis/plot/ms_plot/_raster_plot_gui.py +15 -33
- vidavis/plot/ms_plot/_raster_plot_inputs.py +113 -0
- {vidavis-0.0.13.dist-info → vidavis-0.0.15.dist-info}/METADATA +1 -1
- {vidavis-0.0.13.dist-info → vidavis-0.0.15.dist-info}/RECORD +16 -15
- {vidavis-0.0.13.dist-info → vidavis-0.0.15.dist-info}/WHEEL +0 -0
- {vidavis-0.0.13.dist-info → vidavis-0.0.15.dist-info}/licenses/LICENSE +0 -0
vidavis/apps/_ms_raster.py
CHANGED
|
@@ -8,17 +8,15 @@ from bokeh.models.formatters import NumeralTickFormatter
|
|
|
8
8
|
import holoviews as hv
|
|
9
9
|
import numpy as np
|
|
10
10
|
from pandas import to_datetime
|
|
11
|
-
import panel as pn
|
|
12
11
|
|
|
13
12
|
from vidavis.bokeh._palette import available_palettes
|
|
14
13
|
from vidavis.data.measurement_set.processing_set._ps_coords import set_index_coordinates
|
|
15
|
-
from vidavis.plot.ms_plot._check_raster_inputs import check_inputs
|
|
16
|
-
from vidavis.plot.ms_plot._locate_points import cursor_changed, points_changed, box_changed, locate_point, locate_box
|
|
17
14
|
from vidavis.plot.ms_plot._ms_plot import MsPlot
|
|
18
15
|
from vidavis.plot.ms_plot._ms_plot_constants import VIS_AXIS_OPTIONS, SPECTRUM_AXIS_OPTIONS, PS_SELECTION_OPTIONS, MS_SELECTION_OPTIONS
|
|
19
16
|
from vidavis.plot.ms_plot._plot_inputs import inputs_changed
|
|
20
|
-
from vidavis.plot.ms_plot._raster_plot_gui import create_raster_gui
|
|
21
17
|
from vidavis.plot.ms_plot._raster_plot import RasterPlot
|
|
18
|
+
from vidavis.plot.ms_plot._raster_plot_gui import create_raster_gui
|
|
19
|
+
from vidavis.plot.ms_plot._raster_plot_inputs import RasterPlotInputs
|
|
22
20
|
from vidavis.plot.ms_plot._time_ticks import get_time_formatter
|
|
23
21
|
|
|
24
22
|
class MsRaster(MsPlot):
|
|
@@ -44,6 +42,8 @@ class MsRaster(MsPlot):
|
|
|
44
42
|
|
|
45
43
|
def __init__(self, ms=None, log_level="info", log_to_file=True, show_gui=False):
|
|
46
44
|
super().__init__(ms, log_level, log_to_file, show_gui, "MsRaster")
|
|
45
|
+
self._plot_inputs = RasterPlotInputs()
|
|
46
|
+
self._plot_inputs.set_input('ms', self._ms_info['ms'])
|
|
47
47
|
self._raster_plot = RasterPlot()
|
|
48
48
|
|
|
49
49
|
# Calculations for color limits
|
|
@@ -51,17 +51,21 @@ class MsRaster(MsPlot):
|
|
|
51
51
|
self._spw_color_limits = {}
|
|
52
52
|
|
|
53
53
|
if show_gui:
|
|
54
|
-
#
|
|
55
|
-
self._empty_plot = self._create_empty_plot()
|
|
56
|
-
|
|
57
|
-
# Set default style and plot inputs to use when launching gui
|
|
54
|
+
# Set default style and plot inputs to use for empty plot and gui
|
|
58
55
|
self.set_style_params()
|
|
59
56
|
self.plot()
|
|
57
|
+
|
|
58
|
+
# Initial plot for gui
|
|
59
|
+
self._create_empty_plot()
|
|
60
|
+
|
|
61
|
+
# Create and show gui panel
|
|
60
62
|
self._launch_gui()
|
|
61
63
|
|
|
62
|
-
# Set filename TextInput widget to input ms
|
|
64
|
+
# Set filename TextInput widget to input ms
|
|
63
65
|
if 'ms' in self._ms_info and self._ms_info['ms']:
|
|
64
|
-
self._set_filename(
|
|
66
|
+
self._set_filename(self._ms_info['ms'])
|
|
67
|
+
self._update_gui_ms_options()
|
|
68
|
+
self._update_plot(do_plot=True)
|
|
65
69
|
|
|
66
70
|
def colormaps(self):
|
|
67
71
|
''' List available colormap (Bokeh palettes). '''
|
|
@@ -99,12 +103,10 @@ class MsRaster(MsPlot):
|
|
|
99
103
|
For explanation and examples, see:
|
|
100
104
|
https://xradio.readthedocs.io/en/latest/measurement_set/schema_and_api/measurement_set_api.html#xradio.measurement_set.ProcessingSetXdt.query
|
|
101
105
|
'''
|
|
102
|
-
if self.
|
|
106
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
103
107
|
try:
|
|
104
|
-
self._plot_inputs
|
|
105
|
-
|
|
106
|
-
self._plot_inputs['data_group'] = kwargs['data_group_name']
|
|
107
|
-
self._data.select_ps(query=query, string_exact_match=string_exact_match, **kwargs)
|
|
108
|
+
self._plot_inputs.set_selection(kwargs)
|
|
109
|
+
self._ms_data.select_ps(query=query, string_exact_match=string_exact_match, **kwargs)
|
|
108
110
|
except KeyError as ke:
|
|
109
111
|
error = "ProcessingSet selection yielded empty ProcessingSet."
|
|
110
112
|
if not self._show_gui:
|
|
@@ -128,12 +130,10 @@ class MsRaster(MsPlot):
|
|
|
128
130
|
For explanation of parameters and examples, see:
|
|
129
131
|
https://xradio.readthedocs.io/en/latest/measurement_set/schema_and_api/measurement_set_api.html#xradio.measurement_set.MeasurementSetXdt.sel
|
|
130
132
|
'''
|
|
131
|
-
if self.
|
|
133
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
132
134
|
try:
|
|
133
|
-
self._plot_inputs
|
|
134
|
-
self.
|
|
135
|
-
if 'data_group_name' in indexers_kwargs:
|
|
136
|
-
self._plot_inputs['data_group'] |= indexers_kwargs['data_group_name']
|
|
135
|
+
self._plot_inputs.set_selection(indexers_kwargs)
|
|
136
|
+
self._ms_data.select_ms(indexers=indexers, method=method, tolerance=tolerance, drop=drop, **indexers_kwargs)
|
|
137
137
|
except KeyError as ke:
|
|
138
138
|
error = str(ke).strip("\'")
|
|
139
139
|
if not self._show_gui:
|
|
@@ -179,34 +179,37 @@ class MsRaster(MsPlot):
|
|
|
179
179
|
|
|
180
180
|
If plot is successful, use show() or save() to view/save the plot.
|
|
181
181
|
'''
|
|
182
|
-
inputs = locals() # collect arguments into dict
|
|
183
|
-
if self._plot_inputs['selection']:
|
|
184
|
-
self._logger.info("Create raster plot with selection: %s", self._plot_inputs['selection'])
|
|
182
|
+
inputs = locals() # collect arguments into dict
|
|
185
183
|
|
|
186
184
|
start = time.time()
|
|
187
185
|
|
|
186
|
+
# If previous plot was shown, unlink from data streams
|
|
187
|
+
super().unlink_plot_streams()
|
|
188
|
+
|
|
188
189
|
# Clear for new plot
|
|
189
190
|
self._reset_plot(clear_plots)
|
|
190
191
|
|
|
191
192
|
# Get data dimensions if valid MS is set to check input axes
|
|
192
193
|
if 'data_dims' in self._ms_info:
|
|
193
|
-
|
|
194
|
+
data_dims = self._ms_info['data_dims'] if 'data_dims' in self._ms_info else None
|
|
195
|
+
inputs['data_dims'] = data_dims
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
self._plot_inputs.set_inputs(inputs)
|
|
198
|
+
selection = self._plot_inputs.get_input('selection')
|
|
199
|
+
if selection:
|
|
200
|
+
self._logger.info("Create raster plot with selection: %s", selection)
|
|
198
201
|
|
|
199
202
|
if not self._show_gui:
|
|
200
203
|
# Cannot plot if no MS
|
|
201
|
-
if not self.
|
|
204
|
+
if not self._ms_data or not self._ms_data.is_valid():
|
|
202
205
|
raise RuntimeError("Cannot plot MS: input MS path is invalid or missing.")
|
|
203
206
|
|
|
204
207
|
# Create raster plot and add to plot list
|
|
205
208
|
try:
|
|
206
|
-
if self._plot_inputs
|
|
207
|
-
self._do_iter_plot(
|
|
209
|
+
if self._plot_inputs.get_input('iter_axis'):
|
|
210
|
+
self._do_iter_plot()
|
|
208
211
|
else:
|
|
209
|
-
plot = self._do_plot(
|
|
212
|
+
plot = self._do_plot()
|
|
210
213
|
self._plots.append(plot)
|
|
211
214
|
except RuntimeError as e:
|
|
212
215
|
error = f"Plot failed: {str(e)}"
|
|
@@ -239,160 +242,155 @@ class MsRaster(MsPlot):
|
|
|
239
242
|
filename = f"{self._ms_info['basename']}_raster.png"
|
|
240
243
|
super().save(filename, fmt, width, height)
|
|
241
244
|
|
|
242
|
-
def
|
|
243
|
-
''' Set inputs from latest plot() call '''
|
|
244
|
-
for key, val in plot_inputs.items():
|
|
245
|
-
self._plot_inputs[key] = val
|
|
246
|
-
|
|
247
|
-
def _do_plot(self, plot_inputs, is_gui_plot=False):
|
|
245
|
+
def _do_plot(self, is_gui_plot=False):
|
|
248
246
|
''' Create plot using plot inputs '''
|
|
249
247
|
if not self._plot_init:
|
|
250
|
-
self._init_plot(
|
|
248
|
+
self._init_plot()
|
|
251
249
|
|
|
252
250
|
# Select vis_axis data to plot and update selection; returns xarray Dataset
|
|
253
|
-
raster_data = self.
|
|
251
|
+
raster_data = self._ms_data.get_raster_data(self._plot_inputs.get_inputs())
|
|
254
252
|
|
|
255
253
|
# Save plot data for plot location callbacks unless layout (location not supported)
|
|
256
|
-
if not self.
|
|
254
|
+
if not self._plot_inputs.is_layout():
|
|
255
|
+
x_axis = self._plot_inputs.get_input('x_axis')
|
|
256
|
+
y_axis = self._plot_inputs.get_input('y_axis')
|
|
257
257
|
if is_gui_plot:
|
|
258
|
-
self._gui_plot_data = set_index_coordinates(raster_data, (
|
|
258
|
+
self._gui_plot_data = set_index_coordinates(raster_data, (x_axis, y_axis))
|
|
259
259
|
else:
|
|
260
|
-
self._plot_data = set_index_coordinates(raster_data, (
|
|
260
|
+
self._plot_data = set_index_coordinates(raster_data, (x_axis, y_axis))
|
|
261
261
|
|
|
262
262
|
# Add params needed for plot: auto color range and ms name
|
|
263
|
-
self._set_auto_color_range(
|
|
263
|
+
self._set_auto_color_range() # set calculated limits if auto mode
|
|
264
264
|
ms_name = self._ms_info['basename'] # for title
|
|
265
|
+
plot_inputs = self._plot_inputs.get_inputs()
|
|
265
266
|
self._raster_plot.set_plot_params(raster_data, plot_inputs, ms_name)
|
|
266
267
|
|
|
267
268
|
# Show plot inputs in log
|
|
268
269
|
super()._set_plot_params(plot_inputs | self._raster_plot.get_plot_params()['style'])
|
|
269
|
-
|
|
270
|
+
plot_params = [f"{key}={value}" for key, value in self._plot_params.items()]
|
|
271
|
+
self._logger.info("MsRaster plot inputs: %s", ", ".join(plot_params))
|
|
270
272
|
|
|
271
273
|
# Make plot. Add data min/max if GUI is shown to update color limits range.
|
|
272
274
|
return self._raster_plot.raster_plot(raster_data, self._logger, self._show_gui)
|
|
273
275
|
|
|
274
|
-
def _do_iter_plot(self
|
|
276
|
+
def _do_iter_plot(self):
|
|
275
277
|
''' Create one plot per iteration value in iter_range which fits into subplots '''
|
|
276
278
|
# Default (0, 0) (first iteration only). Use (0, -1) for all iterations.
|
|
277
279
|
# If subplots is a grid, end iteration index is limited by the grid size.
|
|
278
280
|
# If subplots is a single plot, all iteration plots in the range can be saved using export_range in save().
|
|
279
|
-
iter_axis =
|
|
280
|
-
iter_range =
|
|
281
|
-
subplots =
|
|
282
|
-
|
|
283
|
-
iter_range = (0, 0) if iter_range is None else iter_range
|
|
284
|
-
start_idx, end_idx = iter_range
|
|
281
|
+
iter_axis = self._plot_inputs.get_input('iter_axis')
|
|
282
|
+
iter_range = self._plot_inputs.get_input('iter_range')
|
|
283
|
+
subplots = self._plot_inputs.get_input('subplots')
|
|
285
284
|
|
|
286
285
|
# Init plot before getting iter values
|
|
287
|
-
self._init_plot(
|
|
288
|
-
|
|
289
|
-
iter_values = self._data.get_dimension_values(iter_axis)
|
|
286
|
+
self._init_plot()
|
|
287
|
+
iter_values = self._ms_data.get_dimension_values(iter_axis)
|
|
290
288
|
n_iter = len(iter_values)
|
|
291
289
|
|
|
290
|
+
iter_range = (0, 0) if iter_range is None else iter_range
|
|
291
|
+
start_idx, end_idx = iter_range
|
|
292
|
+
auto_range = end_idx == -1
|
|
293
|
+
|
|
292
294
|
if start_idx >= n_iter:
|
|
293
295
|
raise IndexError(f"iter_range start {start_idx} is greater than number of iterations {n_iter}")
|
|
294
296
|
end_idx = n_iter if (end_idx == -1 or end_idx >= n_iter) else end_idx + 1
|
|
295
297
|
num_iter_plots = end_idx - start_idx
|
|
296
298
|
|
|
297
|
-
# Plot the minimum of iter range or subplots number of plots
|
|
299
|
+
# Plot the minimum of iter range or subplots number of plots.
|
|
300
|
+
# If subplots is single plot, plot all for save()
|
|
298
301
|
num_subplots = np.prod(subplots) if subplots else 1
|
|
299
302
|
num_iter_plots = min(num_iter_plots, num_subplots) if num_subplots > 1 else num_iter_plots
|
|
300
303
|
end_idx = start_idx + num_iter_plots
|
|
301
|
-
self._plot_inputs['iter_range'] = (start_idx, end_idx)
|
|
302
304
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
if auto_range:
|
|
306
|
+
# For listing plot inputs
|
|
307
|
+
start_idx = start_idx.item() if isinstance(start_idx, np.int64) else start_idx
|
|
308
|
+
end_idx = end_idx.item() if isinstance(end_idx, np.int64) else end_idx
|
|
309
|
+
self._plot_inputs.set_input('auto_iter_range', (start_idx, end_idx - 1))
|
|
306
310
|
|
|
307
311
|
for i in range(start_idx, end_idx):
|
|
308
312
|
# Select iteration value and make plot
|
|
309
313
|
value = iter_values[i]
|
|
310
314
|
self._logger.info("Plot %s iteration index %s value %s", iter_axis, i, value)
|
|
311
|
-
|
|
315
|
+
self._plot_inputs.set_selection({iter_axis: value})
|
|
312
316
|
try:
|
|
313
|
-
plot = self._do_plot(
|
|
317
|
+
plot = self._do_plot()
|
|
314
318
|
self._plots.append(plot)
|
|
315
319
|
except RuntimeError as e:
|
|
316
320
|
self._logger.info("Iteration plot for value %s failed: %s", str(value), str(e))
|
|
317
321
|
continue
|
|
318
322
|
|
|
319
|
-
def _init_plot(self
|
|
323
|
+
def _init_plot(self):
|
|
320
324
|
''' Apply automatic selection '''
|
|
321
325
|
# Remove previous auto selections
|
|
322
326
|
for key in ['dim_selection', 'auto_spw']:
|
|
323
|
-
|
|
324
|
-
del self._plot_inputs[key]
|
|
325
|
-
except KeyError:
|
|
326
|
-
pass
|
|
327
|
+
self._plot_inputs.remove_input(key)
|
|
327
328
|
|
|
328
329
|
# Automatically select data group and spw name if not user-selected
|
|
329
330
|
auto_selection = {}
|
|
330
|
-
if 'data_group'
|
|
331
|
+
if not self._plot_inputs.get_input('data_group'):
|
|
331
332
|
auto_selection['data_group_name'] = 'base'
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
333
|
+
self._plot_inputs.set_input('data_group', 'base')
|
|
334
|
+
|
|
335
|
+
data_group = self._plot_inputs.get_input('data_group')
|
|
336
|
+
spw_selection = self._plot_inputs.get_selection('spw_name')
|
|
337
|
+
if not spw_selection:
|
|
338
|
+
first_spw = self._ms_data.get_first_spw(data_group)
|
|
335
339
|
auto_selection['spw_name'] = first_spw
|
|
336
|
-
|
|
340
|
+
self._plot_inputs.set_input('auto_spw', first_spw) # keep separate from user selection
|
|
337
341
|
|
|
338
342
|
if auto_selection:
|
|
339
343
|
# Do selection and save to plot inputs
|
|
340
344
|
self._logger.info("Automatic selection of data group and/or spw: %s", auto_selection)
|
|
341
|
-
self.
|
|
345
|
+
self._ms_data.select_ps(query=None, string_exact_match=True, **auto_selection)
|
|
342
346
|
|
|
343
347
|
# Print data info for spw selection
|
|
344
|
-
self._logger.info("Plotting %s msv4 datasets.", self.
|
|
345
|
-
self._logger.info("Maximum dimensions for selected spw: %s", self.
|
|
348
|
+
self._logger.info("Plotting %s msv4 datasets.", self._ms_data.get_num_ms())
|
|
349
|
+
self._logger.info("Maximum dimensions for selected spw: %s", self._ms_data.get_max_data_dims())
|
|
346
350
|
self._plot_init = True
|
|
347
351
|
|
|
348
|
-
def
|
|
349
|
-
''' Determine if plot is a layout using plot inputs '''
|
|
350
|
-
# Check if subplots is a layout
|
|
351
|
-
if self._plot_inputs['subplots'] is None or self._plot_inputs['subplots'] == (1, 1):
|
|
352
|
-
return False
|
|
353
|
-
|
|
354
|
-
# Check if iteration set and iter_range more than one plot
|
|
355
|
-
iter_length = 0
|
|
356
|
-
if self._plot_inputs['iter_axis'] is not None:
|
|
357
|
-
iter_range = self._plot_inputs['iter_range']
|
|
358
|
-
iter_range = (0, 0) if iter_range is None else iter_range
|
|
359
|
-
iter_length = len(range(iter_range[0], iter_range[1] + 1))
|
|
360
|
-
|
|
361
|
-
# Also check if previous plot(s) not cleared
|
|
362
|
-
return iter_length > 1 or len(self._plots) > 0
|
|
363
|
-
|
|
364
|
-
def _set_auto_color_range(self, plot_inputs):
|
|
352
|
+
def _set_auto_color_range(self):
|
|
365
353
|
''' Calculate stats for color limits for non-gui amplitude plots. '''
|
|
366
|
-
color_mode =
|
|
367
|
-
|
|
354
|
+
color_mode = self._plot_inputs.get_input('color_mode')
|
|
355
|
+
auto_color_limits = None
|
|
368
356
|
|
|
369
357
|
if color_mode == 'auto':
|
|
370
|
-
if
|
|
358
|
+
if self._plot_inputs.get_input('vis_axis') == 'amp' and not self._plot_inputs.get_input('aggregator'):
|
|
371
359
|
# For amplitude, limit colorbar range using stored per-spw ms stats
|
|
372
|
-
spw_name = self._plot_inputs
|
|
360
|
+
spw_name = self._plot_inputs.get_selection('spw_name')
|
|
361
|
+
if not spw_name:
|
|
362
|
+
spw_name = self._plot_inputs.get_input('auto_spw')
|
|
363
|
+
|
|
373
364
|
if spw_name in self._spw_color_limits:
|
|
374
|
-
|
|
365
|
+
auto_color_limits = self._spw_color_limits[spw_name]
|
|
375
366
|
else:
|
|
376
367
|
# Select spw name and data group only, no dimensions
|
|
377
|
-
data_group = self._plot_inputs
|
|
368
|
+
data_group = self._plot_inputs.get_input('data_group')
|
|
378
369
|
spw_data_selection = {'spw_name': spw_name, 'data_group_name': data_group}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
370
|
+
auto_color_limits = self._calc_amp_color_limits(spw_data_selection)
|
|
371
|
+
|
|
372
|
+
if auto_color_limits:
|
|
373
|
+
# Convert to float for listing plot inputs
|
|
374
|
+
start, end = auto_color_limits
|
|
375
|
+
start = start.item() if isinstance(start, np.float64) else start
|
|
376
|
+
end = end.item() if isinstance(end, np.float64) else end
|
|
377
|
+
auto_color_limits = (start, end)
|
|
378
|
+
self._spw_color_limits[spw_name] = auto_color_limits
|
|
379
|
+
self._plot_inputs.set_input('auto_color_range', auto_color_limits)
|
|
380
|
+
|
|
381
|
+
if auto_color_limits:
|
|
382
|
+
self._logger.info("Setting amplitude color range: (%.4f, %.4f).", auto_color_limits[0], auto_color_limits[1])
|
|
385
383
|
elif color_mode is None:
|
|
386
384
|
self._logger.info("Autoscale color range")
|
|
387
385
|
else:
|
|
388
|
-
self._logger.info("Using manual color range: %s",
|
|
386
|
+
self._logger.info("Using manual color range: %s", self._plot_inputs.get_input('color_range'))
|
|
389
387
|
|
|
390
388
|
def _calc_amp_color_limits(self, selection):
|
|
391
389
|
# Calculate colorbar limits from amplitude stats for unflagged data in selected spw
|
|
392
390
|
self._logger.info("Calculating stats for colorbar limits.")
|
|
393
391
|
start = time.time()
|
|
394
392
|
|
|
395
|
-
ms_stats = self.
|
|
393
|
+
ms_stats = self._ms_data.get_vis_stats(selection, 'amp')
|
|
396
394
|
self._spw_stats['spw_name'] = ms_stats
|
|
397
395
|
if not ms_stats:
|
|
398
396
|
return None # autoscale
|
|
@@ -417,7 +415,7 @@ class MsRaster(MsPlot):
|
|
|
417
415
|
if clear_plots:
|
|
418
416
|
super().clear_plots()
|
|
419
417
|
|
|
420
|
-
# Clear params
|
|
418
|
+
# Clear params for last plot
|
|
421
419
|
self._raster_plot.reset_plot_params()
|
|
422
420
|
|
|
423
421
|
# Unitialize plot to redo auto selections if needed
|
|
@@ -429,7 +427,8 @@ class MsRaster(MsPlot):
|
|
|
429
427
|
def _launch_gui(self):
|
|
430
428
|
''' Use Holoviz Panel to create and show a dashboard for plot inputs. '''
|
|
431
429
|
callbacks = {
|
|
432
|
-
'
|
|
430
|
+
'set_filename': self._set_filename,
|
|
431
|
+
'select_filename': self._select_filename,
|
|
433
432
|
'style': self._set_style_params,
|
|
434
433
|
'color': self._set_color_range,
|
|
435
434
|
'axes': self._set_axes,
|
|
@@ -439,164 +438,125 @@ class MsRaster(MsPlot):
|
|
|
439
438
|
'iter_values': self._set_iter_values,
|
|
440
439
|
'iteration': self._set_iteration,
|
|
441
440
|
'title': self._set_title,
|
|
442
|
-
'plot_updating': self._update_plot_spinner,
|
|
443
441
|
'update_plot': self._update_plot,
|
|
444
442
|
}
|
|
443
|
+
|
|
445
444
|
data_dims = self._ms_info['data_dims'] if 'data_dims' in self._ms_info else None
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
plot_info = {
|
|
446
|
+
'ms': self._ms_info['ms'],
|
|
447
|
+
'data_dims': data_dims,
|
|
448
|
+
'x_axis': self._plot_inputs.get_input('x_axis'),
|
|
449
|
+
'y_axis': self._plot_inputs.get_input('y_axis'),
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
self._gui_panel = create_raster_gui(callbacks, plot_info, self._empty_plot)
|
|
453
|
+
self._gui_panel.show(title=self._app_name, threaded=True)
|
|
450
454
|
|
|
451
455
|
###
|
|
452
456
|
### Main callback to create plot if inputs changed
|
|
453
457
|
###
|
|
454
458
|
# pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
455
|
-
def _update_plot(self,
|
|
459
|
+
def _update_plot(self, do_plot):
|
|
456
460
|
''' Create plot with inputs from GUI, or update cursor/box location.
|
|
457
461
|
Callbacks:
|
|
458
|
-
ms (first plot) - return plot with default inputs
|
|
459
462
|
do_plot (Plot button clicked) - return plot with inputs from GUI
|
|
460
|
-
x, y (PointerXY) - update cursor location box
|
|
461
|
-
data (PointDraw from point_draw tool) - update location of drawn points in tab and log
|
|
462
|
-
bounds (Bounds from box_select tool) - update location of points in box in tab and log
|
|
463
463
|
This function *must* return plot, even if empty plot or last plot, for DynamicMap.
|
|
464
464
|
'''
|
|
465
|
+
if not do_plot or not self._gui_panel:
|
|
466
|
+
return
|
|
467
|
+
|
|
465
468
|
# Remove toast notification and collapse selection accordion
|
|
466
469
|
if self._toast:
|
|
467
470
|
self._toast.destroy()
|
|
468
471
|
self._get_selector("selectors").active = []
|
|
469
|
-
|
|
470
|
-
if not ms:
|
|
471
|
-
# GUI launched with no MS, nothing to plot
|
|
472
|
-
return self._empty_plot
|
|
473
|
-
|
|
474
|
-
# User changed inputs without clicking Plot button, or callback for cursor/box.
|
|
475
|
-
if not do_plot and not self._first_gui_plot:
|
|
476
|
-
if cursor_changed(x, y, self._last_cursor):
|
|
477
|
-
# new cursor position - update cursor location box
|
|
478
|
-
self._update_cursor_location(x, y)
|
|
479
|
-
self._last_cursor = (x, y)
|
|
480
|
-
|
|
481
|
-
if points_changed(data, self._last_points):
|
|
482
|
-
# new points position - update selected points location tab
|
|
483
|
-
self._update_points_location(data)
|
|
484
|
-
self._last_points = data
|
|
485
|
-
|
|
486
|
-
if box_changed(bounds, self._last_box):
|
|
487
|
-
# new box_select position - update selected box location tab
|
|
488
|
-
self._update_box_location(bounds)
|
|
489
|
-
self._last_box = bounds
|
|
490
|
-
|
|
491
|
-
# Not ready to update plot yet, return last plot.
|
|
492
|
-
return self._last_gui_plot
|
|
493
|
-
|
|
494
|
-
# First plot for input ms, or user clicked Plot button for new inputs
|
|
495
|
-
if (self._set_ms(ms) or self._first_gui_plot) and self._data and self._data.is_valid():
|
|
496
|
-
# New MS set and is valid
|
|
497
|
-
self._update_gui_axis_options()
|
|
498
|
-
|
|
499
|
-
# Add ms path to detect change and make new plot
|
|
500
|
-
self._plot_inputs['ms'] = ms
|
|
501
|
-
|
|
502
|
-
# Do new plot or resend last plot
|
|
503
|
-
self._reset_plot()
|
|
504
|
-
self.clear_selection()
|
|
505
472
|
gui_plot = None
|
|
506
473
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
self._last_plot_inputs = self._plot_inputs.copy()
|
|
530
|
-
self._last_style_inputs = style_inputs.copy()
|
|
531
|
-
self._last_plot_inputs['ps_selection'] = self._plot_inputs['ps_selection'].copy()
|
|
532
|
-
self._last_plot_inputs['ms_selection'] = self._plot_inputs['ms_selection'].copy()
|
|
474
|
+
if self._plot_inputs.get_input('ms'):
|
|
475
|
+
# Start spinner
|
|
476
|
+
self._update_plot_status(True)
|
|
477
|
+
self._update_plot_spinner(True)
|
|
478
|
+
|
|
479
|
+
# Clear last plot
|
|
480
|
+
self._reset_plot()
|
|
481
|
+
self.clear_selection()
|
|
482
|
+
if 'ps_selection' in self._gui_selection or 'ms_selection' in self._gui_selection:
|
|
483
|
+
self._do_gui_selection()
|
|
484
|
+
|
|
485
|
+
# Make plot if first plot or changed plot
|
|
486
|
+
style_inputs = self._raster_plot.get_plot_params()['style']
|
|
487
|
+
plot_inputs = self._plot_inputs.get_inputs()
|
|
488
|
+
if inputs_changed(plot_inputs, self._last_plot_inputs) or inputs_changed(style_inputs, self._last_style_inputs):
|
|
489
|
+
try:
|
|
490
|
+
# Check inputs from GUI then plot
|
|
491
|
+
self._plot_inputs.set_input('data_dims', self._ms_info['data_dims'])
|
|
492
|
+
self._plot_inputs.check_inputs()
|
|
493
|
+
gui_plot = self._do_gui_plot()
|
|
494
|
+
self._last_gui_plot = gui_plot # save plot for locate callback
|
|
495
|
+
self._logger.info("Plot update complete")
|
|
533
496
|
|
|
534
|
-
|
|
535
|
-
|
|
497
|
+
# Put plot with dmap for locate streams in gui panel
|
|
498
|
+
dmap = self._get_locate_dmap(self._locate_gui_points)
|
|
499
|
+
self._gui_panel[0][0][0].object = gui_plot * dmap
|
|
500
|
+
except (ValueError, TypeError, KeyError, RuntimeError) as e:
|
|
501
|
+
# Clear plot, inputs invalid
|
|
502
|
+
self._notify(str(e), 'error', 0)
|
|
536
503
|
|
|
537
|
-
#
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
self._plot_inputs['ms_selection'].clear()
|
|
504
|
+
# Update plot inputs for gui tab
|
|
505
|
+
self._set_plot_params(plot_inputs | style_inputs)
|
|
506
|
+
self._show_plot_inputs()
|
|
541
507
|
|
|
542
|
-
|
|
508
|
+
# Save inputs to check if changed next time
|
|
509
|
+
self._last_plot_inputs = plot_inputs.copy()
|
|
510
|
+
self._last_style_inputs = style_inputs.copy()
|
|
543
511
|
|
|
544
512
|
# Add plot inputs to GUI, change plot button to outline, and stop spinner
|
|
545
|
-
self._show_plot_inputs()
|
|
546
513
|
self._update_plot_status(False)
|
|
547
514
|
self._update_plot_spinner(False)
|
|
548
515
|
|
|
549
|
-
return gui_plot
|
|
550
516
|
# pylint: enable=too-many-arguments, too-many-positional-arguments
|
|
551
517
|
|
|
518
|
+
def _locate_gui_points(self, x, y, data, bounds):
|
|
519
|
+
''' Callback for locate streams '''
|
|
520
|
+
if self._gui_plot_data:
|
|
521
|
+
super()._locate_cursor(x, y, self._gui_plot_data, self._gui_panel[0])
|
|
522
|
+
super()._locate_points(data, self._gui_plot_data, self._gui_panel[0])
|
|
523
|
+
super()._locate_box(bounds, self._gui_plot_data, self._gui_panel[0])
|
|
524
|
+
return self._last_gui_plot
|
|
525
|
+
|
|
552
526
|
def _do_gui_selection(self):
|
|
553
527
|
''' Apply selections selected in GUI '''
|
|
554
|
-
if self.
|
|
555
|
-
self.select_ps(**self.
|
|
556
|
-
if self.
|
|
557
|
-
self.select_ms(**self.
|
|
528
|
+
if self._gui_selection['ps_selection']:
|
|
529
|
+
self.select_ps(**self._gui_selection['ps_selection'])
|
|
530
|
+
if self._gui_selection['ms_selection']:
|
|
531
|
+
self.select_ms(**self._gui_selection['ms_selection'], drop=True)
|
|
558
532
|
|
|
559
533
|
###
|
|
560
534
|
### Create plot for DynamicMap
|
|
561
535
|
###
|
|
562
536
|
def _do_gui_plot(self):
|
|
563
537
|
''' Create plot based on gui plot inputs '''
|
|
564
|
-
if self.
|
|
538
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
565
539
|
try:
|
|
566
|
-
if self._plot_inputs
|
|
540
|
+
if self._plot_inputs.get_input('iter_axis'):
|
|
567
541
|
# Make iter plot (possibly with subplots layout)
|
|
568
|
-
self._do_iter_plot(
|
|
569
|
-
subplots = self._plot_inputs
|
|
570
|
-
layout_plot
|
|
571
|
-
|
|
572
|
-
if is_layout:
|
|
542
|
+
self._do_iter_plot()
|
|
543
|
+
subplots = self._plot_inputs.get_input('subplots')
|
|
544
|
+
layout_plot = super()._layout_plots(subplots)
|
|
545
|
+
if self._plot_inputs.is_layout():
|
|
573
546
|
# Cannot show Layout in DynamicMap, show in new tab
|
|
574
547
|
super().show()
|
|
575
|
-
self.
|
|
576
|
-
return self._last_gui_plot
|
|
548
|
+
return self._last_plot
|
|
577
549
|
# Overlay raster plot for DynamicMap
|
|
578
|
-
self._logger.info("Plot update complete")
|
|
579
550
|
return layout_plot
|
|
580
551
|
|
|
581
552
|
# Make single Overlay raster plot for DynamicMap
|
|
582
|
-
|
|
583
|
-
plot_params = self._raster_plot.get_plot_params()
|
|
553
|
+
gui_plot = self._do_plot(True)
|
|
584
554
|
|
|
585
555
|
# Update color limits in gui with data range
|
|
556
|
+
plot_params = self._raster_plot.get_plot_params()
|
|
586
557
|
self._update_color_range(plot_params)
|
|
587
558
|
|
|
588
|
-
|
|
589
|
-
plot.QuadMesh.I = self._set_plot_colorbar(plot.QuadMesh.I, plot_params, "flagged")
|
|
590
|
-
plot.QuadMesh.II = self._set_plot_colorbar(plot.QuadMesh.II, plot_params, "unflagged")
|
|
591
|
-
|
|
592
|
-
self._logger.info("Plot update complete")
|
|
593
|
-
return plot.opts(
|
|
594
|
-
hv.opts.QuadMesh(
|
|
595
|
-
tools=['hover', 'box_select'],
|
|
596
|
-
selection_fill_alpha=0.5, # dim selected areas of plot
|
|
597
|
-
nonselection_fill_alpha=1.0, # do not dim unselected areas of plot
|
|
598
|
-
)
|
|
599
|
-
)
|
|
559
|
+
return gui_plot
|
|
600
560
|
except RuntimeError as e:
|
|
601
561
|
error = f"Plot failed: {str(e)}"
|
|
602
562
|
super()._notify(error, "error", 0)
|
|
@@ -607,7 +567,7 @@ class MsRaster(MsPlot):
|
|
|
607
567
|
def _create_empty_plot(self):
|
|
608
568
|
''' Create empty Overlay plot for DynamicMap with colormap params and required tools enabled '''
|
|
609
569
|
plot_params = self._raster_plot.get_plot_params()
|
|
610
|
-
|
|
570
|
+
self._empty_plot = hv.Overlay(
|
|
611
571
|
hv.QuadMesh([]).opts(
|
|
612
572
|
colorbar=plot_params['style']['show_flagged_colorbar'],
|
|
613
573
|
cmap=plot_params['style']['flagged_cmap'],
|
|
@@ -619,51 +579,14 @@ class MsRaster(MsPlot):
|
|
|
619
579
|
responsive=True,
|
|
620
580
|
)
|
|
621
581
|
)
|
|
622
|
-
return plot.opts(
|
|
623
|
-
hv.opts.QuadMesh(
|
|
624
|
-
tools=['hover', 'box_select'],
|
|
625
|
-
selection_fill_alpha=0.5, # dim selected areas of plot
|
|
626
|
-
nonselection_fill_alpha=1.0, # do not dim unselected areas of plot
|
|
627
|
-
)
|
|
628
|
-
)
|
|
629
|
-
|
|
630
|
-
def _set_plot_colorbar(self, plot, plot_params, plot_type):
|
|
631
|
-
''' Update plot colorbar labels and limits
|
|
632
|
-
plot_type is "unflagged" or "flagged"
|
|
633
|
-
'''
|
|
634
|
-
# Update colorbar labels if shown, else hide
|
|
635
|
-
colorbar_key = plot_type + '_colorbar'
|
|
636
|
-
if plot_params['plot'][colorbar_key]:
|
|
637
|
-
c_label = plot_params['plot']['axis_labels']['c']['label']
|
|
638
|
-
cbar_title = "Flagged " + c_label if plot_type == "flagged" else c_label
|
|
639
|
-
|
|
640
|
-
plot = plot.opts(
|
|
641
|
-
colorbar=True,
|
|
642
|
-
backend_opts={
|
|
643
|
-
"colorbar.title": cbar_title,
|
|
644
|
-
}
|
|
645
|
-
)
|
|
646
|
-
else:
|
|
647
|
-
plot = plot.opts(
|
|
648
|
-
colorbar=False,
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
# Update plot color limits
|
|
652
|
-
color_limits = plot_params['plot']['color_limits']
|
|
653
|
-
if color_limits:
|
|
654
|
-
plot = plot.opts(
|
|
655
|
-
clim=color_limits,
|
|
656
|
-
)
|
|
657
|
-
|
|
658
|
-
return plot
|
|
659
582
|
|
|
660
583
|
def _update_color_range(self, plot_params):
|
|
661
584
|
''' Set the start/end range on the colorbar to min/max of plot data '''
|
|
662
|
-
if self.
|
|
585
|
+
if self._gui_panel and 'data' in plot_params and 'data_range' in plot_params['data']:
|
|
663
586
|
# Update range slider start and end to data min and max
|
|
664
587
|
data_range = plot_params['data']['data_range']
|
|
665
588
|
style_selectors = self._get_selector('style')
|
|
666
|
-
range_slider = style_selectors[
|
|
589
|
+
range_slider = style_selectors[2][1]
|
|
667
590
|
range_slider.start = data_range[0]
|
|
668
591
|
range_slider.end = data_range[1]
|
|
669
592
|
|
|
@@ -672,13 +595,17 @@ class MsRaster(MsPlot):
|
|
|
672
595
|
###
|
|
673
596
|
def _get_selector(self, name):
|
|
674
597
|
''' Return selector group for name, for setting options '''
|
|
675
|
-
|
|
676
|
-
|
|
598
|
+
if not self._gui_panel:
|
|
599
|
+
return None
|
|
600
|
+
|
|
601
|
+
selectors = self._gui_panel[2][1]
|
|
677
602
|
if name == "selectors":
|
|
678
603
|
return selectors
|
|
604
|
+
|
|
605
|
+
selectors_index = {'file': 0, 'style': 1, 'sel': 2, 'axes': 3, 'agg': 4, 'iter': 5, 'title': 6}
|
|
679
606
|
return selectors[selectors_index[name]]
|
|
680
607
|
|
|
681
|
-
def
|
|
608
|
+
def _update_gui_ms_options(self):
|
|
682
609
|
''' Set gui options from ms data '''
|
|
683
610
|
if 'data_dims' in self._ms_info:
|
|
684
611
|
data_dims = self._ms_info['data_dims']
|
|
@@ -705,7 +632,7 @@ class MsRaster(MsPlot):
|
|
|
705
632
|
# Update options for vis_axis selector
|
|
706
633
|
vis_axis_selector = axis_selectors.objects[2]
|
|
707
634
|
vis_axis_value = vis_axis_selector.value
|
|
708
|
-
if self.
|
|
635
|
+
if self._ms_data.get_correlated_data('base') == 'SPECTRUM':
|
|
709
636
|
vis_axis_selector.options = SPECTRUM_AXIS_OPTIONS
|
|
710
637
|
else:
|
|
711
638
|
vis_axis_selector.options = VIS_AXIS_OPTIONS
|
|
@@ -731,8 +658,8 @@ class MsRaster(MsPlot):
|
|
|
731
658
|
|
|
732
659
|
def _update_ps_selection_options(self, ps_selectors):
|
|
733
660
|
''' Set ProcessingSet gui options from ms summary '''
|
|
734
|
-
if self.
|
|
735
|
-
summary = self.
|
|
661
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
662
|
+
summary = self._ms_data.get_summary()
|
|
736
663
|
if summary is None:
|
|
737
664
|
return
|
|
738
665
|
|
|
@@ -745,11 +672,14 @@ class MsRaster(MsPlot):
|
|
|
745
672
|
options.extend(value)
|
|
746
673
|
else:
|
|
747
674
|
options.append(value)
|
|
748
|
-
|
|
675
|
+
if options:
|
|
676
|
+
selector.options = sorted(list(set(options)))
|
|
677
|
+
else:
|
|
678
|
+
selector.options = ['']
|
|
749
679
|
|
|
750
680
|
def _update_ms_selection_options(self, ms_selectors):
|
|
751
681
|
''' Set MeasurementSet gui options from ms data '''
|
|
752
|
-
if self.
|
|
682
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
753
683
|
for selector in ms_selectors:
|
|
754
684
|
selection_key = MS_SELECTION_OPTIONS[selector.name] if selector.name in MS_SELECTION_OPTIONS else None
|
|
755
685
|
if selection_key:
|
|
@@ -761,28 +691,23 @@ class MsRaster(MsPlot):
|
|
|
761
691
|
###
|
|
762
692
|
### Callbacks for widgets which update other widgets
|
|
763
693
|
###
|
|
764
|
-
def
|
|
694
|
+
def _select_filename(self, filename):
|
|
765
695
|
''' Set filename in text box from file selector value (list) '''
|
|
766
|
-
if filename and self.
|
|
696
|
+
if filename and self._gui_panel:
|
|
767
697
|
file_selectors = self._get_selector('file')
|
|
768
698
|
|
|
769
699
|
# Collapse FileSelector card
|
|
770
700
|
file_selectors[1].collapsed = True
|
|
771
701
|
|
|
772
|
-
#
|
|
702
|
+
# Set filename from last file in file selector
|
|
773
703
|
filename_input = file_selectors[0][0]
|
|
774
|
-
if filename_input.value:
|
|
775
|
-
self._update_plot_status(True)
|
|
776
|
-
|
|
777
|
-
# Set filename from last file in file selector (triggers _update_plot())
|
|
778
|
-
#filename_input.width = len(filename[-1])
|
|
779
704
|
filename_input.value = filename[-1]
|
|
780
705
|
|
|
781
706
|
def _set_iter_values(self, iter_axis):
|
|
782
707
|
''' Set up player with values when iter_axis is selected '''
|
|
783
708
|
iter_axis = None if iter_axis == 'None' else iter_axis
|
|
784
|
-
if iter_axis and self.
|
|
785
|
-
iter_values = self.
|
|
709
|
+
if iter_axis and self._gui_panel:
|
|
710
|
+
iter_values = self._ms_data.get_dimension_values(iter_axis)
|
|
786
711
|
if iter_values:
|
|
787
712
|
|
|
788
713
|
iter_selectors = self._get_selector('iter')
|
|
@@ -812,7 +737,7 @@ class MsRaster(MsPlot):
|
|
|
812
737
|
|
|
813
738
|
def _get_datetime_values(self, float_times):
|
|
814
739
|
''' Return list of float time values as list of datetime values for gui options '''
|
|
815
|
-
time_attrs = self.
|
|
740
|
+
time_attrs = self._ms_data.get_dimension_attrs('time')
|
|
816
741
|
datetime_values = []
|
|
817
742
|
try:
|
|
818
743
|
datetime_values = to_datetime(float_times, unit=time_attrs['units'], origin=time_attrs['format'])
|
|
@@ -822,118 +747,40 @@ class MsRaster(MsPlot):
|
|
|
822
747
|
|
|
823
748
|
def _update_plot_spinner(self, plot_clicked):
|
|
824
749
|
''' Callback to start spinner when Plot button clicked. '''
|
|
825
|
-
if self.
|
|
750
|
+
if self._gui_panel:
|
|
826
751
|
# Start spinner
|
|
827
|
-
spinner = self.
|
|
752
|
+
spinner = self._gui_panel[2][2][1]
|
|
828
753
|
spinner.value = plot_clicked
|
|
829
754
|
|
|
830
755
|
def _update_plot_status(self, plot_changed):
|
|
831
756
|
''' Change button color when plot inputs change. '''
|
|
832
|
-
if self.
|
|
757
|
+
if self._gui_panel:
|
|
833
758
|
# Set button color
|
|
834
|
-
button = self.
|
|
759
|
+
button = self._gui_panel[2][2][0]
|
|
835
760
|
button.button_style = 'solid' if plot_changed else 'outline'
|
|
836
761
|
|
|
837
762
|
def _show_plot_inputs(self):
|
|
838
|
-
''' Show inputs for raster plot in GUI tab '''
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
inputs_column.clear()
|
|
842
|
-
for param in self._plot_params:
|
|
843
|
-
str_pane = pn.pane.Str(param)
|
|
844
|
-
str_pane.margin = (0, 10)
|
|
845
|
-
inputs_column.append(str_pane)
|
|
846
|
-
|
|
847
|
-
def _update_cursor_location(self, x, y):
|
|
848
|
-
''' Show data values for cursor x,y position in cursor location box below plot '''
|
|
849
|
-
# Convert plot values to selection values to select plot data
|
|
850
|
-
x_axis = self._plot_inputs['x_axis']
|
|
851
|
-
y_axis = self._plot_inputs['y_axis']
|
|
852
|
-
cursor_position = {x_axis: x, y_axis: y}
|
|
853
|
-
cursor_location = locate_point(self._gui_plot_data, cursor_position, self._plot_inputs['vis_axis'])
|
|
854
|
-
|
|
855
|
-
cursor_location_box = self._gui_layout[0][0][1] # row[0] tabs[0] column[1]
|
|
856
|
-
cursor_location_box.clear() # pn.WidgetBox
|
|
857
|
-
location_layout = pn.Column(pn.widgets.StaticText(name="Cursor Location"))
|
|
858
|
-
location_row = self._layout_point_location(cursor_location)
|
|
859
|
-
# Add row of columns to column layout
|
|
860
|
-
location_layout.append(location_row)
|
|
861
|
-
# Add column layout to widget box
|
|
862
|
-
cursor_location_box.append(location_layout)
|
|
863
|
-
|
|
864
|
-
def _layout_point_location(self, text_list):
|
|
865
|
-
''' Layout list of StaticText in row of columns containing 3 rows '''
|
|
866
|
-
location_row = pn.Row()
|
|
867
|
-
location_col = pn.Column()
|
|
868
|
-
|
|
869
|
-
for static_text in text_list:
|
|
870
|
-
# 3 entries per column; append to row and start new column
|
|
871
|
-
if len(location_col.objects) == 3:
|
|
872
|
-
location_row.append(location_col)
|
|
873
|
-
location_col = pn.Column()
|
|
874
|
-
|
|
875
|
-
static_text.margin = (0, 10) # default (5, 10)
|
|
876
|
-
location_col.append(static_text)
|
|
877
|
-
|
|
878
|
-
# Add last column
|
|
879
|
-
location_row.append(location_col)
|
|
880
|
-
return location_row
|
|
881
|
-
|
|
882
|
-
def _update_points_location(self, data):
|
|
883
|
-
''' Show data values for points in point_draw in tab and log '''
|
|
884
|
-
points_locate_column = self._gui_layout[0][2] # row[0] tabs[2]
|
|
885
|
-
points_locate_column.clear()
|
|
886
|
-
points = list(zip(data['x'], data['y']))
|
|
887
|
-
|
|
888
|
-
if points:
|
|
889
|
-
self._logger.info("Locate selected points:")
|
|
890
|
-
x_axis = self._plot_inputs['x_axis']
|
|
891
|
-
y_axis = self._plot_inputs['y_axis']
|
|
892
|
-
|
|
893
|
-
for point in list(zip(data['x'], data['y'])):
|
|
894
|
-
# Locate point
|
|
895
|
-
point_position = {x_axis: point[0], y_axis: point[1]}
|
|
896
|
-
point_location = locate_point(self._gui_plot_data, point_position, self._plot_inputs['vis_axis'])
|
|
897
|
-
# Format location and add to points locate column
|
|
898
|
-
location_layout = self._layout_point_location(point_location)
|
|
899
|
-
points_locate_column.append(location_layout)
|
|
900
|
-
points_locate_column.append(pn.layout.Divider())
|
|
901
|
-
|
|
902
|
-
# Format and add to log
|
|
903
|
-
location_list = [f"{static_text.name}={static_text.value}" for static_text in point_location]
|
|
904
|
-
self._logger.info(", ".join(location_list))
|
|
905
|
-
|
|
906
|
-
def _update_box_location(self, bounds):
|
|
907
|
-
''' Show data values for points in box_select in tab and log '''
|
|
908
|
-
box_locate_column = self._gui_layout[0][3] # row[0] tabs[3]
|
|
909
|
-
box_locate_column.clear()
|
|
910
|
-
if bounds:
|
|
911
|
-
x_axis = self._plot_inputs['x_axis']
|
|
912
|
-
y_axis = self._plot_inputs['y_axis']
|
|
913
|
-
box_bounds = {x_axis: (bounds[0], bounds[2]), y_axis: (bounds[1], bounds[3])}
|
|
914
|
-
npoints, point_locations = locate_box(self._gui_plot_data, box_bounds, self._plot_inputs['vis_axis'])
|
|
915
|
-
|
|
916
|
-
message = f"Locate {npoints} points"
|
|
917
|
-
message += " (only first 100 shown):" if npoints > 100 else ":"
|
|
918
|
-
self._logger.info(message)
|
|
919
|
-
box_locate_column.append(pn.pane.Str(message))
|
|
920
|
-
|
|
921
|
-
for point in point_locations:
|
|
922
|
-
# Format and add to box locate column
|
|
923
|
-
location_layout = self._layout_point_location(point)
|
|
924
|
-
box_locate_column.append(location_layout)
|
|
925
|
-
box_locate_column.append(pn.layout.Divider())
|
|
926
|
-
|
|
927
|
-
# Format and add to log
|
|
928
|
-
location_list = [f"{static_text.name}={static_text.value}" for static_text in point]
|
|
929
|
-
self._logger.info(", ".join(location_list))
|
|
763
|
+
''' Show inputs for raster plot in column in GUI tab '''
|
|
764
|
+
inputs_column = self._gui_panel[0][1]
|
|
765
|
+
super()._fill_inputs_column(inputs_column)
|
|
930
766
|
|
|
931
767
|
###
|
|
932
768
|
### Callbacks for widgets which update plot inputs
|
|
933
769
|
###
|
|
770
|
+
def _set_filename(self, filename):
|
|
771
|
+
''' Set ms input from file text input '''
|
|
772
|
+
self._plot_inputs.set_input('ms', filename)
|
|
773
|
+
if self._set_ms(filename):
|
|
774
|
+
# New MS set, update gui input options
|
|
775
|
+
try:
|
|
776
|
+
self._update_gui_ms_options()
|
|
777
|
+
self._update_plot_status(True) # Change plot button to solid
|
|
778
|
+
except AttributeError:
|
|
779
|
+
self._update_plot_status(False)
|
|
780
|
+
|
|
934
781
|
def _set_title(self, title):
|
|
935
782
|
''' Set title from gui text input '''
|
|
936
|
-
self._plot_inputs
|
|
783
|
+
self._plot_inputs.set_input('title', title)
|
|
937
784
|
self._update_plot_status(True) # Change plot button to solid
|
|
938
785
|
|
|
939
786
|
def _set_style_params(self, unflagged_cmap, flagged_cmap, show_colorbar, show_flagged_colorbar):
|
|
@@ -942,65 +789,59 @@ class MsRaster(MsPlot):
|
|
|
942
789
|
|
|
943
790
|
def _set_color_range(self, color_mode, color_range):
|
|
944
791
|
''' Set style params from gui '''
|
|
945
|
-
color_mode
|
|
946
|
-
color_mode = None if color_mode == 'No' else color_mode
|
|
947
|
-
self._plot_inputs['color_mode'] = color_mode
|
|
948
|
-
self._plot_inputs['color_range'] = color_range
|
|
792
|
+
self._plot_inputs.set_color_inputs(color_mode, color_range)
|
|
949
793
|
self._update_plot_status(True) # Change plot button to solid
|
|
950
794
|
|
|
951
795
|
def _set_axes(self, x_axis, y_axis, vis_axis):
|
|
952
|
-
''' Set plot axis
|
|
953
|
-
self._plot_inputs
|
|
954
|
-
self._plot_inputs['y_axis'] = y_axis
|
|
955
|
-
self._plot_inputs['vis_axis'] = vis_axis
|
|
796
|
+
''' Set plot axis inputs from gui '''
|
|
797
|
+
self._plot_inputs.set_axis_inputs(x_axis, y_axis, vis_axis)
|
|
956
798
|
self._update_plot_status(True) # Change plot button to solid
|
|
957
799
|
|
|
958
800
|
def _set_aggregation(self, aggregator, agg_axes):
|
|
959
801
|
''' Set aggregation params from gui '''
|
|
960
|
-
aggregator
|
|
961
|
-
self._plot_inputs['aggregator'] = aggregator
|
|
962
|
-
self._plot_inputs['agg_axis'] = agg_axes # ignored if aggregator not set
|
|
802
|
+
self._plot_inputs.set_aggregation_inputs(aggregator, agg_axes)
|
|
963
803
|
self._update_plot_status(True) # Change plot button to solid
|
|
964
804
|
|
|
965
805
|
# pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
966
806
|
def _set_iteration(self, iter_axis, iter_value_type, iter_value, iter_start, iter_end, subplot_rows, subplot_columns):
|
|
967
807
|
''' Set iteration params from gui '''
|
|
968
808
|
iter_axis = None if iter_axis == 'None' else iter_axis
|
|
969
|
-
|
|
970
|
-
self._plot_inputs['subplots'] = (subplot_rows, subplot_columns)
|
|
971
|
-
|
|
809
|
+
iter_range = None
|
|
972
810
|
if iter_axis:
|
|
811
|
+
# Set iter_range
|
|
973
812
|
if iter_value_type == 'By Value':
|
|
974
813
|
# Use index of iter_value for tuple
|
|
975
|
-
if self.
|
|
976
|
-
iter_values = self.
|
|
814
|
+
if self._ms_data and self._ms_data.is_valid():
|
|
815
|
+
iter_values = self._ms_data.get_dimension_values(iter_axis)
|
|
977
816
|
iter_index = iter_values.index(iter_value)
|
|
978
|
-
|
|
817
|
+
iter_range = (iter_index, iter_index)
|
|
979
818
|
else:
|
|
980
819
|
# 'By Range': use range start and end values for tuple
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
820
|
+
iter_range = (iter_start, iter_end)
|
|
821
|
+
|
|
822
|
+
self._plot_inputs.set_iteration_inputs(iter_axis, iter_range, subplot_rows, subplot_columns)
|
|
984
823
|
self._update_plot_status(True) # Change plot button to solid
|
|
824
|
+
# pylint: enable=too-many-arguments, too-many-positional-arguments
|
|
985
825
|
|
|
826
|
+
# pylint: disable=too-many-arguments, too-many-positional-arguments, unused-argument
|
|
986
827
|
def _set_ps_selection(self, query, name, intents, scan_name, spw_name, field_name, source_name, line_name):
|
|
987
|
-
'''
|
|
828
|
+
''' Set ProcessingSet selection from gui using summary columns '''
|
|
988
829
|
inputs = locals()
|
|
989
830
|
ps_selection = {}
|
|
990
831
|
for key, val in inputs.items():
|
|
991
832
|
if key in PS_SELECTION_OPTIONS.values() and val:
|
|
992
833
|
ps_selection[key] = val
|
|
993
|
-
self.
|
|
834
|
+
self._gui_selection['ps_selection'] = ps_selection
|
|
994
835
|
self._update_plot_status(True) # Change plot button to solid
|
|
995
836
|
|
|
996
837
|
def _set_ms_selection(self, data_group, datetime, baseline, antenna1, antenna2, frequency, polarization):
|
|
997
|
-
'''
|
|
838
|
+
''' Set MeasurementSet selection from gui using data group, dimensions, and coordinates '''
|
|
998
839
|
inputs = locals()
|
|
999
840
|
inputs['time'] = inputs.pop('datetime')
|
|
1000
841
|
ms_selection = {}
|
|
1001
842
|
for key, val in inputs.items():
|
|
1002
843
|
if key in MS_SELECTION_OPTIONS.values() and val:
|
|
1003
844
|
ms_selection[key] = val
|
|
1004
|
-
self.
|
|
845
|
+
self._gui_selection['ms_selection'] = ms_selection
|
|
1005
846
|
self._update_plot_status(True) # Change plot button to solid
|
|
1006
847
|
# pylint: enable=too-many-arguments, too-many-positional-arguments, unused-argument
|