cubevis 0.5.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.
Files changed (132) hide show
  1. cubevis/LICENSE.rst +500 -0
  2. cubevis/__icons__/20px/fast-backward.svg +13 -0
  3. cubevis/__icons__/20px/fast-forward.svg +13 -0
  4. cubevis/__icons__/20px/step-backward.svg +12 -0
  5. cubevis/__icons__/20px/step-forward.svg +12 -0
  6. cubevis/__icons__/add-chan.png +0 -0
  7. cubevis/__icons__/add-chan.svg +84 -0
  8. cubevis/__icons__/add-cube.png +0 -0
  9. cubevis/__icons__/add-cube.svg +186 -0
  10. cubevis/__icons__/drag.png +0 -0
  11. cubevis/__icons__/drag.svg +109 -0
  12. cubevis/__icons__/mask-selected.png +0 -0
  13. cubevis/__icons__/mask.png +0 -0
  14. cubevis/__icons__/mask.svg +1 -0
  15. cubevis/__icons__/new-layer-sm-selected.png +0 -0
  16. cubevis/__icons__/new-layer-sm-selected.svg +88 -0
  17. cubevis/__icons__/new-layer-sm.png +0 -0
  18. cubevis/__icons__/new-layer-sm.svg +15 -0
  19. cubevis/__icons__/reset.png +0 -0
  20. cubevis/__icons__/reset.svg +11 -0
  21. cubevis/__icons__/sub-chan.png +0 -0
  22. cubevis/__icons__/sub-chan.svg +71 -0
  23. cubevis/__icons__/sub-cube.png +0 -0
  24. cubevis/__icons__/sub-cube.svg +95 -0
  25. cubevis/__icons__/zoom-to-fit.png +0 -0
  26. cubevis/__icons__/zoom-to-fit.svg +21 -0
  27. cubevis/__init__.py +58 -0
  28. cubevis/__js__/bokeh-3.6.1.min.js +728 -0
  29. cubevis/__js__/bokeh-tables-3.6.1.min.js +119 -0
  30. cubevis/__js__/bokeh-widgets-3.6.1.min.js +141 -0
  31. cubevis/__js__/casalib.min.js +1 -0
  32. cubevis/__js__/cubevisjs.min.js +62 -0
  33. cubevis/__version__.py +1 -0
  34. cubevis/apps/__init__.py +44 -0
  35. cubevis/apps/_createmask.py +461 -0
  36. cubevis/apps/_createregion.py +513 -0
  37. cubevis/apps/_interactiveclean.py +3260 -0
  38. cubevis/apps/_interactiveclean_wrappers.py +130 -0
  39. cubevis/apps/_ms_raster.py +815 -0
  40. cubevis/apps/_plotants.py +286 -0
  41. cubevis/apps/_plotbandpass.py +7 -0
  42. cubevis/bokeh/__init__.py +29 -0
  43. cubevis/bokeh/annotations/__init__.py +1 -0
  44. cubevis/bokeh/annotations/_ev_poly_annotation.py +6 -0
  45. cubevis/bokeh/components/__init__.py +28 -0
  46. cubevis/bokeh/format/__init__.py +31 -0
  47. cubevis/bokeh/format/_time_ticks.py +44 -0
  48. cubevis/bokeh/format/_wcs_ticks.py +45 -0
  49. cubevis/bokeh/models/__init__.py +4 -0
  50. cubevis/bokeh/models/_edit_span.py +7 -0
  51. cubevis/bokeh/models/_ev_text_input.py +6 -0
  52. cubevis/bokeh/models/_tip.py +37 -0
  53. cubevis/bokeh/models/_tip_button.py +50 -0
  54. cubevis/bokeh/sources/__init__.py +35 -0
  55. cubevis/bokeh/sources/_data_pipe.py +258 -0
  56. cubevis/bokeh/sources/_image_data_source.py +83 -0
  57. cubevis/bokeh/sources/_image_pipe.py +581 -0
  58. cubevis/bokeh/sources/_spectra_data_source.py +55 -0
  59. cubevis/bokeh/sources/_updatable_data_source.py +189 -0
  60. cubevis/bokeh/state/__init__.py +34 -0
  61. cubevis/bokeh/state/_initialize.py +164 -0
  62. cubevis/bokeh/state/_javascript.py +53 -0
  63. cubevis/bokeh/state/_palette.py +58 -0
  64. cubevis/bokeh/state/_session.py +44 -0
  65. cubevis/bokeh/state/js/bokeh-2.4.1.min.js +596 -0
  66. cubevis/bokeh/state/js/bokeh-gl-2.4.1.min.js +74 -0
  67. cubevis/bokeh/state/js/bokeh-tables-2.4.1.min.js +132 -0
  68. cubevis/bokeh/state/js/bokeh-widgets-2.4.1.min.js +118 -0
  69. cubevis/bokeh/state/js/casaguijs-v0.0.4.0-b2.4.min.js +49 -0
  70. cubevis/bokeh/state/js/casaguijs-v0.0.5.0-b2.4.min.js +49 -0
  71. cubevis/bokeh/state/js/casaguijs-v0.0.6.0-b2.4.min.js +49 -0
  72. cubevis/bokeh/state/js/casalib-v0.0.1.min.js +1 -0
  73. cubevis/bokeh/tools/__init__.py +31 -0
  74. cubevis/bokeh/tools/_cbreset_tool.py +52 -0
  75. cubevis/bokeh/tools/_drag_tool.py +61 -0
  76. cubevis/bokeh/utils/__init__.py +35 -0
  77. cubevis/bokeh/utils/_axes_labels.py +94 -0
  78. cubevis/bokeh/utils/_svg_icon.py +136 -0
  79. cubevis/data/__init__.py +1 -0
  80. cubevis/data/casaimage/__init__.py +114 -0
  81. cubevis/data/measurement_set/__init__.py +7 -0
  82. cubevis/data/measurement_set/_ms_data.py +178 -0
  83. cubevis/data/measurement_set/processing_set/__init__.py +30 -0
  84. cubevis/data/measurement_set/processing_set/_ps_concat.py +98 -0
  85. cubevis/data/measurement_set/processing_set/_ps_coords.py +78 -0
  86. cubevis/data/measurement_set/processing_set/_ps_data.py +213 -0
  87. cubevis/data/measurement_set/processing_set/_ps_io.py +55 -0
  88. cubevis/data/measurement_set/processing_set/_ps_raster_data.py +154 -0
  89. cubevis/data/measurement_set/processing_set/_ps_select.py +91 -0
  90. cubevis/data/measurement_set/processing_set/_ps_stats.py +218 -0
  91. cubevis/data/measurement_set/processing_set/_xds_data.py +149 -0
  92. cubevis/plot/__init__.py +1 -0
  93. cubevis/plot/ms_plot/__init__.py +29 -0
  94. cubevis/plot/ms_plot/_ms_plot.py +242 -0
  95. cubevis/plot/ms_plot/_ms_plot_constants.py +22 -0
  96. cubevis/plot/ms_plot/_ms_plot_selectors.py +348 -0
  97. cubevis/plot/ms_plot/_raster_plot.py +292 -0
  98. cubevis/plot/ms_plot/_raster_plot_inputs.py +116 -0
  99. cubevis/plot/ms_plot/_xds_plot_axes.py +110 -0
  100. cubevis/private/__java__/xml-casa-assembly-1.86.jar +0 -0
  101. cubevis/private/_gclean.py +798 -0
  102. cubevis/private/casashell/createmask.py +332 -0
  103. cubevis/private/casashell/iclean.py +4432 -0
  104. cubevis/private/casatasks/__init__.py +140 -0
  105. cubevis/private/casatasks/createmask.py +86 -0
  106. cubevis/private/casatasks/createregion.py +83 -0
  107. cubevis/private/casatasks/iclean.py +1831 -0
  108. cubevis/readme.rst +16 -0
  109. cubevis/remote/__init__.py +10 -0
  110. cubevis/remote/_gclean.py +61 -0
  111. cubevis/remote/_local.py +287 -0
  112. cubevis/remote/_remote_kernel.py +80 -0
  113. cubevis/toolbox/__init__.py +32 -0
  114. cubevis/toolbox/_app_context.py +74 -0
  115. cubevis/toolbox/_cube.py +3457 -0
  116. cubevis/toolbox/_region_list.py +197 -0
  117. cubevis/utils/_ResourceManager.py +86 -0
  118. cubevis/utils/__init__.py +620 -0
  119. cubevis/utils/_contextmgrchain.py +84 -0
  120. cubevis/utils/_conversion.py +93 -0
  121. cubevis/utils/_copydoc.py +55 -0
  122. cubevis/utils/_docenum.py +25 -0
  123. cubevis/utils/_import_protected_module.py +35 -0
  124. cubevis/utils/_logging.py +85 -0
  125. cubevis/utils/_pkgs.py +77 -0
  126. cubevis/utils/_regions.py +40 -0
  127. cubevis/utils/_static.py +66 -0
  128. cubevis/utils/_tiles.py +167 -0
  129. cubevis-0.5.2.dist-info/METADATA +151 -0
  130. cubevis-0.5.2.dist-info/RECORD +132 -0
  131. cubevis-0.5.2.dist-info/WHEEL +4 -0
  132. cubevis-0.5.2.dist-info/licenses/LICENSE +504 -0
