vidavis 0.1.1__py3-none-any.whl → 0.1.2__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 CHANGED
@@ -1 +1 @@
1
- __version__ = '0.1.1'
1
+ __version__ = '0.1.2'
@@ -2,6 +2,7 @@
2
2
  Implementation of the ``MsRaster`` application for measurement set raster plotting and editing
3
3
  '''
4
4
 
5
+ import threading
5
6
  import time
6
7
 
7
8
  from bokeh.models.formatters import NumeralTickFormatter
@@ -183,8 +184,8 @@ class MsRaster(MsPlot):
183
184
 
184
185
  start = time.time()
185
186
 
186
- # If previous plot was shown, unlink from data streams
187
- super().unlink_plot_locate()
187
+ # Unlink previous plot from data streams
188
+ super()._unlink_plot_locate()
188
189
 
189
190
  # Clear for new plot
190
191
  self._reset_plot(clear_plots)
@@ -450,7 +451,15 @@ class MsRaster(MsPlot):
450
451
  }
451
452
 
452
453
  self._gui_panel = create_raster_gui(callbacks, plot_info, self._empty_plot)
453
- self._gui_panel.show(title=self._app_name, threaded=True)
454
+
455
+ # Start Panel server in a background daemon thread so it doesn't block process exit.
456
+ # Note: The Panel server will automatically stop when the Python process exits.
457
+ # Any open browser windows or tabs displaying the plot will lose connection at that point.
458
+ server_thread = threading.Thread(
459
+ target=lambda panel=self._gui_panel, name=self._app_name: panel.show(title=name, threaded=False),
460
+ daemon=True
461
+ )
462
+ server_thread.start()
454
463
 
455
464
  ###
456
465
  ### Main callback to create plot if inputs changed
@@ -496,7 +505,7 @@ class MsRaster(MsPlot):
496
505
 
497
506
  # Put plot with dmap for locate streams in gui panel
498
507
  dmap = self._get_locate_dmap(self._locate_gui_points)
499
- self._gui_panel[0][0][0].object = gui_plot * dmap
508
+ self._gui_panel[0][0].object = gui_plot * dmap
500
509
  except (ValueError, TypeError, KeyError, RuntimeError) as e:
501
510
  # Clear plot, inputs invalid
502
511
  self._notify(str(e), 'error', 0)
@@ -518,7 +527,7 @@ class MsRaster(MsPlot):
518
527
  def _locate_gui_points(self, x, y, data, bounds):
519
528
  ''' Callback for locate streams '''
520
529
  if self._gui_plot_data:
521
- super()._locate_cursor(x, y, self._gui_plot_data, self._gui_panel[0][0][1])
530
+ super()._locate_cursor(x, y, self._gui_plot_data, self._gui_panel[0][1])
522
531
  super()._locate_points(data, self._gui_plot_data, self._gui_panel[2])
523
532
  super()._locate_box(bounds, self._gui_plot_data, self._gui_panel[3])
524
533
  return self._last_gui_plot
@@ -602,7 +611,7 @@ class MsRaster(MsPlot):
602
611
  if not self._gui_panel:
603
612
  return None
604
613
 
605
- selectors = self._gui_panel[0][2][1]
614
+ selectors = self._gui_panel[4][1]
606
615
  if name == "selectors":
607
616
  return selectors
608
617
 
@@ -688,7 +697,7 @@ class MsRaster(MsPlot):
688
697
  selection_key = MS_SELECTION_OPTIONS[selector.name] if selector.name in MS_SELECTION_OPTIONS else None
689
698
  if selection_key:
690
699
  if selection_key == 'data_group':
691
- selector.options = list(super().data_groups())
700
+ selector.options = list(super().data_groups(False))
692
701
  else:
693
702
  selector.options = super().get_dimension_values(selection_key)
694
703
 
@@ -753,14 +762,14 @@ class MsRaster(MsPlot):
753
762
  ''' Callback to start spinner when Plot button clicked. '''
754
763
  if self._gui_panel:
755
764
  # Start spinner
756
- spinner = self._gui_panel[0][2][2][1]
765
+ spinner = self._gui_panel[4][2][1]
757
766
  spinner.value = plot_clicked
758
767
 
759
768
  def _update_plot_status(self, plot_changed):
760
769
  ''' Change button color when plot inputs change. '''
761
770
  if self._gui_panel:
762
771
  # Set button color
763
- button = self._gui_panel[0][2][2][0]
772
+ button = self._gui_panel[4][2][0]
764
773
  button.button_style = 'solid' if plot_changed else 'outline'
765
774
 
766
775
  def _show_plot_inputs(self):
@@ -85,11 +85,12 @@ class PsData:
85
85
  return self._ps_xdt.xr_ps.summary(data_group)
86
86
 
87
87
  def get_data_groups(self):
88
- ''' Returns set of data group names in Processing Set data. '''
89
- data_groups = []
88
+ ''' Returns dict of data groups in Processing Set data. '''
89
+ data_groups = {}
90
90
  for ms_xdt_name in self._ps_xdt:
91
- data_groups.extend(list(self._ps_xdt[ms_xdt_name].data_groups))
92
- return set(data_groups)
91
+ for group_name, group_members in self._ps_xdt[ms_xdt_name].data_groups.items():
92
+ data_groups[group_name] = group_members
93
+ return data_groups
93
94
 
94
95
  def plot_antennas(self, label_antennas=False):
95
96
  ''' Plot antenna positions.
