vidavis 0.1.3__tar.gz → 0.1.4__tar.gz

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.
Files changed (39) hide show
  1. {vidavis-0.1.3 → vidavis-0.1.4}/PKG-INFO +1 -1
  2. {vidavis-0.1.3 → vidavis-0.1.4}/pyproject.toml +1 -1
  3. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/apps/_ms_raster.py +5 -4
  4. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_raster_data.py +1 -1
  5. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_locate_points.py +60 -65
  6. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_ms_plot.py +93 -35
  7. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_raster_plot_gui.py +4 -4
  8. {vidavis-0.1.3 → vidavis-0.1.4}/LICENSE +0 -0
  9. {vidavis-0.1.3 → vidavis-0.1.4}/readme.rst +0 -0
  10. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/LICENSE.rst +0 -0
  11. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/__init__.py +0 -0
  12. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/apps/__init__.py +0 -0
  13. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/bokeh/__init__.py +0 -0
  14. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/bokeh/_palette.py +0 -0
  15. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/__init__.py +0 -0
  16. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/__init__.py +0 -0
  17. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/_ms_data.py +0 -0
  18. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/__init__.py +0 -0
  19. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_concat.py +0 -0
  20. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_coords.py +0 -0
  21. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_data.py +0 -0
  22. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_io.py +0 -0
  23. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_select.py +0 -0
  24. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_ps_stats.py +0 -0
  25. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/data/measurement_set/processing_set/_xds_data.py +0 -0
  26. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/__init__.py +0 -0
  27. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/__init__.py +0 -0
  28. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_check_raster_inputs.py +0 -0
  29. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_ms_plot_constants.py +0 -0
  30. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_ms_plot_selectors.py +0 -0
  31. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_plot_inputs.py +0 -0
  32. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_raster_plot.py +0 -0
  33. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_raster_plot_inputs.py +0 -0
  34. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_time_ticks.py +0 -0
  35. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/plot/ms_plot/_xds_plot_axes.py +0 -0
  36. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/toolbox/__init__.py +0 -0
  37. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/toolbox/_app_context.py +0 -0
  38. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/toolbox/_logging.py +0 -0
  39. {vidavis-0.1.3 → vidavis-0.1.4}/src/vidavis/toolbox/_static.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vidavis
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Radio astronomy visibility data visualization
5
5
  License: LGPL
6
6
  Author-email: Darrell Schiebel <darrell@schiebel.us>,Pam Harris <pharris@nrao.edu>
@@ -16,7 +16,7 @@ dependencies = [
16
16
  ]
17
17
  requires-python = ">=3.11, <3.14"
18
18
  readme = "readme.rst"
19
- version = "0.1.3"
19
+ version = "0.1.4"
20
20
 
21
21
  [project.license]
22
22
  text = "LGPL"
@@ -521,15 +521,16 @@ class MsRaster(MsPlot):
521
521
  # Add plot inputs to GUI, change plot button to outline, and stop spinner
522
522
  self._update_plot_status(False)
523
523
  self._update_plot_spinner(False)
524
-
525
524
  # pylint: enable=too-many-arguments, too-many-positional-arguments
526
525
 
527
- def _locate_gui_points(self, x, y, data, bounds):
526
+ def _locate_gui_points(self, x, y, data, boxes):
528
527
  ''' Callback for locate streams '''
529
528
  if self._gui_plot_data:
529
+ if super()._locate_points(data, self._gui_plot_data, self._gui_panel[2]):
530
+ return self._last_gui_plot
531
+ if super()._locate_boxes(boxes, self._gui_plot_data, self._gui_panel[3]):
532
+ return self._last_gui_plot
530
533
  super()._locate_cursor(x, y, self._gui_plot_data, self._gui_panel[0][1])
531
- super()._locate_points(data, self._gui_plot_data, self._gui_panel[2])
532
- super()._locate_box(bounds, self._gui_plot_data, self._gui_panel[3])
533
534
  return self._last_gui_plot
534
535
 
535
536
  def _do_gui_selection(self):
@@ -30,7 +30,7 @@ def raster_data(ps_xdt, plot_inputs, logger):
30
30
  raise RuntimeError("Plot failed: raster plane selection yielded data with all nan values.")