@@ -0,0 +1,286 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2022
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ """
29
+ plotants module
30
+ """
31
+
32
+ import os
33
+
34
+ import numpy as np
35
+ from bokeh.io import export_png, export_svgs
36
+ from bokeh.models import ColumnDataSource, LabelSet
37
+ from bokeh.plotting import figure, show
38
+
39
+ try:
40
+ from cairosvg import svg2pdf
41
+ _have_svg2pdf = True
42
+ except ImportError:
43
+ _have_svg2pdf = False
44
+
45
+ try:
46
+ import casatools as ct
47
+ from casatools import table, msmetadata, quanta, ms, measures
48
+ except:
49
+ ct = None
50
+ from cubevis.utils import warn_import
51
+ warn_import('casatools')
52
+
53
+ _FIGURE_PLOT_WIDTH = 450
54
+ _FIGURE_PLOT_HEIGHT = 450
55
+
56
+
57
+ def __get_observatory_info(msname):
58
+ """Extract the observatory information from `msname`.
59
+
60
+ Parameters
61
+ ----------
62
+ msname: string
63
+ Path to a CASA measurement set.
64
+
65
+ Returns
66
+ -------
67
+ ( string, list )
68
+ string is the telescope name and the list is the array position
69
+ """
70
+ metadata = ct.msmetadata()
71
+ metadata.open(msname)
72
+ telescope = metadata.observatorynames()[0]
73
+ positions = metadata.observatoryposition()
74
+ metadata.close()
75
+ return telescope, positions
76
+
77
+
78
+ def __get_antenna_info(msname, log, exclude, checkbaselines):
79
+ """Return the antenna position info.
80
+
81
+ Parameters
82
+ ----------
83
+ msname: string
84
+ Path to the CASA measurement set.
85
+ log: boolean
86
+ whether to plot logarithmic positions
87
+ exclude: [ int ]
88
+ list antenna name/id selection to exclude from plot
89
+ checkbaselines: boolean
90
+ whether to check baselines in the main table
91
+ """
92
+ if ct is None:
93
+ raise RuntimeError('casatools is not available')
94
+
95
+ me = ct.measures()
96
+ qa = ct.quanta()
97
+ tb = ct.table()
98
+
99
+ telescope, positions = __get_observatory_info(msname)
100
+ positions_wgs84 = me.measure(positions, "WGS84")
101
+ array_lon, array_lat, = [positions_wgs84[i]["value"] for i in ["m0", "m1", "m2"]]
102
+
103
+ # Open the ANTENNA subtable to get the names of the antennas in this MS and
104
+ # their positions. Note that the entries in the ANTENNA subtable are pretty
105
+ # much in random order, so antenna_names translates between their index and name
106
+ # (e.g., index 11 = STD155). We'll need these indices for later, since the
107
+ # main data table refers to the antennas by their indices, not names.
108
+
109
+ anttabname = msname + "/ANTENNA"
110
+ tb.open(anttabname)
111
+ # Get antenna names from antenna table
112
+ antenna_names = np.array(tb.getcol("NAME")).tolist()
113
+ station_names = np.array(tb.getcol("STATION")).tolist()
114
+ if telescope == "VLBA": # names = ant@station
115
+ antenna_names = ["@".join(antsta) for antsta in zip(antenna_names, station_names)]
116
+ # Get antenna positions from antenna table
117
+ antenna_positions = np.array(
118
+ [
119
+ me.position("ITRF", qa.quantity(x, "m"), qa.quantity(y, "m"), qa.quantity(z, "m"))
120
+ for (x, y, z) in tb.getcol("POSITION").transpose()
121
+ ]
122
+ )
123
+ tb.close()
124
+
125
+ all_ant_ids = range(len(antenna_names))
126
+ if checkbaselines:
127
+ # Get antenna ids from main table; this will add to runtime
128
+ tb.open(msname)
129
+ ants1 = tb.getcol("ANTENNA1")
130
+ ants2 = tb.getcol("ANTENNA2")
131
+ tb.close()
132
+ ant_ids_used = list(set(np.append(ants1, ants2)))
133
+ else:
134
+ # use them all!
135
+ ant_ids_used = all_ant_ids
136
+
137
+ # handle exclude -- remove from ant_ids_used
138
+ for ant_id in exclude:
139
+ try:
140
+ ant_name_id = antenna_names[ant_id] + " (id " + str(ant_id) + ")"
141
+ ant_ids_used.remove(ant_id)
142
+ print( f'''Exclude antenna {ant_name_id}''' )
143
+ except ValueError:
144
+ print( f'''Cannot exclude antenna {ant_name_id}: not in main table''' )
145
+
146
+ # apply ant_ids_used mask
147
+ antenna_names = [antenna_names[i] for i in ant_ids_used]
148
+ antenna_positions = [antenna_positions[i] for i in ant_ids_used]
149
+ station_names = [station_names[i] for i in ant_ids_used]
150
+
151
+ n_ants = len(ant_ids_used)
152
+ # casalog.post("Number of points being plotted: " + str(n_ants))
153
+ if n_ants == 0: # excluded all antennas
154
+ return telescope, antenna_names, [], [], [], []
155
+
156
+ # Get the names, indices, and lat/lon/alt coords of "good" antennas.
157
+ ant_wgs84s = np.array([me.measure(pos, "WGS84") for pos in antenna_positions])
158
+
159
+ # Convert from lat, lon, alt to X, Y, Z (unless VLBA)
160
+ # where X is east, Y is north, Z is up,
161
+ # and 0, 0, 0 is the center
162
+ # Note: this conversion is NOT exact, since it doesn't take into account
163
+ # Earth's ellipticity! But it's close enough.
164
+ if telescope == "VLBA" and not log:
165
+ ant_lons, ant_lats = [[pos[i] for pos in ant_wgs84s] for i in ["m0", "m1"]]
166
+ ant_xs = [qa.convert(lon, "deg")["value"] for lon in ant_lons]
167
+ ant_ys = [qa.convert(lat, "deg")["value"] for lat in ant_lats]
168
+ else:
169
+ ant_lons, ant_lats = [np.array([pos[i]["value"] for pos in ant_wgs84s]) for i in ["m0", "m1"]]
170
+ rade = 6370000.0 # radE
171
+ ant_xs = (ant_lons - array_lon) * rade * np.cos(array_lat)
172
+ ant_ys = (ant_lats - array_lat) * rade
173
+ return telescope, antenna_names, ant_ids_used, ant_xs, ant_ys, station_names
174
+
175
+
176
+ def __plot_antennas_log(telescope, names, ids, xpos, ypos, antindex, stations, title):
177
+ raise NotImplementedError("This is a placeholder for another type of plot. It is not implemented yet.")
178
+
179
+
180
+ def __plot_antennas(telescope, names, ids, xpos, ypos, antindex, stations, title):
181
+ if telescope == "VLBA":
182
+ labelx = "Longitude (deg)"
183
+ labely = "Latitude (deg)"
184
+ else:
185
+ # use m or km units
186
+ units = " (m)"
187
+ if np.median(xpos) > 1e6 or np.median(ypos) > 1e6:
188
+ xpos /= 1e3
189
+ ypos /= 1e3
190
+ units = " (km)"
191
+ labelx = "X" + units
192
+ labely = "Y" + units
193
+ if antindex:
194
+ names = [f"{name} ({idx})" for name, idx in zip(names, ids)]
195
+ source = ColumnDataSource(data=dict(x=[], y=[], labels=[]))
196
+ source.data = dict(x=xpos, y=ypos, labels=names)
197
+ labels = LabelSet(x="x", y="y", text="labels", x_offset=5, y_offset=5, source=source, text_font_size="10pt")
198
+ plot = figure(plot_height=_FIGURE_PLOT_HEIGHT, plot_width=_FIGURE_PLOT_WIDTH)
199
+ plot.scatter("x", "y", source=source, size=5, line_color="red", fill_color="red", fill_alpha=0.5)
200
+ plot.title.text = title
201
+ plot.xaxis[0].axis_label = labelx
202
+ plot.yaxis[0].axis_label = labely
203
+ plot.add_layout(labels)
204
+ return plot
205
+
206
+
207
+ def plotants(vis, figfile="", antindex=False, logpos=False, exclude=[], checkbaselines=False, title="", showgui=True):
208
+ """Plot the antenna distribution in the local reference frame:
209
+ The location of the antennas in the MS will be plotted with
210
+ X-toward local east; Y-toward local north. The name of each
211
+ antenna is shown next to its respective location.
212
+
213
+ Parameters
214
+ ----------
215
+ vis: string
216
+ Path to the input visibility file
217
+
218
+ antindex: boolean, default: False
219
+ Label antennas with name and antenna ID
220
+
221
+ logpos: boolean, default: False
222
+ Produce a logarithmic position plot.
223
+
224
+ exclude: list, default: []
225
+ antenna IDs or names to exclude from plotting, for example:
226
+ exclude=[2,3,4], exclude=['DV15']
227
+
228
+ checkbaselines: boolean, default: False
229
+ Only plot antennas in the MAIN table. This can be useful after a split.
230
+ WARNING: Setting checkbaselines to True will add to runtime in proportion
231
+ to the number of rows in the dataset.
232
+
233
+ title: string, default: ''
234
+ Title written along top of plot
235
+ """
236
+ if os.path.exists(vis) is False:
237
+ raise Exception(f"Visibility file {vis} does not exist") # could be a print + return
238
+ # remove trailing / for title basename
239
+ if vis.endswith("/"):
240
+ vis = vis[:-1]
241
+
242
+ myms = ct.ms()
243
+ try:
244
+ exclude = myms.msseltoindex(vis, baseline=exclude)["antenna1"].tolist()
245
+ except RuntimeError as rterr: # MSSelection failed
246
+ errmsg = str(rterr)
247
+ errmsg = errmsg.replace("specificion", "specification")
248
+ errmsg = errmsg.replace("Antenna Expression: ", "")
249
+ raise RuntimeError("Exclude selection error: " + errmsg) from rterr
250
+
251
+ # Get the antenna positions
252
+ telescope, names, ids, xpos, ypos, stations = __get_antenna_info(vis, logpos, exclude, checkbaselines)
253
+ if not names:
254
+ raise ValueError("No antennas selected. Exiting plotants.")
255
+
256
+ if title == "":
257
+ msname = os.path.basename(vis)
258
+ title = "Antenna Positions for "
259
+ if len(msname) > 55:
260
+ title += "\n"
261
+ title += msname
262
+
263
+ if logpos:
264
+ fig = __plot_antennas_log(telescope, names, ids, xpos, ypos, antindex, stations, title)
265
+ else:
266
+ fig = __plot_antennas(telescope, names, ids, xpos, ypos, antindex, stations, title)
267
+
268
+ if showgui is not False:
269
+ show(fig)
270
+
271
+ if figfile != "":
272
+ if figfile.endswith(".png"):
273
+ export_png(fig, filename=figfile)
274
+ elif figfile.endswith(".svg"):
275
+ fig.output_backend = "svg"
276
+ export_svgs(fig, filename=figfile)
277
+ elif figfile.endswith(".pdf"):
278
+ if _have_svg2pdf == True:
279
+ fig.output_backend = "svg"
280
+ export_svgs(fig, filename=figfile.replace(".pdf", ".svg"))
281
+ svg2pdf(url=figfile.replace(".pdf", ".svg"), write_to=figfile)
282
+ os.system("rm " + figfile.replace(".pdf", ".svg"))
283
+ else:
284
+ raise RuntimeError("cairosvg is required for generating PDF output, but it is not available")
285
+ else:
286
+ raise ValueError("Invalid output file type. Must be .png or .svg or .pdf")
@@ -0,0 +1,7 @@
1
+ """Plotbandpass module
2
+ """
3
+
4
+ def plotbandpass():
5
+ """Plotbandpass function
6
+ """
7
+ raise NotImplementedError("This is a placeholder for plotbandpass. It is not implemented yet.")
@@ -0,0 +1,29 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2021, 2022
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ '''This module contains the extensions and additions to the functionality
29
+ provided by Bokeh'''
@@ -0,0 +1 @@
1
+ from ._ev_poly_annotation import EvPolyAnnotation
@@ -0,0 +1,6 @@
1
+ from bokeh.models import PolyAnnotation
2
+
3
+ class EvPolyAnnotation(PolyAnnotation):
4
+
5
+ def __init__(self, *args, **kwargs) -> None:
6
+ super().__init__(*args, **kwargs)
@@ -0,0 +1,28 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2021,2022,2023
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ '''Custom Bokeh GUI Components'''
@@ -0,0 +1,31 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2023
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ '''Implementation of Bokeh formatting extensions provided by ``cubevis``'''
29
+
30
+ from ._time_ticks import get_time_formatter
31
+ from ._wcs_ticks import WcsTicks
@@ -0,0 +1,44 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2025
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+
29
+ ''' Format time ticks for consistency at various zoom levels '''
30
+
31
+ from bokeh.models.formatters import DatetimeTickFormatter
32
+
33
+ def get_time_formatter():
34
+ ''' Tick formatter which includes H:M:S in most ticks '''
35
+ return DatetimeTickFormatter(
36
+ context_which = 'all',
37
+ microseconds='%fus',
38
+ milliseconds='%H:%M:%S %3Nms',
39
+ seconds='%H:%M:%S',
40
+ minsec='%H:%M:%S',
41
+ minutes='%H:%M:%S',
42
+ hourmin='%H:%M:%S',
43
+ hours='%H:%M:%S',
44
+ days='%F')
@@ -0,0 +1,45 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2023
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ from bokeh.models import TickFormatter
29
+ from bokeh.util.compiler import TypeScript
30
+ from bokeh.core.properties import Instance, String
31
+ from cubevis.bokeh.sources import ImageDataSource
32
+ from ..state import casalib_url, cubevisjs_url
33
+
34
+ class WcsTicks(TickFormatter):
35
+
36
+ ## which axis are we labeling
37
+ axis = String( )
38
+
39
+ ## source containing the WCS information
40
+ image_source = Instance(ImageDataSource)
41
+
42
+ __javascript__ = [ casalib_url( ), cubevisjs_url( ) ]
43
+
44
+ def __init__( self, *args, **kwargs ):
45
+ super( ).__init__( *args, **kwargs )
@@ -0,0 +1,4 @@
1
+ from ._tip_button import TipButton
2
+ from ._tip import Tip
3
+ from ._edit_span import EditSpan
4
+ from ._ev_text_input import EvTextInput
@@ -0,0 +1,7 @@
1
+ from bokeh.models import Span
2
+
3
+ class EditSpan(Span):
4
+
5
+ # explicit __init__ to support Init signatures
6
+ def __init__(self, *args, **kwargs) -> None:
7
+ super().__init__(*args, **kwargs)
@@ -0,0 +1,6 @@
1
+ from bokeh.models import TextInput
2
+
3
+ class EvTextInput(TextInput):
4
+
5
+ def __init__(self, *args, **kwargs) -> None:
6
+ super().__init__(*args, **kwargs)
@@ -0,0 +1,37 @@
1
+ from bokeh.models import Tooltip
2
+ from bokeh.models.layouts import LayoutDOM, UIElement
3
+ from bokeh.core.properties import Instance, Required, Float, Int, Either
4
+
5
+ class Tip(LayoutDOM):
6
+ '''Display a tooltip for the child element
7
+ '''
8
+
9
+ def __init__(self, *args, **kwargs) -> None:
10
+ if len(args) != 1 and "child" not in kwargs:
11
+ raise ValueError("a 'child' argument must be supplied")
12
+ elif len(args) == 1 and "child" in kwargs:
13
+ raise ValueError("'child' supplied as both a positional argument and a keyword")
14
+ elif len(args) > 1:
15
+ raise ValueError("only one 'child' can be supplied as a positional argument")
16
+ elif len(args) > 0:
17
+ kwargs["child"] = args[0]
18
+
19
+ super().__init__(**kwargs)
20
+
21
+ child = Required(Instance(UIElement), help="""
22
+ A child, which can be other components including plots, rows, columns, and widgets.
23
+ """)
24
+
25
+ tooltip = Required(Instance(Tooltip), help="""
26
+ A tooltip with plain text or rich HTML contents, providing general help or
27
+ description of a widget's or component's function.
28
+ """)
29
+
30
+ hover_wait = Either( Float, Int, default=1.5, help='''
31
+ amount of time (in seconds) to wait before displaying
32
+ ''' )
33
+
34
+ def _sphinx_height_hint(self):
35
+ if child._sphinx_height_hint() is None:
36
+ return None
37
+ return child._sphinx_height_hint()
@@ -0,0 +1,50 @@
1
+
2
+ from bokeh.models.callbacks import Callback
3
+ from bokeh.util.callback_manager import EventCallback
4
+ from bokeh.events import ButtonClick
5
+ from bokeh.models.widgets.buttons import AbstractButton
6
+ from bokeh.models.ui.icons import BuiltinIcon
7
+ from bokeh.core.properties import Instance, Required, Override, Nullable, Float, Int, Either
8
+ from bokeh.models import Tooltip
9
+
10
+
11
+
12
+ class TipButton(AbstractButton):
13
+ """ A button with a help symbol that displays additional text when hovered
14
+ over or clicked.
15
+ """
16
+
17
+ # explicit __init__ to support Init signatures
18
+ def __init__(self, *args, **kwargs) -> None:
19
+ super().__init__(*args, **kwargs)
20
+
21
+ tooltip = Required(Instance(Tooltip), help="""
22
+ A tooltip with plain text or rich HTML contents, providing general help or
23
+ description of a widget's or component's function.
24
+ """)
25
+
26
+ hover_wait = Either( Float, Int, default=1.5, help='''
27
+ amount of time (in seconds) to wait before displaying
28
+ ''' )
29
+
30
+ label = Override(default="")
31
+
32
+ icon = Override(default=lambda: BuiltinIcon("help", size=18))
33
+
34
+ button_type = Override(default="default")
35
+
36
+ def on_click(self, handler: EventCallback) -> None:
37
+ ''' Set up a handler for button clicks.
38
+
39
+ Args:
40
+ handler (func) : handler function to call when button is clicked.
41
+
42
+ Returns:
43
+ None
44
+
45
+ '''
46
+ self.on_event(ButtonClick, handler)
47
+
48
+ def js_on_click(self, handler: Callback) -> None:
49
+ ''' Set up a JavaScript handler for button clicks. '''
50
+ self.js_on_event(ButtonClick, handler)
@@ -0,0 +1,35 @@
1
+ ########################################################################
2
+ #
3
+ # Copyright (C) 2021,2022
4
+ # Associated Universities, Inc. Washington DC, USA.
5
+ #
6
+ # This script is free software; you can redistribute it and/or modify it
7
+ # under the terms of the GNU Library General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful, but WITHOUT
12
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
+ # License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Library General Public License
17
+ # along with this library; if not, write to the Free Software Foundation,
18
+ # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19
+ #
20
+ # Correspondence concerning AIPS++ should be adressed as follows:
21
+ # Internet email: casa-feedback@nrao.edu.
22
+ # Postal address: AIPS++ Project Office
23
+ # National Radio Astronomy Observatory
24
+ # 520 Edgemont Road
25
+ # Charlottesville, VA 22903-2475 USA
26
+ #
27
+ ########################################################################
28
+ '''Implementation of the Bokeh data source extensions provided by
29
+ ``cubevis``'''
30
+
31
+ from ._data_pipe import DataPipe
32
+ from ._image_pipe import ImagePipe
33
+ from ._image_data_source import ImageDataSource
34
+ from ._spectra_data_source import SpectraDataSource
35
+ from ._updatable_data_source import UpdatableDataSource