@@ -47,7 +47,7 @@ def update_cursor_location(cursor, plot_axes, xds, cursor_locate_box):
47
47
  cursor_position = {x_axis: x, y_axis: y}
48
48
  cursor_location = _locate_point(xds, cursor_position, vis_axis)
49
49
 
50
- location_column = pn.Column(pn.widgets.StaticText(name="Cursor Location"))
50
+ location_column = pn.Column(pn.widgets.StaticText(name="CURSOR LOCATION"))
51
51
  # Add row of columns to column layout
52
52
  location_row = _layout_point_location(cursor_location)
53
53
  location_column.append(location_row)
@@ -4,6 +4,7 @@ Base class for ms plots
4
4
 
5
5
  import os
6
6
  import logging
7
+ import threading
7
8
  import time
8
9
 
9
10
  from bokeh.io import export_png, export_svg
@@ -74,7 +75,7 @@ class MsPlot:
74
75
  self._last_points = None
75
76
  self._last_box = None
76
77
  self._locate_plot_options = {
77
- 'tools': ['hover', 'box_select'],
78
+ 'tools': ['box_select', 'hover'],
78
79
  'selection_fill_alpha': 0.2, # dim selected areas of plot
79
80
  'nonselection_fill_alpha': 1.0, # do not dim unselected areas of plot
80
81
  }
@@ -107,10 +108,17 @@ class MsPlot:
107
108
  else:
108
109
  self._logger.error("Error: MS path has not been set")
109
110
 
110
- def data_groups(self):
111
- ''' Returns set of data groups from all ProcessingSet ms_xds. '''
111
+ def data_groups(self, show=False):
112
+ ''' Get data groups from all ProcessingSet ms_xds and either print or return them. '''
112
113
  if self._ms_data:
113
- return self._ms_data.data_groups()
114
+ ms_data_groups = self._ms_data.data_groups()
115
+ if show:
116
+ for name, items in ms_data_groups.items():
117
+ print(name, ":")
118
+ for item, val in items.items():
119
+ print(f" {item} = {val}")
120
+ return None
121
+ return ms_data_groups
114
122
  self._logger.error("Error: MS path has not been set")
115
123
  return None
116
124
 
@@ -152,16 +160,6 @@ class MsPlot:
152
160
  self._gui_panel[2].clear() # locate points
153
161
  self._gui_panel[3].clear() # locate box
154
162
 