31
31
 
32
32
  # Compute complex component of vis data
33
- raster_xds[correlated_data] = get_axis_data(raster_xds, plot_inputs['vis_axis'], data_group).compute()
33
+ raster_xds[correlated_data] = get_axis_data(raster_xds, plot_inputs['vis_axis'], data_group)
34
34
 
35
35
  # Convert float time to datetime
36
36
  set_datetime_coordinate(raster_xds)
@@ -10,32 +10,41 @@ import panel as pn
10
10
 
11
11
  from vidavis.plot.ms_plot._ms_plot_constants import TIME_FORMAT
12
12
 
13
- def cursor_changed(cursor, last_cursor):
14
- ''' Check whether cursor position changed '''
15
- x, y = cursor
16
- if not x and not y:
17
- return False # not cursor callback
18
- if last_cursor and last_cursor == (x, y):
19
- return False # same cursor
20
- return True # new cursor or cursor changed
21
-
22
- def points_changed(data, last_points):
23
- ''' Check whether point positions changed '''
24
- # No data = {'x': [], 'y': []}
25
- if not data or (len(data['x']) == 0 and len(data['y']) == 0):
26
- return False # not points callback
27
- if last_points and last_points == data:
28
- return False # same points
29
- return True # new points, points changed, or points deleted
30
-
31
- def box_changed(bounds, last_box):
32
- ''' Check whether box position changed '''
33
- # No bounds = None
34
- if not bounds:
35
- return False # no data, not box select callback
36
- if last_box and last_box == bounds:
37
- return False # same box
38
- return True # new box, box changed, or box deleted
13
+ def get_locate_value(xds, coord, value):
14
+ ''' Convert index coordinates to int and float time coordinate to datetime. Select nearest value <= value. '''
15
+ if coord in ['baseline', 'antenna_name', 'polarization']:
16
+ # Convert float to int index value
17
+ return round(value)
18
+
19
+ if coord in ['time', 'frequency']:
20
+ if coord=='time' and isinstance(value, float):
21
+ # Convert float to datetime value
22
+ # Bokeh datetime values are floating point values that represent milliseconds-since-epoch (unix time)
23
+ value = to_datetime(value, unit='ms')
24
+ value_sel = {coord: value}
25
+ nearest_value = xds[coord].sel(indexers=None, method='nearest', tolerance=None, drop=False, **value_sel).values
26
+ return nearest_value
27
+
28
+ return value
29
+
30
+ def data_changed(data, last_data):
31
+ ''' Check whether data changed, input as list of tuples '''
32
+ if not data:
33
+ return False # not callback for this data
34
+ if last_data and len(last_data) == len(data) and last_data == data:
35
+ return False # same data
36
+ return True # new data, data changed, or data removed
37
+
38
+ def get_new_data(data, last_data):
39
+ ''' Return data not in last_data, input as list of tuples '''
40
+ new_data = []
41
+ if last_data:
42
+ for info in data:
43
+ if info not in last_data:
44
+ new_data.append(info)
45
+ else:
46
+ new_data = data
47
+ return new_data
39
48
 
40
49
  def update_cursor_location(cursor, plot_axes, xds, cursor_locate_box):
41
50
  ''' Show data values for cursor x,y position in cursor location box (pn.WidgetBox) '''
@@ -47,42 +56,40 @@ def update_cursor_location(cursor, plot_axes, xds, cursor_locate_box):
47
56
  cursor_position = {x_axis: x, y_axis: y}
48
57
  cursor_location = _locate_point(xds, cursor_position, vis_axis)
49
58
 
50
- location_column = pn.Column(pn.widgets.StaticText(name="CURSOR LOCATION"))
51
59
  # Add row of columns to column layout
60
+ location_column = pn.Column(pn.widgets.StaticText(name="CURSOR LOCATION"))
52
61
  location_row = _layout_point_location(cursor_location)
53
62
  location_column.append(location_row)
63
+
54
64
  # Add location column to widget box
55
65
  cursor_locate_box.append(location_column)
56
66
 
