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.
@@ -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
- # Return plot for gui DynamicMap: empty plot when ms not set or plot fails
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, which triggers default plot
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([self._ms_info['ms']]) # function expects list from FileBrowser widget
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._data and self._data.is_valid():
106
+ if self._ms_data and self._ms_data.is_valid():
103
107
  try:
104
- self._plot_inputs['selection'] |= kwargs
105
- if 'data_group_name' in kwargs:
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._data and self._data.is_valid():
133
+ if self._ms_data and self._ms_data.is_valid():
132
134
  try:
133
- self._plot_inputs['selection'] |= indexers_kwargs
134
- self._data.select_ms(indexers=indexers, method=method, tolerance=tolerance, drop=drop, **indexers_kwargs)
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 (not unused as pylint complains!)
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
- inputs['data_dims'] = self._ms_info['data_dims'] if 'data_dims' in self._ms_info else None
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
- # Validate input arguments then set
196
- check_inputs(inputs)
197
- self._set_plot_inputs(inputs)
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._data or not self._data.is_valid():
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['iter_axis']:
207
- self._do_iter_plot(self._plot_inputs)
209
+ if self._plot_inputs.get_input('iter_axis'):
210
+ self._do_iter_plot()
208
211
  else:
209
- plot = self._do_plot(self._plot_inputs)
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 _set_plot_inputs(self, plot_inputs):
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(plot_inputs)
248
+ self._init_plot()
251
249
 
252
250
  # Select vis_axis data to plot and update selection; returns xarray Dataset
253
- raster_data = self._data.get_raster_data(plot_inputs)
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._is_layout():
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, (self._plot_inputs['x_axis'], self._plot_inputs['y_axis']))
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, (self._plot_inputs['x_axis'], self._plot_inputs['y_axis']))
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(plot_inputs) # set calculated limits if auto mode
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
- self._logger.info("MsRaster plot parameters: %s", ", ".join(self._plot_params))
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, plot_inputs):
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 = plot_inputs['iter_axis']
280
- iter_range = plot_inputs['iter_range']
281
- subplots = plot_inputs['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(plot_inputs)
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
- # Set each iter value in selection
304
- if 'selection' not in plot_inputs:
305
- plot_inputs['selection'] = {}
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
- plot_inputs['selection'][iter_axis] = value
315
+ self._plot_inputs.set_selection({iter_axis: value})
312
316
  try:
313
- plot = self._do_plot(plot_inputs)
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, plot_inputs):
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
- try:
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' not in plot_inputs:
331
+ if not self._plot_inputs.get_input('data_group'):
331
332
  auto_selection['data_group_name'] = 'base'
332
- plot_inputs['data_group'] = 'base'
333
- if 'selection' not in plot_inputs or 'spw_name' not in plot_inputs['selection']:
334
- first_spw = self._data.get_first_spw(plot_inputs['data_group'])
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
- plot_inputs['auto_spw'] = first_spw # do not add to user selection
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._data.select_ps(query=None, string_exact_match=True, **auto_selection)
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._data.get_num_ms())
345
- self._logger.info("Maximum dimensions for selected spw: %s", self._data.get_max_data_dims())
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 _is_layout(self):
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 = plot_inputs['color_mode']
367
- color_limits = None
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 plot_inputs['vis_axis']=='amp' and not plot_inputs['aggregator']:
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['selection']['spw_name'] if ('selection' in plot_inputs and 'spw_name' in plot_inputs['selection']) else self._plot_inputs['auto_spw']
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
- color_limits = self._spw_color_limits[spw_name]
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['data_group']
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
- color_limits = self._calc_amp_color_limits(spw_data_selection)
380
- self._spw_color_limits[spw_name] = color_limits
381
- plot_inputs['auto_color_range'] = color_limits
382
-
383
- if color_limits:
384
- self._logger.info("Setting amplitude color range: (%.4f, %.4f).", color_limits[0], color_limits[1])
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", plot_inputs['color_range'])
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._data.get_vis_stats(selection, 'amp')
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 set for last plot
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
- 'filename': self._set_filename,
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
- x_axis = self._plot_inputs['x_axis']
447
- y_axis = self._plot_inputs['y_axis']
448
- self._gui_layout = create_raster_gui(callbacks, data_dims, x_axis, y_axis)
449
- self._gui_layout.show(title=self._app_name, threaded=True)
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, ms, do_plot, x, y, data, bounds):
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
- # Make plot if first plot or changed plot
508
- style_inputs = self._raster_plot.get_plot_params()['style']
509
- if inputs_changed(self._plot_inputs, self._last_plot_inputs) or inputs_changed(style_inputs, self._last_style_inputs):
510
- try:
511
- # Check inputs from GUI then plot
512
- self._plot_inputs['data_dims'] = self._ms_info['data_dims']
513
- check_inputs(self._plot_inputs)
514
- if 'ps_selection' in self._plot_inputs or 'ms_selection' in self._plot_inputs:
515
- self._do_gui_selection()
516
- gui_plot = self._do_gui_plot()
517
- except (ValueError, TypeError, KeyError, RuntimeError) as e:
518
- # Clear plot, inputs invalid
519
- self._notify(str(e), 'error', 0)
520
- gui_plot = self._empty_plot
521
- else:
522
- # Subparam values changed but not applied to plot
523
- gui_plot = self._last_gui_plot
524
-
525
- # Update plot inputs for gui
526
- self._set_plot_params(self._plot_inputs | style_inputs)
527
-
528
- # Save inputs to see if changed next time
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
- # Save plot for return value if plot update not requested
535
- self._last_gui_plot = gui_plot
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
- # Remove selection not from user
538
- if self._first_gui_plot and not do_plot:
539
- self._plot_inputs['ps_selection'].clear()
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
- self._first_gui_plot = False
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._plot_inputs['ps_selection']:
555
- self.select_ps(**self._plot_inputs['ps_selection'])
556
- if self._plot_inputs['ms_selection']:
557
- self.select_ms(**self._plot_inputs['ms_selection'])
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._data and self._data.is_valid():
538
+ if self._ms_data and self._ms_data.is_valid():
565
539
  try:
566
- if self._plot_inputs['iter_axis']:
540
+ if self._plot_inputs.get_input('iter_axis'):
567
541
  # Make iter plot (possibly with subplots layout)
568
- self._do_iter_plot(self._plot_inputs)
569
- subplots = self._plot_inputs['subplots']
570
- layout_plot, is_layout = super()._layout_plots(subplots)
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._logger.info("Plot update complete")
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
- plot = self._do_plot(self._plot_inputs, True)
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
- # Update colorbar labels and limits
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
- plot = hv.Overlay(
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._gui_layout and 'data' in plot_params and 'data_range' in plot_params['data']:
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[3][1]
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
- selectors = self._gui_layout[2][1]
676
- selectors_index = {'file': 0, 'style': 1, 'sel': 2, 'axes': 3, 'agg': 4, 'iter': 5, 'title': 6}
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 _update_gui_axis_options(self):
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._data.get_correlated_data('base') == 'SPECTRUM':
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._data and self._data.is_valid():
735
- summary = self._data.get_summary()
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
- selector.options = sorted(list(set(options)))
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._data and self._data.is_valid():
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 _set_filename(self, filename):
694
+ def _select_filename(self, filename):
765
695
  ''' Set filename in text box from file selector value (list) '''
766
- if filename and self._gui_layout:
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
- # Change plot button color to indicate change unless ms path not set previously
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._gui_layout:
785
- iter_values = self._data.get_dimension_values(iter_axis)
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._data.get_dimension_attrs('time')
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._gui_layout:
750
+ if self._gui_panel:
826
751
  # Start spinner
827
- spinner = self._gui_layout[2][2][1]
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._gui_layout:
757
+ if self._gui_panel:
833
758
  # Set button color
834
- button = self._gui_layout[2][2][0]
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
- if self._plot_params:
840
- inputs_column = self._gui_layout[0][1]
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['title'] = title
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 = color_mode.split()[0]
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 params from gui '''
953
- self._plot_inputs['x_axis'] = x_axis
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 = None if aggregator== 'None' else 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
- self._plot_inputs['iter_axis'] = iter_axis
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._data and self._data.is_valid():
976
- iter_values = self._data.get_dimension_values(iter_axis)
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
- self._plot_inputs['iter_range'] = (iter_index, iter_index)
817
+ iter_range = (iter_index, iter_index)
979
818
  else:
980
819
  # 'By Range': use range start and end values for tuple
981
- self._plot_inputs['iter_range'] = (iter_start, iter_end)
982
- else:
983
- self._plot_inputs['iter_range'] = None
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
- ''' Select ProcessingSet from gui using summary columns '''
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._plot_inputs['ps_selection'] = ps_selection
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
- ''' Select MeasurementSet from gui using data group, dimensions, and coordinates '''
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._plot_inputs['ms_selection'] = ms_selection
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