155
- def unlink_plot_locate(self):
156
- ''' Disconnect streams when plot data is going to be replaced '''
157
- if self._show_panel and len(self._show_panel.objects) == 4:
158
- # Remove dmap (streams with callback) from previous plot
159
- self._show_panel[0][0] = self._last_plot.opts(tools=['hover'])
160
- # Remove locate widgets
161
- self._show_panel[0].pop(1) # cursor locate box
162
- self._show_panel.pop(3) # box locate tab
163
- self._show_panel.pop(2) # points locate tab
164
-
165
163
  def clear_selection(self):
166
164
  ''' Clear data selection and restore original ProcessingSet '''
167
165
  if self._ms_data:
@@ -203,21 +201,29 @@ class MsPlot:
203
201
  ('Plot',
204
202
  pn.Column(
205
203
  plot * dmap,
206
- pn.WidgetBox(), # cursor info
204
+ pn.WidgetBox(sizing_mode='stretch_width'), # cursor info
207
205
  )
208
206
  ),
209
- sizing_mode='stretch_width',
207
+ sizing_mode='stretch_both',
210
208
  )
209
+
210
+ # Add tabs for inputs and locate
211
211
  if inputs_column:
212
212
  self._show_panel.append(('Plot Inputs', inputs_column))
213
- self._show_panel.append(('Locate Selected Points', pn.Feed(sizing_mode='stretch_height')))
214
- self._show_panel.append(('Locate Selected Box', pn.Feed(sizing_mode='stretch_height')))
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
215
 
216
216
  # return value for locate callback
217
217
  self._last_plot = plot
218
218
 
219
- # Show panel layout
220
- self._show_panel.show(title=self._app_name, threaded=True)
219
+ # Start Panel server in a background daemon thread so it doesn't block process exit.
220
+ # Note: The Panel server will automatically stop when the Python process exits.
221
+ # Any open browser windows or tabs displaying the plot will lose connection at that point.
222
+ server_thread = threading.Thread(
223
+ target=lambda panel=self._show_panel, name=self._app_name: panel.show(title=name, threaded=False),
224
+ daemon=True
225
+ )
226
+ server_thread.start()
221
227
 
222
228
  def save(self, filename='ms_plot.png', fmt='auto', width=900, height=600):
223
229
  '''
@@ -407,6 +413,16 @@ class MsPlot:
407
413
  )
408
414
  return dmap * points
409
415
 
416
+ def _unlink_plot_locate(self):
417
+ ''' Disconnect streams when plot data is going to be replaced '''
418
+ if self._show_panel and len(self._show_panel.objects) == 4:
419
+ # Remove dmap (streams with callback) from previous plot
420
+ self._show_panel[0][0] = self._last_plot.opts(tools=['hover'])
421
+ # Remove locate widgets
422
+ self._show_panel[0].pop(1) # cursor locate box
423
+ self._show_panel.pop(3) # box locate tab
424
+ self._show_panel.pop(2) # points locate tab
425
+
410
426
  def _get_plot_axes(self):
411
427
  ''' Return x, y, vis axes '''
412
428
  if not self._plot_axes:
@@ -335,7 +335,7 @@ def _add_multi_choice(ps_selection, names):
335
335
  for name in names:
336
336
  # For value or list
337
337
  ps_selection.append(
338
- pn.widgets.MultiSelect(
338
+ pn.widgets.MultiChoice(
339
339
  name=name,
340
340
  sizing_mode='stretch_width',
341
341
  )
@@ -185,7 +185,6 @@ class RasterPlot:
185
185
  x_formatter = get_time_formatter() if x_axis == 'time' else None
186
186
  y_formatter = get_time_formatter() if y_axis == 'time' else None
187
187
 
188
- # Hide flagged colorbar if unflagged colorbar is shown
189
188
  if xda.count().values > 0:
190
189
  if is_flagged:
191
190
  show_colorbar = style_params['show_flagged_colorbar']
@@ -240,7 +239,6 @@ class RasterPlot:
240
239
  yticks=plot_params['axis_labels']['y']['ticks'],
241
240
  rot=45,
242
241
  marker='s', # square
243
- hover=True,
244
242
  responsive=True,
245
243
  )
246
244
 
@@ -8,7 +8,7 @@ from vidavis.plot.ms_plot._ms_plot_selectors import (file_selector, title_select
8
8
 
9
9
  def create_raster_gui(callbacks, plot_info, empty_plot):
10
10
  ''' Use Holoviz Panel to create a dashboard for plot inputs and raster plot display.