57
- def update_points_location(data, plot_axes, xds, points_tab_feed):
67
+ def update_points_location(points, plot_axes, xds, points_tab_feed):
58
68
  ''' Show data values for points in point_draw in tab and log '''
59
- points_tab_feed.clear()
60
69
  locate_log = []
61
- if data:
62
- x_axis, y_axis, vis_axis = plot_axes
63
- message = f"Locate {len(data['x'])} points:"
64
- locate_log.append(message)
65
- for point in list(zip(data['x'], data['y'])):
66
- # Locate point
67
- point_position = {x_axis: point[0], y_axis: point[1]}
68
- point_location = _locate_point(xds, point_position, vis_axis)
69
- # Format location and add to points locate column
70
- location_layout = _layout_point_location(point_location)
71
- points_tab_feed.append(location_layout)
72
- points_tab_feed.append(pn.layout.Divider())
73
-
74
- # Format and add to log
75
- location_list = [f"{static_text.name}={static_text.value}" for static_text in point_location]
76
- locate_log.append(", ".join(location_list))
70
+ x_axis, y_axis, vis_axis = plot_axes
71
+ for point in points:
72
+ # Locate point
73
+ point_position = {x_axis: point[0], y_axis: point[1]}
74
+ point_location = _locate_point(xds, point_position, vis_axis)
75
+
76
+ # Format location and add to points locate column
77
+ location_layout = _layout_point_location(point_location)
78
+ points_tab_feed.append(location_layout)
79
+ points_tab_feed.append(pn.layout.Divider())
80
+
81
+ # Format and add to log
82
+ location_list = [f"{static_text.name}={static_text.value}" for static_text in point_location]
83
+ locate_log.append(", ".join(location_list))
77
84
  return locate_log
78
85
 
79
- def update_box_location(bounds, plot_axes, xds, box_tab_feed):
86
+ # pylint: disable=too-many-locals
87
+ def update_boxes_location(boxes, plot_axes, xds, box_tab_feed):
80
88
  ''' Show data values for points in box_select in tab and log '''
81
- box_tab_feed.clear()
82
89
  locate_log = []
83
- if bounds:
84
- x_axis, y_axis, vis_axis = plot_axes
85
- box_bounds = {x_axis: (bounds[0], bounds[2]), y_axis: (bounds[1], bounds[3])}
90
+ x_axis, y_axis, vis_axis = plot_axes
91
+ for box in boxes:
92
+ box_bounds = {x_axis: (box[0], box[2]), y_axis: (box[1], box[3])}
86
93
  npoints, point_locations = _locate_box(xds, box_bounds, vis_axis)
87
94
 
88
95
  message = f"Locate {npoints} points"
@@ -100,6 +107,7 @@ def update_box_location(bounds, plot_axes, xds, box_tab_feed):
100
107
  location_list = [f"{static_text.name}={static_text.value}" for static_text in point]
101
108
  locate_log.append(", ".join(location_list))
102
109
  return locate_log
110
+ # pylint: enable=too-many-locals
103
111
 
104
112
  def _locate_point(xds, position, vis_axis):
