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,197 @@
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
+ import hashlib
29
+ from astropy.wcs import WCS
30
+ from regions import PixCoord, PolygonPixelRegion
31
+
32
+ class _Line:
33
+
34
+ def __init__( self, style ):
35
+ if not ( 'color' in style and 'width' in style and 'alpha' in style and 'dash' in style ):
36
+ raise RuntimeError( 'style must contain color, width, alpha and dash' )
37
+ self.__style = style
38
+
39
+ def color( self ):
40
+ return self.__style['color']
41
+
42
+ def width( self ):
43
+ return self.__style['width']
44
+
45
+ def alpha( self ):
46
+ return self.__style['alpha']
47
+
48
+ def dash( self ):
49
+ return self.__style['dash']
50
+
51
+ class _Fill:
52
+
53
+ def __init__( self, fill ):
54
+ if not ( 'color' in fill and 'alpha' in fill and 'hatch' in fill ):
55
+ raise RuntimeError( 'fill must contain color, alpha and hatch' )
56
+ self.__fill = fill
57
+
58
+ def color( self ):
59
+ return self.__fill['color']
60
+
61
+ def alpha( self ):
62
+ return self.__fill['alpha']
63
+
64
+ def hatch( self ):
65
+ return self.__fill['hatch']
66
+
67
+ class Region:
68
+
69
+ ### reuse astropy WCS objects based upon fits header strings
70
+ ### to avoid reparsing
71
+ wcs_cache = { }
72
+
73
+ def __init__( self, name, xs, ys, channels, line, fill, wcs=None ):
74
+ if type(name) != str:
75
+ raise RuntimeError( 'region names are strings' )
76
+ if len(xs) != len(ys):
77
+ raise RuntimeError( 'X and Y values must be of equal length' )
78
+
79
+ self.__ste = { }
80
+ self.__ste['name'] = name
81
+ self.__ste['xs'] = xs
82
+ self.__ste['ys'] = ys
83
+ self.__ste['chan'] = channels
84
+ self.__ste['line'] = line
85
+ self.__ste['fill'] = fill
86
+ self.__ste['wcs'] = None
87
+ if wcs is not None:
88
+ if isinstance(wcs,WCS):
89
+ self.__ste['wcs'] = wcs
90
+ elif type(wcs) == str:
91
+ ## Assume wcs is a FITS header
92
+ hash = hashlib.md5(wcs.encode()).hexdigest()
93
+ if hash not in Region.wcs_cache:
94
+ Region.wcs_cache[hash] = WCS( header=wcs )
95
+ self.__ste['wcs'] = Region.wcs_cache[hash]
96
+ else:
97
+ raise RuntimeError( f'''Regions initialized with non-FITS header representations of the WCS of type {type(wcs)} are not supported''' )
98
+
99
+ def __str__(self):
100
+ return self.__repr__( )
101
+
102
+ def __repr__(self):
103
+ return f'''<{self.__class__.__name__}({self.__ste['name']}) @ {hex(id(self))}>'''
104
+
105
+ def name( self ):
106
+ return self.__ste['name']
107
+
108
+ def xs( self ):
109
+ return self.__ste['xs']
110
+
111
+ def ys( self ):
112
+ return self.__ste['ys']
113
+
114
+ def vertices( self ):
115
+ return zip( self.__ste['xs'], self.__ste['ys'] )
116
+
117
+ def channels( self ):
118
+ return self.__ste['chan']
119
+
120
+ def line( self ):
121
+ return _Line( self.__ste['line'] )
122
+
123
+ def fill( self ):
124
+ return _Fill( self.__ste['fill'] )
125
+
126
+ def to_astropy_pixel( self ):
127
+ ### It seems as though there is no way to create 4 dimensional pixel coordinates (RA,DEC,STOKES,CHAN)
128
+ ### using astropy.
129
+ return PolygonPixelRegion( vertices=PixCoord( self.__ste['xs'], self.__ste['ys'],
130
+ ### meta and visual are not available on regions v0.10 which
131
+ ### seems to be the most recent version available with pip
132
+ #meta={ 'name': self.__ste['name'] },
133
+ #visual={ 'dash': self.__ste['line']['dash'],
134
+ # 'linewidth': self.__ste['line']['width'] }
135
+ ) )
136
+
137
+
138
+ def to_astropy_sky( self, wcs=None ):
139
+ if wcs is None:
140
+ wcs = self.__ste['wcs']
141
+ if wcs is None:
142
+ raise RuntimeError( 'No world coordinate system is available' )
143
+ ### Astropy coordinates seem to be limited to two dimensions so the generalized
144
+ ### WCS object (potentially with stokes and frequency axes) must be converted to
145
+ ### a two coordinate description.
146
+ return self.to_astropy_pixel( ).to_sky( wcs.sub([1,2]) )
147
+
148
+ class _Iter:
149
+ def __init__( self, ste ):
150
+ self.__ste = ste
151
+
152
+ def __iter__(self):
153
+ for name, rgn in self.__ste['raw'].items( ):
154
+ yield ( name, Region( name, rgn['geometry']['xs'], rgn['geometry']['ys'],
155
+ rgn['channels'], rgn['styling']['line'],
156
+ rgn['styling']['fill'], wcs=self.__ste['wcs'] ) )
157
+
158
+ class RegionList:
159
+ '''This class is for representing regions within cubevis applications. Currently it only wowrks with the
160
+ `createregion` app. It is not (currently) designed as an end user class but rather as an output class for
161
+ the user.
162
+
163
+ Currently it only accepts a dictionary like for `regiondict`:
164
+ ```
165
+ {'rg0': {'channels': [[0, 0]], 'geometry': {'xs': [33.51816859449925, 31.611101128190022, 121.40193309213468], 'ys': [195.13666993774888, 232.39613665715922, 229.12483086356568]}, 'styling': {'line': {'color': '#ffffff', 'width': 1, 'alpha': 1, 'dash': 'solid'}, 'fill': {'color': '#ffffff', 'alpha': 0, 'hatch': 'blank'}}}, 'rg1': {'channels': [[0, 0]], 'geometry': {'xs': [289.43821781788444, 347.2289277115166, 351.7707259199244], 'ys': [236.68983013019135, 232.27134277978703, 186.01834737432947]}, 'styling': {'line': {'color': '#ffffff', 'width': 1, 'alpha': 1, 'dash': 'solid'}, 'fill': {'color': '#ffffff', 'alpha': 0, 'hatch': 'blank'}}}, 'rg2': {'channels': [[0, 0]], 'geometry': {'xs': [346.576046788646, 334.82618711394673, 270.71434943666696], 'ys': [61.16382772497764, 9.769953019597281, 16.587407740876944]}, 'styling': {'line': {'color': '#ffffff', 'width': 1, 'alpha': 1, 'dash': 'solid'}, 'fill': {'color': '#ffffff', 'alpha': 0, 'hatch': 'blank'}}}, 'rg3': {'channels': [[0, 0]], 'geometry': {'xs': [17.33383873194185, 20.60032838342714, 105.68674392600984], 'ys': [65.03236450671528, 26.158256778791444, 15.71542171880079]}, 'styling': {'line': {'color': '#ffffff', 'width': 1, 'alpha': 1, 'dash': 'solid'}, 'fill': {'color': '#ffffff', 'alpha': 0, 'hatch': 'blank'}}}, 'rg4': {'channels': [[0, 0]], 'geometry': {'xs': [194.1150775408404, 186.7420925740613, 247.32924839610087, 257.7778686999655, 220.3835500015239], 'ys': [100.28458653562863, 138.0450054510982, 136.91400495710235, 109.48993737427867, 75.12723329938433]}, 'styling': {'line': {'color': '#ffffff', 'width': 1, 'alpha': 1, 'dash': 'solid'}, 'fill': {'color': '#ffffff', 'alpha': 0, 'hatch': 'blank'}}}}
166
+ ```
167
+ The `wcs` parameter could either be a string representation of a FITS wcs header or it could be an
168
+ astropy `WCS` object.
169
+ '''
170
+
171
+ def __init__( self, regiondict, wcs ):
172
+
173
+ self.__ste = { 'wcs': wcs }
174
+ self.__summary_size = 22
175
+
176
+ if type(regiondict) != dict:
177
+ raise RuntimeError( 'RegionList must be initialized with a dictionary representation of regions' )
178
+ self.__ste['raw'] = regiondict
179
+
180
+ def __iter__(self):
181
+ return _Iter(self.__ste).__iter__( )
182
+
183
+ def __str__(self):
184
+ return self.__repr__( )
185
+
186
+ def __repr__(self):
187
+ added = 0
188
+ names = ''
189
+ keys = self.__ste['raw'].keys( )
190
+ for name in keys:
191
+ if len(names) + len(names) > self.__summary_size: break
192
+ names = names + (',' if len(names) > 0 else '') + name
193
+ added = added + 1
194
+ if added < len(keys):
195
+ names = f'''{names}...'''
196
+ return f'''<{self.__class__.__name__}[{names}] @ {hex(id(self))}>'''
197
+
@@ -0,0 +1,86 @@
1
+ import weakref
2
+ import atexit
3
+ import asyncio
4
+ import sys
5
+
6
+ from ._logging import get_logger
7
+ logger = get_logger()
8
+
9
+ class _ResourceManager:
10
+ """ This class acts as a single place to manage the destruction of system
11
+ resources (event_loops, ports, etc). To start with, get the singleton
12
+ instance via
13
+
14
+ import utils.resource_manager
15
+ """
16
+ def __init__(self):
17
+ # A list of webservers to close when the event loop is closed.
18
+ self.webservers_to_close = []
19
+ self.reg_at_exit(self, 'stop_asyncio_loop')
20
+
21
+ def reg_webserver(self, websockets_server):
22
+ """ Register a webserver to be closed when the event loop is stopped. """
23
+ self.webservers_to_close.append(weakref.ref(websockets_server))
24
+
25
+ def reg_at_exit(self, obj_or_func=None, fname="", *vargs):
26
+ """ Register a function or method to be called when python exits.
27
+ @param obj_or_func An object containing a method fname, or a global/static function.
28
+ @param fname If obj_or_func is an object instance, then this can be the method name
29
+ of the object to call.
30
+ @param vargs Any extra parameters to pass to the obj_or_func or fname function.
31
+ """
32
+ if (fname == "" and callable(obj_or_func)):
33
+ atexit.register(obj_or_func, *vargs)
34
+ else:
35
+ ref = weakref.ref(obj_or_func)
36
+ atexit.register(self._call_on_ref, ref, fname, *vargs)
37
+
38
+ def stop_asyncio_loop(self):
39
+ """ Calls "stop" on the event_loop and closes any webservers registered
40
+ with reg_webserver. """
41
+ logger.debug("stop_asyncio_loop")
42
+ try:
43
+ event_loop = asyncio.get_running_loop()
44
+ self._close_webservers(event_loop)
45
+ event_loop.stop()
46
+ return
47
+ except RuntimeError:
48
+ self._close_webservers(None)
49
+ return
50
+
51
+ def _close_webserver(self, server_weakref, event_loop=None):
52
+ """ Close the given webserver. If event_loop != None, then use the loop
53
+ to wait, blocking until the server has finished closing. """
54
+ instance = server_weakref()
55
+ if (instance == None):
56
+ logger.debug("close_webserver(None)")
57
+ return
58
+ logger.debug(f"close_webserver({instance})")
59
+ instance.close()
60
+ if event_loop != None:
61
+ event_loop.run_until_complete(instance.wait_closed())
62
+
63
+ def _close_webservers(self, event_loop):
64
+ """ Calls _close_webserver for each server registered with reg_webserver. """
65
+ for webserver in self.webservers_to_close:
66
+ self._close_webserver(webserver, event_loop)
67
+ self.webservers_to_close.clear()
68
+
69
+ def _call_on_ref(self, ref, fname, *vargs):
70
+ """ Call the function named fname on the given object instance ref, aka:
71
+
72
+ ref.fname(*vargs)
73
+ """
74
+ instance = ref()
75
+ if instance == None:
76
+ logger.debug('call_on_ref(None)')
77
+ return
78
+ if not hasattr(instance, fname):
79
+ logger.debug(f"call_on_ref({instance.__class__.__name__}.{fname} == None)")
80
+ return
81
+ instance_method = getattr(instance, fname)
82
+ if not callable(instance_method):
83
+ logger.debug(f"call_on_ref(non-callable {instance.__class__.__name__}.{fname})")
84
+ return
85
+ logger.debug(f"{instance.__class__.__name__}.{fname}()")
86
+ instance_method(*vargs)