11
- ms (str): path to MS, if set
11
+ callbacks (dist): callback functions for widgets
12
12
  plot_info (dict): with keys 'ms', 'data_dims', 'x_axis', 'y_axis'
13
13
  empty_plot (hv.Overlay): QuadMesh overlay plot with no data
14
14
  '''
@@ -22,24 +22,19 @@ def create_raster_gui(callbacks, plot_info, empty_plot):
22
22
  #dmap, points = get_plot_dmap(callbacks, selectors, init_plot)
23
23
 
24
24
  return pn.Tabs(
25
- ('Plot', pn.Row( # Tabs[0]
26
- pn.Column( # Row[0]
27
- pn.pane.HoloViews(empty_plot), # Column[0] plot
28
- pn.WidgetBox(), # Column[1] cursor location
29
- ),
30
- pn.Spacer(width=10), # Row[1]
31
- pn.Column( # Row[2]
32
- pn.Spacer(height=25), # Column[0]
33
- selectors, # Column[1] selectors
34
- init_plot, # Column[2] plot button and spinner
35
- width_policy='min',
36
- width=300,
37
- sizing_mode='stretch_height',
38
- ),
25
+ ('Plot', pn.Column( # Tabs[0]
26
+ pn.pane.HoloViews(empty_plot), # Row[0] plot
27
+ pn.WidgetBox(sizing_mode='stretch_width'), # Row[1] cursor location
39
28
  )),
40
29
  ('Plot Inputs', pn.Column()), # Tabs[1]
41
30
  ('Locate Selected Points', pn.Feed(sizing_mode='stretch_height')), # Tabs[2]
42
31
  ('Locate Selected Box', pn.Feed(sizing_mode='stretch_height')), # Tabs[3]
32
+ ('Plot Settings', pn.Column( # Tabs[4]
33
+ pn.Spacer(height=25), # Column[0]
34
+ selectors, # Column[1] selectors
35
+ init_plot, # Column[2] plot button and spinner
36
+ sizing_mode='stretch_both',
37
+ )),
43
38
  sizing_mode='stretch_width',
44
39
  )
45
40
 
@@ -79,6 +74,7 @@ def get_plot_input_selectors(callbacks, plot_info):
79
74
  ("Aggregation", agg_selectors), # [4]
80
75
  ("Iteration", iter_selectors), # [5]
81
76
  ("Plot title", title_input), # [6]
77
+ sizing_mode='stretch_width',
82
78
  )
83
79
  selectors.toggle = True
84
80
  return selectors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vidavis
3
- Version: 0.1.1
3
+ Version: 0.1.2
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>
@@ -1,7 +1,7 @@
1
1
  vidavis/LICENSE.rst,sha256=qzGpkvhDzf_MgF1PIn6rCmYPrcEhkfrBUchosLJj-U4,26371
2
2
  vidavis/__init__.py,sha256=FVM92yTXUplR7tVHiGao0Y3Hd80pRTrwVIYDLjzICws,1709
3
3
  vidavis/apps/__init__.py,sha256=ZQ5v1VFtjn3ztmuOHLOk5WbC1uLNIgL9rbHQ4v0zJwY,87
4
- vidavis/apps/_ms_raster.py,sha256=e-vEBjoNajE3gZPSRHUJwWGugHRbdVPBd7WVFYnH3DM,41175
4
+ vidavis/apps/_ms_raster.py,sha256=HR2t6ZYTzZxxFtPnPmAVoI_PADHYA268FwhCrM1u6-o,41600
5
5
  vidavis/bokeh/__init__.py,sha256=gdPPxBCe0enCSjvPFxkgMlhpVnAMFXKcw9GN28tVdXM,95
6
6
  vidavis/bokeh/_palette.py,sha256=gzfJHuUgqxd8hJpZe-gQPFTCPq9f5I8uLEkHAK5FNDM,2480
7
7
  vidavis/data/__init__.py,sha256=-RDRe0PYK6vPlhdRV2Dy1vGbnDGoXWDATmfxaR-gXcE,48
@@ -10,7 +10,7 @@ vidavis/data/measurement_set/_ms_data.py,sha256=7ATsPbGFAv8WtWk_PRxlfoLdqapd6eMv
10
10
  vidavis/data/measurement_set/processing_set/__init__.py,sha256=TVQe5Nl4APCB2E1T1giAkOvSxg7OBNcOm9-BeZelY2Q,95
11
11
  vidavis/data/measurement_set/processing_set/_ps_concat.py,sha256=uTuxE7krTu6SS7lwV9ITMsAxJ4BJhKOU9dLlQ9L1oNY,3513
12
12
  vidavis/data/measurement_set/processing_set/_ps_coords.py,sha256=SDp-0ebd94QjO_jPv00weiYmp-OD1XqsCzWvNc0D-94,3747
13
- vidavis/data/measurement_set/processing_set/_ps_data.py,sha256=aO_J8ETi-Lqu4eNNKsKUHzvvnyRhww4hECUjbBS9Z9U,11626
13
+ vidavis/data/measurement_set/processing_set/_ps_data.py,sha256=v6ARj5AJYsT30Gp8tWOZCoU7WxDb2_p8pfMbVBW4gVA,11689
14
14
  vidavis/data/measurement_set/processing_set/_ps_io.py,sha256=VeNi-s1hozgCAGAGHs4NUXtlVFwUh-mkqrY9iYWOfW4,1717
15
15
  vidavis/data/measurement_set/processing_set/_ps_raster_data.py,sha256=m7d0qe5bS-XjGD_1mrpRn9dTobwG8WDidCmAaLP2TWQ,7378
16
16
  vidavis/data/measurement_set/processing_set/_ps_select.py,sha256=AtEsLy3bSHEyFUFKM-OO6_-YwUdWOWcGkXkEgFxMaEE,10859
@@ -19,13 +19,13 @@ vidavis/data/measurement_set/processing_set/_xds_data.py,sha256=qLO2VkLINkSAQ7CG
19
19
  vidavis/plot/__init__.py,sha256=thxe5vAGdpEiqoKPHLJoWUqKMVrUVx0ajpsGf5pVP98,95
20
20
  vidavis/plot/ms_plot/__init__.py,sha256=wY0_7gY9M6K1D6tKQsr89L_uSs3seJlD-uicx7dx5Mo,74
21
21
  vidavis/plot/ms_plot/_check_raster_inputs.py,sha256=a7u5wlDKTxWYW36-Xp3xd4c756SbYURdFkGHbUaX440,4786
22
- vidavis/plot/ms_plot/_locate_points.py,sha256=DPGdCHanRkNp-6nYJcZknX8iNMlYrNllKhmQuwxqONQ,11006
23
- vidavis/plot/ms_plot/_ms_plot.py,sha256=EQx348f6ifYakQREmkfh2ybIefsPYqKjNT5gd44LqjI,19343
22
+ vidavis/plot/ms_plot/_locate_points.py,sha256=PlPAq0WGoKNOEiTsOV8cDKHAcbkQOWfqoc0vRSFbkiA,11006
23
+ vidavis/plot/ms_plot/_ms_plot.py,sha256=0zbZ-QdXdwl91Ze9--H7G47y9FulHkGy_5_2dlm9wuw,20144
24
24
  vidavis/plot/ms_plot/_ms_plot_constants.py,sha256=xbn_dEx4QWbZIsUDziJifrT7pXwO2Qr2B5CHyAy16So,940
25
- vidavis/plot/ms_plot/_ms_plot_selectors.py,sha256=jBjthBjfXDf6W19HG8j8Pzxxzmnte5apeVDjsMy-dDg,11146
25
+ vidavis/plot/ms_plot/_ms_plot_selectors.py,sha256=LeRLuOVkitzuOL--QRHXtoxJIz3DGjhjIjSfbOj7qyI,11146
26
26
  vidavis/plot/ms_plot/_plot_inputs.py,sha256=GeErBB3pYz6ecJiMTGQMNXkPeMLbWbYGmqL5dr8A46Q,687
27
- vidavis/plot/ms_plot/_raster_plot.py,sha256=Uv0D-P7PyvcMBqFHqmbNxnDkUMekVok511WIvaA-JB0,10894
28
- vidavis/plot/ms_plot/_raster_plot_gui.py,sha256=f57Jj9BMNuTTzCC3AgHqL17R0MGfiO9Rxt6u0mesnYA,3623
27
+ vidavis/plot/ms_plot/_raster_plot.py,sha256=6TOZvKSh8oBI79K926zp8Cn5bzk4MJGPB_PQ5S-1H4M,10803
28
+ vidavis/plot/ms_plot/_raster_plot_gui.py,sha256=gsNklMUj4Tx9H2r4Am8XHY0qoEHcCsaDYZDd3FaAmSQ,3563
29
29
  vidavis/plot/ms_plot/_raster_plot_inputs.py,sha256=kxR6-1Qn4IyQ4FjgpVZ9HEZ7EnPHxJZWomb0n_zaRwo,4071
30
30
  vidavis/plot/ms_plot/_time_ticks.py,sha256=j-DcPh7RfGE8iX2bPjLQDQPIbiAbmjiEWQnKmdMWA3I,1773
31
31
  vidavis/plot/ms_plot/_xds_plot_axes.py,sha256=EeWvAbiKV33nEWdI8V3M0uwLTnycq4bFYBOyVWkxCu0,4429
@@ -33,8 +33,8 @@ vidavis/toolbox/__init__.py,sha256=jqFa-eziVz_frNnXxwjJFK36qNpz1H38s-VlpBcq-R8,1
33
33
  vidavis/toolbox/_app_context.py,sha256=H7gtF8RrAH46FqDcMobv3KM1Osbnapgu6aTG-m3VCWA,3049
34
34
  vidavis/toolbox/_logging.py,sha256=OEisrd8FM8VTNBMc7neLh9ekelf29ZILYB5pScebly0,2739
35
35
  vidavis/toolbox/_static.py,sha256=HJLMtClppgOJXWAtV6Umn5EqN80u0oZiIouQ1JsB9PM,2346
36
- vidavis/__version__.py,sha256=jZ5uWOiyV1Hb9rhNyo3bAgfWmHx8_xkueUWpcUrkz_w,21
37
- vidavis-0.1.1.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
38
- vidavis-0.1.1.dist-info/METADATA,sha256=8zI_duU6ZeUuTgbF0ufb3Vr6EnDlrB3MxfdBu5vcunA,2268
39
- vidavis-0.1.1.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
40
- vidavis-0.1.1.dist-info/RECORD,,
36
+ vidavis/__version__.py,sha256=r_cKr7sbAG8wXvZQ-5WkC2eXGKMDWp6Xe_hNXu43MT0,21
37
+ vidavis-0.1.2.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
38
+ vidavis-0.1.2.dist-info/METADATA,sha256=bGXBhlQbWV5_Y82WSurot_OPr4U4on-pjsQZWDX-_d4,2268
39
+ vidavis-0.1.2.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
40
+ vidavis-0.1.2.dist-info/RECORD,,