105
113
  '''
@@ -141,8 +149,9 @@ def _locate_box(xds, bounds, vis_axis):
141
149
  selection = {}
142
150
  for coord, val in bounds.items():
143
151
  # Round index values to int for selection
144
- selection[coord] = slice(_get_selection_value(coord, val[0]), _get_selection_value(coord, val[1]))
152
+ selection[coord] = slice(get_locate_value(xds, coord, val[0]), get_locate_value(xds, coord, val[1]))
145
153
  sel_xds = xds.sel(indexers=None, method=None, tolerance=None, drop=False, **selection)
154
+ sel_xds.compute()
146
155
 
147
156
  x_coord, y_coord = bounds.keys()
148
157
  npoints = sel_xds.sizes[x_coord] * sel_xds.sizes[y_coord]
@@ -175,10 +184,6 @@ def _get_point_location(xds, position, vis_axis):
175
184
 
176
185
  if xds:
177
186
  try:
178
- for coord, value in position.items():
179
- # Round index coordinates to int and convert time to datetime if float for selection
180
- position[coord] = _get_selection_value(coord, value)
181
-
182
187
  sel_xds = xds.sel(indexers=None, method='nearest', tolerance=None, drop=False, **position)
183
188
  for coord in sel_xds.coords:
184
189
  if coord == 'uvw_label' or ('baseline_antenna' in coord and 'baseline_name' in sel_xds.coords):
@@ -206,16 +211,6 @@ def _get_point_location(xds, position, vis_axis):
206
211
  values[vis_axis.upper()] = values.pop('VISIBILITY')
207
212
  return values, units
208
213
 
209
- def _get_selection_value(coord, value):
210
- ''' Convert index coordinates to int and float time coordinate to datetime '''
211
- if coord in ['baseline', 'antenna_name', 'polarization']:
212
- # Round index coordinates to int for selecction
213
- value = round(value)
214
- elif coord == 'time' and isinstance(value, float):
215
- # Bokeh datetime values are floating-point numbers: milliseconds since the Unix epoch
216
- value = to_datetime(value, unit='ms', origin='unix')
217
- return value
218
-
219
214
  def _get_xda_val_unit(xda):
220
215
  ''' Return value and unit of xda (selected so only one value) '''
221
216
  # Value
@@ -17,7 +17,7 @@ from selenium import webdriver
17
17
  from toolviper.utils.logger import setup_logger
18
18
 
19
19
  from vidavis.data.measurement_set._ms_data import MsData
20
- from vidavis.plot.ms_plot._locate_points import cursor_changed, points_changed, box_changed, update_cursor_location, update_points_location, update_box_location
20
+ from vidavis.plot.ms_plot._locate_points import get_locate_value, data_changed, get_new_data, update_cursor_location, update_points_location, update_boxes_location
21
21
  from vidavis.toolbox import AppContext
22
22
 
23
23
  class MsPlot:
@@ -73,9 +73,10 @@ class MsPlot:
73
73
  self._plot_axes = None
74
74
  self._last_cursor = None
75
75
  self._last_points = None
76
- self._last_box = None
76
+ self._last_boxes = None
77
77
  self._locate_plot_options = {
78
- 'tools': ['box_select', 'hover'],
78
+ 'tools': ['hover'],
79
+ 'muted_alpha': 0,
79
80
  'selection_fill_alpha': 0.2, # dim selected areas of plot
80
81
  'nonselection_fill_alpha': 1.0, # do not dim unselected areas of plot
81
82
  }
@@ -189,10 +190,11 @@ class MsPlot:
189
190
  if inputs_column:
190
191
  self._show_panel.append(('Plot Inputs', inputs_column))
191
192
  else:
192
- plot = plot.opts(
193
+ plot = plot.options(
193
194
  hv.opts.QuadMesh(**self._locate_plot_options),
194
- hv.opts.Scatter(**self._locate_plot_options)
195
+ hv.opts.Scatter(**self._locate_plot_options),
195
196
  )
197
+
196
198
  # Add DynamicMap for streams for single plot
197
199
  dmap = self._get_locate_dmap(self._locate)
198
200
 
@@ -210,8 +212,11 @@ class MsPlot:
210
212
  # Add tabs for inputs and locate
211
213
  if inputs_column:
212
214
  self._show_panel.append(('Plot Inputs', inputs_column))
213
- self._show_panel.append(('Locate Selected Points', pn.Feed(height_policy='max')))
214
- self._show_panel.append(('Locate Selected Box', pn.Feed(height_policy='max')))
215
+ self._show_panel.append(('Locate Points', pn.Feed(height_policy='max')))
216
+ self._show_panel.append(('Locate Box', pn.Feed(height_policy='max')))
217
+
218
+ # Compute coordinate values for locate
219
+ self._compute_plot_metadata(self._plot_data)
215
220
 
216
221
  # return value for locate callback
217
222
  self._last_plot = plot
@@ -397,21 +402,28 @@ class MsPlot:
397
402
  str_pane.margin = (0, 10)
398
403
  inputs_tab_column.append(str_pane)
399
404
 
405
+ def _compute_plot_metadata(self, xds):
406
+ ''' Compute coordinate dask arrays to numpy arrays in memory '''
407
+ for coord in xds.coords:
408
+ xds[coord] = xds[coord].compute()
409
+
400
410
  def _get_locate_dmap(self, callback):
401
411
  ''' Return DynamicMap with streams callback to locate points '''
402
412
  points = hv.Points([]).opts(
403
413
  size=5,
404
414
  fill_color='white'
405
415
  )
416
+ boxes = hv.Rectangles([])
406
417
  dmap = hv.DynamicMap(
407
418
  callback,
408
419
  streams=[
409
- hv.streams.PointerXY(), # cursor location (x, y)
410
- hv.streams.PointDraw(source=points), # fixed points location (data)
411
- hv.streams.BoundsXY() # box location (bounds)
420
+ hv.streams.PointerXY(), # cursor location (x, y)
421
+ hv.streams.PointDraw(source=points), # fixed points location (data)
422
+ hv.streams.BoxEdit(source=boxes).rename(data='boxes') # box location (boxes)
412
423
  ]
413
424
  )
414
- return dmap * points
425
+ return (dmap * points * boxes).options(
426
+ hv.opts.Rectangles(fill_alpha=0.5, line_color='white'))
415
427
 
416
428
  def _unlink_plot_locate(self):
417
429
  ''' Disconnect streams when plot data is going to be replaced '''
@@ -432,45 +444,91 @@ class MsPlot:
432
444
  self._plot_axes = (x_axis, y_axis, vis_axis)
433
445
  return self._plot_axes
434
446
 
435
- def _locate(self, x, y, data, bounds):
447
+ def _locate(self, x, y, data, boxes):
436
448
  ''' Callback for all show plot streams '''
449
+ if self._locate_points(data, self._plot_data, self._show_panel[2]):
450
+ return self._last_plot
451
+
452
+ if self._locate_boxes(boxes, self._plot_data, self._show_panel[3]):
453
+ return self._last_plot
454
+
437
455
  self._locate_cursor(x, y, self._plot_data, self._show_panel[0][1])
438
- self._locate_points(data, self._plot_data, self._show_panel[2])
439
- self._locate_box(bounds, self._plot_data, self._show_panel[3])
440
456
  return self._last_plot
441
457
 
442
458
  def _locate_cursor(self, x, y, plot_data, cursor_box):
443
459
  ''' Show location from cursor position in cursor locate box '''
460
+ if not x and not y: # not cursor callback
461
+ return False
462
+ plot_axes = self._get_plot_axes()
463
+ x = get_locate_value(plot_data, plot_axes[0], x)
464
+ y = get_locate_value(plot_data, plot_axes[1], y)
444
465
  cursor = (x, y)
445
- if cursor_changed(cursor, self._last_cursor):
466
+ if data_changed(cursor, self._last_cursor):
446
467
  # new cursor position - update cursor location box
447
- update_cursor_location(cursor, self._get_plot_axes(), plot_data, cursor_box)
468
+ update_cursor_location(cursor, plot_axes, plot_data, cursor_box)
448
469
  self._last_cursor = cursor
470
+ return True
471
+ return False
449
472
 
450
473
  def _locate_points(self, point_data, plot_data, points_tab):
451
474
  ''' Show points locations from point_draw tool '''
452
- if points_changed(point_data, self._last_points):
453
- # update selected points location tab
454
- location_info = update_points_location(point_data, self._get_plot_axes(), plot_data, points_tab)
475
+ if not point_data or len(point_data['x']) == 0: # not points callback
476
+ return False
477
+
478
+ plot_axes = self._get_plot_axes()
479
+ x_vals = point_data['x']
480
+ y_vals = point_data['y']
481
+ point_data['x'] = [get_locate_value(plot_data, plot_axes[0], x) for x in x_vals]
482
+ point_data['y'] = [get_locate_value(plot_data, plot_axes[1], y) for y in y_vals]
483
+ data_points = list(zip(point_data['x'], point_data['y']))
484
+
485
+ if not data_changed(data_points, self._last_points):
486
+ return False
487
+
488
+ # update selected points location tab with new points
489
+ points_to_locate = get_new_data(data_points, self._last_points)
490
+ self._last_points = data_points
455
491
 
456
- # log to file only
457
- self._logger.removeHandler(self._stdout_handler)
458
- for info in location_info:
459
- self._logger.info(info)
460
- self._logger.addHandler(self._stdout_handler)
492
+ if len(points_to_locate) == len(data_points):
493
+ points_tab.clear() # clear for locating all points
461
494
 
462
- self._last_points = point_data
495
+ if points_to_locate:
496
+ location_info = update_points_location(points_to_locate, self._get_plot_axes(), plot_data, points_tab)
497
+ self._log_to_file_only(location_info)
498
+ return True
463
499
 
464
- def _locate_box(self, box_bounds, plot_data, box_tab):
500
+ def _locate_boxes(self, boxes, plot_data, box_tab):
465
501
  ''' Show points locations in box from box_select tool '''
466
- if box_changed(box_bounds, self._last_box):
467
- # update selected box location tab
468
- location_info = update_box_location(box_bounds, self._get_plot_axes(), plot_data, box_tab)
502
+ if not boxes or len(boxes['x0']) == 0: # not box callback
503
+ return False
469
504
 
470
- # log to file only
471
- self._logger.removeHandler(self._stdout_handler)
472
- for info in location_info:
473
- self._logger.info(info)
474
- self._logger.addHandler(self._stdout_handler)
505
+ plot_axes = self._get_plot_axes()
506
+ x0_vals = boxes['x0']
507
+ y0_vals = boxes['y0']
508
+ x1_vals = boxes['x1']
509
+ y1_vals = boxes['y1']
510
+ boxes['x0'] = [get_locate_value(plot_data, plot_axes[0], x0) for x0 in x0_vals]
511
+ boxes['y0'] = [get_locate_value(plot_data, plot_axes[1], y0) for y0 in y0_vals]
512
+ boxes['x1'] = [get_locate_value(plot_data, plot_axes[0], x1) for x1 in x1_vals]
513
+ boxes['y1'] = [get_locate_value(plot_data, plot_axes[1], y1) for y1 in y1_vals]
514
+ box_list = list(zip(boxes['x0'], boxes['y0'], boxes['x1'], boxes['y1']))
515
+
516
+ if not data_changed(box_list, self._last_boxes):
517
+ return False
475
518
 
476
- self._last_box = box_bounds
519
+ # update selected box location tab with new boxes
520
+ boxes_to_locate = get_new_data(box_list, self._last_boxes)
521
+ self._last_boxes = box_list
522
+
523
+ if boxes_to_locate:
524
+ box_tab.clear()
525
+ location_info = update_boxes_location(boxes_to_locate, self._get_plot_axes(), plot_data, box_tab)
526
+ self._log_to_file_only(location_info)
527
+ return True
528
+
529
+ def _log_to_file_only(self, messages):
530
+ ''' log messages to file only '''
531
+ self._logger.removeHandler(self._stdout_handler)
532
+ for message in messages:
533
+ self._logger.info(message)
534
+ self._logger.addHandler(self._stdout_handler)
@@ -26,10 +26,10 @@ def create_raster_gui(callbacks, plot_info, empty_plot):
26
26
  pn.pane.HoloViews(empty_plot), # Row[0] plot
27
27
  pn.WidgetBox(sizing_mode='stretch_width'), # Row[1] cursor location
28
28
  )),
29
- ('Plot Inputs', pn.Column()), # Tabs[1]
30
- ('Locate Selected Points', pn.Feed(sizing_mode='stretch_height')), # Tabs[2]
31
- ('Locate Selected Box', pn.Feed(sizing_mode='stretch_height')), # Tabs[3]
32
- ('Plot Settings', pn.Column( # Tabs[4]
29
+ ('Plot Inputs', pn.Column()), # Tabs[1]
30
+ ('Locate Points', pn.Feed(sizing_mode='stretch_height')), # Tabs[2]
31
+ ('Locate Box', pn.Feed(sizing_mode='stretch_height')), # Tabs[3]
32
+ ('Plot Settings', pn.Column( # Tabs[4]
33
33
  pn.Spacer(height=25), # Column[0]
34
34
  selectors, # Column[1] selectors
35
35
  init_plot, # Column[2] plot button and spinner
File without changes
File without changes
File without changes
File without changes