cubevis 1.0.0__py3-none-any.whl → 1.0.4__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 (46) hide show
  1. cubevis/__init__.py +12 -23
  2. cubevis/__js__/bokeh-3.6/cubevisjs.min.js +64 -0
  3. cubevis/__js__/{cubevisjs.min.js → bokeh-3.7/cubevisjs.min.js} +3 -3
  4. cubevis/__js__/bokeh-3.8/cubevisjs.min.js +64 -0
  5. cubevis/__js__/casalib.min.js +1 -1
  6. cubevis/__version__.py +1 -1
  7. cubevis/bokeh/__init__.py +16 -0
  8. cubevis/bokeh/annotations/_ev_poly_annotation.py +2 -1
  9. cubevis/bokeh/format/_wcs_ticks.py +6 -2
  10. cubevis/bokeh/models/__init__.py +1 -0
  11. cubevis/bokeh/models/_showable.py +352 -0
  12. cubevis/bokeh/models/_tip.py +2 -1
  13. cubevis/bokeh/models/_tip_button.py +2 -3
  14. cubevis/bokeh/sources/_data_pipe.py +6 -2
  15. cubevis/bokeh/sources/_image_data_source.py +6 -2
  16. cubevis/bokeh/sources/_image_pipe.py +4 -1
  17. cubevis/bokeh/sources/_spectra_data_source.py +6 -3
  18. cubevis/bokeh/sources/_updatable_data_source.py +6 -2
  19. cubevis/bokeh/state/__init__.py +4 -3
  20. cubevis/bokeh/state/_current.py +34 -0
  21. cubevis/bokeh/state/_initialize.py +282 -116
  22. cubevis/bokeh/state/_javascript.py +95 -21
  23. cubevis/bokeh/tools/_cbreset_tool.py +2 -1
  24. cubevis/bokeh/tools/_drag_tool.py +2 -1
  25. cubevis/bokeh/utils/__init__.py +0 -1
  26. cubevis/exe/_setting.py +1 -0
  27. cubevis/private/apps/__init__.py +4 -2
  28. cubevis/private/apps/_interactiveclean.mustache +6 -2
  29. cubevis/private/apps/_interactiveclean.py +6 -2
  30. cubevis/private/apps/_interactivecleannotebook.mustache +112 -0
  31. cubevis/private/apps/_interactivecleannotebook.py +1874 -0
  32. cubevis/private/casatasks/iclean.py +4 -0
  33. cubevis/toolbox/_app_context.py +5 -9
  34. cubevis/toolbox/_cube.py +6 -2
  35. cubevis/toolbox/_interactive_clean_ui.mustache +20 -31
  36. cubevis/toolbox/_interactive_clean_ui.py +20 -31
  37. cubevis/utils/__init__.py +183 -41
  38. cubevis/utils/_git.py +36 -0
  39. cubevis/utils/_jupyter.py +12 -0
  40. {cubevis-1.0.0.dist-info → cubevis-1.0.4.dist-info}/METADATA +3 -3
  41. {cubevis-1.0.0.dist-info → cubevis-1.0.4.dist-info}/RECORD +43 -39
  42. cubevis/__js__/bokeh-3.6.1.min.js +0 -728
  43. cubevis/__js__/bokeh-tables-3.6.1.min.js +0 -119
  44. cubevis/__js__/bokeh-widgets-3.6.1.min.js +0 -141
  45. {cubevis-1.0.0.dist-info → cubevis-1.0.4.dist-info}/WHEEL +0 -0
  46. {cubevis-1.0.0.dist-info → cubevis-1.0.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  ########################################################################
2
2
  #
3
- # Copyright (C) 2021,2022,2023
3
+ # Copyright (C) 2021,2022,2023,2025
4
4
  # Associated Universities, Inc. Washington DC, USA.
5
5
  #
6
6
  # This script is free software; you can redistribute it and/or modify it
@@ -30,135 +30,301 @@ generated HTML that is used to display the Bokeh plots that ``casagui``'s
30
30
  applications produce'''
31
31
  import os
32
32
  import re
33
+ import logging
33
34
  from os import path
35
+ from enum import Enum
34
36
  from os.path import dirname, join, basename, abspath
35
37
  from urllib.parse import urlparse
36
38
  from bokeh import resources
39
+ from bokeh.settings import settings
37
40
  from ...utils import path_to_url, static_vars, have_network
38
41
 
42
+ logger = logging.getLogger(__name__)
39
43
 
40
- @static_vars( initialized=False,
41
- do_local_subst=not have_network( ) )
42
- def initialize_bokeh( bokehjs_subst=None ):
44
+ _CUBEVIS_LIBS = {}
45
+ # Selector for which source to prefer for JavaScript files. Bokeh's Python
46
+ # package comes with static versions of the Bokeh JavaScript libraries.
47
+ # cubevis libraries are available both as static versions contained within
48
+ # the Python package and from an NRAO website.
49
+ #
50
+ # None = auto-detect, 'local' = prefer local, 'network' = prefer network
51
+ class JsLoading(Enum):
52
+ AUTO = 'auto'
53
+ LOCAL = 'local'
54
+ NETWORK = 'network'
55
+
56
+ _JS_STRATEGY = JsLoading.AUTO
57
+
58
+ # Package-level registry
59
+ _JUPYTER_STATE = {
60
+ 'models_registered': set()
61
+ }
62
+
63
+ def get_cubevis_libs( ):
64
+ """Get the package-level default cubevis paths"""
65
+ return _CUBEVIS_LIBS
66
+
67
+ def set_cubevis_lib(**kw):
68
+ """Set custom paths for cubevis JavaScript libraries"""
69
+ libs = get_cubevis_libs()
70
+ for lib in ['bokeh', 'bokeh_widgets', 'bokeh_tables', 'casalib', 'cubevisjs']:
71
+ if lib in kw:
72
+ libs[lib] = kw[lib]
73
+ return libs
74
+
75
+ def get_js_loading( ):
76
+ """Get JavaScript loading strategy.
77
+ """
78
+ return _JS_STRATEGY
79
+
80
+ def set_js_loading(strategy):
81
+ """Set JavaScript loading strategy.
82
+
83
+ Args:
84
+ strategy (JsLoading or str):
85
+ - 'auto': Smart selection based on environment
86
+ - 'local': Always prefer local static files when available
87
+ - 'network': Always prefer network CDN when available
88
+ """
89
+ global _JS_STRATEGY
90
+ if isinstance(strategy, str):
91
+ _JS_STRATEGY = JsLoading(strategy)
92
+ elif isinstance(strategy, JsLoading):
93
+ _JS_STRATEGY = strategy
94
+ else:
95
+ raise TypeError("'strategy' must be a valid JsLoading string or enum member")
96
+
97
+ def get_js_loading_selection( ):
98
+ # Check for user override
99
+ global _JS_STRATEGY
100
+
101
+ prefer_network = False
102
+ prefer_local = False
103
+
104
+ in_jupyter = is_jupyter()
105
+ use_network = have_network()
106
+
107
+ if _JS_STRATEGY is JsLoading.LOCAL:
108
+ prefer_network = False
109
+ prefer_local = True
110
+ logger.debug("Strategy: User override -> prefer local")
111
+ elif _JS_STRATEGY is JsLoading.NETWORK:
112
+ prefer_network = True
113
+ prefer_local = False
114
+ logger.debug("Strategy: User override -> prefer network")
115
+ else:
116
+ # Auto-detect optimal strategy
117
+ if in_jupyter and use_network:
118
+ # Jupyter notebooks work best with CDN versions
119
+ prefer_network = True
120
+ prefer_local = False
121
+ logger.debug("Strategy: Jupyter + network -> prefer CDN")
122
+ elif not use_network:
123
+ # No choice - must use local
124
+ prefer_network = False
125
+ prefer_local = True
126
+ logger.debug("Strategy: No network -> local only")
127
+ else:
128
+ # Standalone application with network -> prefer local for speed/reliability
129
+ prefer_network = False
130
+ prefer_local = True
131
+ logger.debug("Strategy: Standalone + network -> prefer local static")
132
+
133
+ return prefer_local, prefer_network
134
+
135
+ def is_jupyter():
136
+ """Check if running in Jupyter environment"""
137
+ try:
138
+ from IPython import get_ipython
139
+ return get_ipython() is not None
140
+ except ImportError:
141
+ return False
142
+
143
+ def resolve_js_library_paths():
144
+ """Resolve paths to all required JavaScript libraries based on environment and availability.
145
+
146
+ Strategy:
147
+ - Jupyter notebooks: Prefer network CDN (required for proper functionality)
148
+ - Standalone apps with network: Prefer local static (faster, more reliable)
149
+ - No network: Use local static (only option)
150
+ - Corporate/restricted networks: Prefer local static (firewall bypass)
151
+
152
+ Returns:
153
+ dict: Dictionary with resolved paths for 'casalib', 'bokeh', 'bokeh_widgets',
154
+ 'bokeh_tables', and 'cubevisjs'
155
+ """
156
+ ### These functions also select remote/local based on Jupyter or
157
+ ### no network because these URLs also are included in the
158
+ ### __javascript__ variables for Bokeh model derived member variables.
159
+ from . import casalib_url as get_casalib_url
160
+ from . import cubevisjs_url as get_cubevisjs_url
161
+
162
+ # Start with user-defined overrides
163
+ result = get_cubevis_libs().copy()
164
+
165
+ # Handle {JSLIB}/ substitution for user paths
166
+ for key, value in result.items():
167
+ if value and value.startswith("{JSLIB}/"):
168
+ result[key] = path_to_url(value[8:])
169
+
170
+ prefer_local, prefer_network = get_js_loading_selection( )
171
+
172
+ # Get available sources
173
+ bokeh_static_js = {}
174
+ bokeh_static_available = False
175
+
176
+ try:
177
+ bokeh_static_path = settings.bokehjs_path()
178
+ js_dir = join(bokeh_static_path, 'js')
179
+ logger.debug( f"Bokeh static pat: {js_dir}" )
180
+
181
+ if path.exists(js_dir):
182
+ for filename in os.listdir(js_dir):
183
+ if filename.endswith('.js'):
184
+ file_path = f"file://{abspath(join(js_dir, filename))}"
185
+
186
+ ## js_dir seems to contain both minified and non minified versions of
187
+ ## the bokeh librarys. If we ever want to allow for non-minified
188
+ ## versions, e.g. for debugging, we'll need to look here
189
+ if re.match(r'.*bokeh(?:-\d+\.\d+\.\d+)?\.min\.js$', filename):
190
+ bokeh_static_js['bokeh'] = file_path
191
+ elif re.match(r'.*bokeh-widgets(?:-\d+\.\d+\.\d+)?\.min\.js$', filename):
192
+ bokeh_static_js['bokeh_widgets'] = file_path
193
+ elif re.match(r'.*bokeh-tables(?:-\d+\.\d+\.\d+)?\.min\.js$', filename):
194
+ bokeh_static_js['bokeh_tables'] = file_path
195
+
196
+ bokeh_static_available = len(bokeh_static_js) > 0
197
+
198
+ except Exception as e:
199
+ logger.warning(f"Could not access Bokeh static files: {e}")
200
+
201
+ # Network connection available
202
+ use_network = have_network()
203
+
204
+ # Fill in missing Bokeh libraries using the selected strategy
205
+ for lib in ['bokeh', 'bokeh_widgets', 'bokeh_tables']:
206
+ if lib not in result or result[lib] is None:
207
+ if prefer_local and bokeh_static_available and lib in bokeh_static_js:
208
+ result[lib] = bokeh_static_js[lib]
209
+ logger.debug(f"Using local static for {lib}")
210
+ elif prefer_network and use_network:
211
+ # Let Bokeh handle CDN URLs - return None to use defaults
212
+ result[lib] = None
213
+ logger.debug(f"Using CDN for {lib}")
214
+ elif bokeh_static_available and lib in bokeh_static_js:
215
+ # Fallback to local if network preference fails
216
+ result[lib] = bokeh_static_js[lib]
217
+ logger.debug(f"Fallback to local static for {lib}")
218
+ else:
219
+ # Last resort - try local cache
220
+ try:
221
+ cached_path = path_to_url(f"{lib}.min.js")
222
+ if cached_path != f"{lib}.min.js": # Found in cache
223
+ result[lib] = cached_path
224
+ logger.debug(f"Using local cache for {lib}")
225
+ else:
226
+ result[lib] = None
227
+ logger.debug(f"No source found for {lib}")
228
+ except:
229
+ result[lib] = None
230
+
231
+ # Fill in cubevis-specific libraries
232
+ if 'casalib' not in result or result['casalib'] is None:
233
+ result['casalib'] = get_casalib_url( )
234
+
235
+ if 'cubevisjs' not in result or result['cubevisjs'] is None:
236
+ result['cubevisjs'] = get_cubevisjs_url( )
237
+
238
+ logger.debug(f"Resolved JS library paths: {result}")
239
+ logger.debug(f"Environment: jupyter={is_jupyter( )}, network={use_network}, strategy={'network' if prefer_network else 'local'}")
240
+
241
+ return result
242
+
243
+ @static_vars(initialized=False)
244
+ def order_bokeh_js():
43
245
  """Initialize `bokeh` for use with the ``cubevisjs`` extensions.
44
246
 
45
- The ``cubevisjs`` extensions for Bokeh are built into a stand-alone
46
- external JavaScript file constructed for the specific version of
47
- Bokeh that is being used. Previously the CASA minified JavaScript
48
- libraries were loaded from the network. Now these libraries are
49
- included in a ``__js__`` directory within the cubevis Python package.
50
- If users need to debug JavaScript problems, non-minified versions
51
- can be copied into the ``__js__`` directory to replace the existing
52
- libraries. To debug within the bokehjs library, a URL or a path
53
- can be supplied by the ``bokehjs_subst`` parameter and it will be
54
- substituted for the standard Bokeh library.
55
-
56
- Parameters
57
- ----------
58
- bokehjs_subst: None or str or list of str
59
- Bokeh dependent javascript library which is loaded after all
60
- other Bokeh libraries have been loaded. This path could be a
61
- local path, a URL or None. None is the default in which case
62
- it loads the published library for the current version of
63
- ``cubevisjs`` and ``bokeh``
64
-
65
- Example
66
- -------
67
- from cubevis.bokeh.state import initialize_bokeh
68
- initialize_bokeh( bokehjs_subst="/tmp/bokeh-3.2.2.js" )
247
+ This function injects the cubevis JavaScript libraries into Bokeh's resource
248
+ loading system in the proper order: casalib bokeh core → bokeh widgets →
249
+ bokeh tables cubevisjs.
250
+
251
+ The function automatically determines the best source for JavaScript libraries
252
+ based on the current environment (Jupyter vs standalone, network availability, etc.).
69
253
  """
70
254
 
71
- if initialize_bokeh.initialized:
72
- ### only initialize once...
255
+ if order_bokeh_js.initialized:
73
256
  return
74
257
 
75
- initialize_bokeh.initialized = True
258
+ # Get all resolved library paths
259
+ js_paths = resolve_js_library_paths()
260
+
261
+ logger.debug(f"order_bokeh_js() initializing with paths: {js_paths}")
262
+ order_bokeh_js.initialized = True
263
+
264
+ # Store original Bokeh js_files function
76
265
  resources.Resources._old_js_files = resources.Resources.js_files
77
- def js_files( self ):
78
- ########################################################################
79
- ### Function that will replace the member function within Bokeh that ###
80
- ### returns the URLs for Bokeh initialization... ###
81
- ########################################################################
82
- def expand_paths( replacement ):
83
- ### turn all paths into URLs
84
- ### turn a single string into a list with one string
85
- if replacement is None:
86
- return [ ]
87
- if type(replacement) == str:
88
- if path.isfile(replacement):
89
- return [ f'''file://{abspath(replacement)}''' ]
90
- elif replacement.startswith('http'):
91
- return [ replacement ]
92
- else:
93
- raise RuntimeError( f'''debugging bokehjs substitution ('{replacement}') does not exist''' )
94
- if type(replacement) == list:
95
- result = [ ]
96
- for u in replacement:
97
- if path.isfile(u):
98
- result.append( f'''file://{abspath(u)}''' )
99
- elif u.startswith('http'):
100
- result.append( u )
101
- else:
102
- raise RuntimeError( f'''debugging bokehjs substitution ('{u}') does not exist''' )
103
- return result
104
- return [ ]
105
- def cubevisjs_predicate( s ):
106
- ### detect cubevisjs library URL
107
- return basename(s).startswith('cubevisjs')
108
- def replace_bokehjs( urls, replacement ):
109
- ### substitute replacement list for the bokehjs library URL
110
- result = [ ]
111
- for url in urls:
112
- if re.match( r'.*/bokeh-\d+\.\d+\.\d+(?:\.min)?\.js$', url ):
113
- result += replacement
114
- else:
115
- result.append(url)
116
- return result
117
-
118
- def include_all_bokehjs( urls ):
119
- result = urls.copy( )
120
- bokeh_path=None
121
- has_bokeh_widgets=False
122
- has_bokeh_tables=False
123
- for url in urls:
124
- if re.match( r'.*/bokeh-\d+\.\d+\.\d+(?:\.min)?\.js$', url ):
125
- bokeh_path = url
126
- if re.match( r'.*/bokeh-widgets-\d+\.\d+\.\d+(?:\.min)?\.js$', url ):
127
- has_bokeh_widgets = True
128
- if re.match( r'.*/bokeh-tables-\d+\.\d+\.\d+(?:\.min)?\.js$', url ):
129
- has_bokeh_tables = True
130
-
131
- if bokeh_path:
132
- if not has_bokeh_widgets:
133
- result.append( bokeh_path.replace('/bokeh-','/bokeh-widgets-') )
134
- if not has_bokeh_tables:
135
- result.append( bokeh_path.replace('/bokeh-','/bokeh-tables-') )
136
-
137
- return result
138
-
139
- user_bokehjs_replacement = expand_paths(bokehjs_subst)
140
- sys_urls = include_all_bokehjs( resources.Resources._old_js_files.fget(self) )
141
- if initialize_bokeh.do_local_subst:
142
- local_urls = [ ]
143
- for url in sys_urls:
144
- pieces = urlparse(url)
145
- if pieces.scheme != 'file':
146
- lib = basename(pieces.path)
147
- url = path_to_url(lib)
148
- if lib != url:
149
- local_urls.append(url)
150
- else:
151
- raise RuntimeError( '''Cannot confirm internet access and could not find local cached versions of Bokeh's libraries''' )
152
- else:
153
- local_urls.append(url)
154
- sys_urls = local_urls
155
-
156
- if len(user_bokehjs_replacement) == 0:
157
- ### move cubevisjs library after Bokeh libraries
158
- return [x for x in sys_urls if not cubevisjs_predicate(x)] + [x for x in sys_urls if cubevisjs_predicate(x)]
159
- else:
160
- ### replace bokehjs library with bokehjs_subst and move cubevisjs library after Bokeh libraries
161
- return replace_bokehjs( [x for x in sys_urls if not cubevisjs_predicate(x)], user_bokehjs_replacement ) + [x for x in sys_urls if cubevisjs_predicate(x)]
162
266
 
267
+ def js_files(self):
268
+ """Replacement function that returns JavaScript files in the correct order"""
269
+
270
+ # Get original Bokeh URLs as fallback
271
+ original_urls = resources.Resources._old_js_files.fget(self)
272
+ logger.debug( f"Original Bokeh JavaScript: {original_urls}" )
273
+
274
+ def get_url_or_fallback(lib_key, fallback_pattern=None):
275
+ """Get resolved URL or find fallback from original Bokeh URLs"""
276
+ resolved_path = js_paths.get(lib_key)
277
+
278
+ if resolved_path:
279
+ return resolved_path
280
+
281
+ # Look for fallback in original URLs
282
+ if fallback_pattern:
283
+ for url in original_urls:
284
+ if re.match(fallback_pattern, url):
285
+ return url
286
+
287
+ return None
288
+
289
+ # Build the ordered list
290
+ ordered_js = []
291
+
292
+ # 1. casalib (always first)
293
+ casalib_url = get_url_or_fallback('casalib')
294
+ if casalib_url:
295
+ ordered_js.append(casalib_url)
296
+
297
+ # 2. bokeh core
298
+ bokeh_url = get_url_or_fallback('bokeh', r'.*/bokeh-\d+\.\d+\.\d+(?:\.min)?\.js$')
299
+ if bokeh_url:
300
+ ordered_js.append(bokeh_url)
301
+
302
+ # 3. bokeh widgets
303
+ widgets_url = get_url_or_fallback('bokeh_widgets', r'.*/bokeh-widgets-\d+\.\d+\.\d+(?:\.min)?\.js$')
304
+ if widgets_url:
305
+ ordered_js.append(widgets_url)
306
+
307
+ # 4. bokeh tables
308
+ tables_url = get_url_or_fallback('bokeh_tables', r'.*/bokeh-tables-\d+\.\d+\.\d+(?:\.min)?\.js$')
309
+ if tables_url:
310
+ ordered_js.append(tables_url)
311
+
312
+ # 5. cubevisjs (always last)
313
+ cubevisjs_url = get_url_or_fallback('cubevisjs')
314
+ if cubevisjs_url:
315
+ ordered_js.append(cubevisjs_url)
316
+
317
+ logger.debug(f"Final JS load order: {ordered_js}")
318
+ return ordered_js
319
+
320
+ # Replace Bokeh's js_files property
163
321
  resources.Resources.js_files = property(js_files)
164
322
  return
323
+
324
+ def get_jupyter_state( ):
325
+ """Get the package-level Jupyter state"""
326
+ return _JUPYTER_STATE
327
+
328
+ def register_model(model_class):
329
+ """Register a model class that needs dependencies"""
330
+ _JUPYTER_STATE['models_registered'].add(model_class.__name__)
@@ -1,6 +1,6 @@
1
1
  ########################################################################
2
2
  #
3
- # Copyright (C) 2023
3
+ # Copyright (C) 2023,2025
4
4
  # Associated Universities, Inc. Washington DC, USA.
5
5
  #
6
6
  # This script is free software; you can redistribute it and/or modify it
@@ -28,26 +28,100 @@
28
28
  '''This contains functions which return the URLs to the ``cubevis``
29
29
  JavaScript libraries. The ``casalib`` library has Bokeh independent
30
30
  functions while the `cubevisjs` library has the Bokeh extensions'''
31
- from ...utils import static_vars
32
- from ._initialize import initialize_bokeh
33
- from os import path
31
+ from os import path, environ
32
+ from pathlib import Path
33
+ from packaging import version
34
+ from bokeh import __version__ as bokeh_version
35
+ from . import get_js_loading_selection
36
+ from ...utils import max_git_version as _max_git_version
34
37
 
35
- @static_vars( library_path=None )
38
+ _local_library_path = None
39
+ _bokeh_major_minor = None
40
+
41
+ _CUBEVIS_RELEASE_VERSION = None
42
+ _CUBEVIS_GITHUB_VERSION = None
43
+ _BOKEH_MAJOR_MINOR = None
44
+ _CUBEVIS_JS_TAG = None
45
+
46
+ def bokeh_major_minor( ):
47
+ global _BOKEH_MAJOR_MINOR
48
+ if _BOKEH_MAJOR_MINOR is None:
49
+ from bokeh import __version__ as bokeh_version
50
+ v = version.parse(bokeh_version)
51
+ _BOKEH_MAJOR_MINOR = f"{v.major}.{v.minor}"
52
+ return _BOKEH_MAJOR_MINOR
53
+
54
+ def github_js_tag( ):
55
+ global _CUBEVIS_JS_TAG
56
+ if _CUBEVIS_JS_TAG is None:
57
+ release = cubevis_release_version( )
58
+ if release is not None:
59
+ _CUBEVIS_JS_TAG = f"v{release}"
60
+ else:
61
+ if 'CUBEVIS_JS_TAG' in environ:
62
+ _CUBEVIS_JS_TAG = environ['CUBEVIS_JS_TAG']
63
+ else:
64
+ _CUBEVIS_JS_TAG = f"v{cubevis_github_version( )}"
65
+ return _CUBEVIS_JS_TAG
66
+
67
+ def cubevis_github_version( ):
68
+ global _CUBEVIS_GITHUB_VERSION
69
+ if _CUBEVIS_GITHUB_VERSION is None:
70
+ _CUBEVIS_GITHUB_VERSION = _max_git_version( )
71
+ return _CUBEVIS_GITHUB_VERSION
72
+
73
+ def cubevis_release_version( ):
74
+ global _CUBEVIS_RELEASE_VERSION
75
+ if _CUBEVIS_RELEASE_VERSION is None:
76
+ try:
77
+ ###
78
+ ### __version__.py is generated as part of the build, but if the source tree
79
+ ### for cubevis is used directly for development, no __version__.py will be
80
+ ### available...
81
+ ###
82
+ from ...__version__ import __version__ as package_version
83
+ _CUBEVIS_RELEASE_VERSION = package_version
84
+ except ModuleNotFoundError: pass
85
+ return _CUBEVIS_RELEASE_VERSION
86
+
87
+ def casalib_path( ):
88
+ global _local_library_path
89
+ if _local_library_path is None:
90
+ _local_library_path = path.join( path.dirname(path.dirname(path.dirname(__file__))), '__js__' )
91
+ casalib_path = path.join( _local_library_path, 'casalib.min.js' )
92
+ if not path.isfile( casalib_path ):
93
+ raise RuntimeError( f''''casalib' JavaScript library not found at '{casalib_path}\'''' )
94
+ return casalib_path
95
+
96
+ def cubevisjs_path( ):
97
+ global _local_library_path
98
+ global _bokeh_major_minor
99
+ if _local_library_path is None:
100
+ _local_library_path = path.join( path.dirname(path.dirname(path.dirname(__file__))), '__js__' )
101
+ if _bokeh_major_minor is None:
102
+ version = bokeh_version.split('.')
103
+ _bokeh_major_minor = f"{version[0]}.{version[1]}"
104
+ cubevisjs_path = path.join( _local_library_path, f"bokeh-{_bokeh_major_minor}", 'cubevisjs.min.js' )
105
+ if not path.isfile(cubevisjs_path):
106
+ raise RuntimeError( f''''cubevisjs' JavaScript library not found at '{cubevisjs_path}\'''' )
107
+ return cubevisjs_path
108
+
109
+ ### These functions MUST also select remote/local based on Jupyter or
110
+ ### no network because these URLs also are included in the
111
+ ### __javascript__ variables for Bokeh model derived member variables.
112
+ ### These paths are then included in the Bokeh list of JavaScript
113
+ ### libraries loaded when the GUI is loaded. However, the ordering is
114
+ ### not correct because cubevisjs.min.js must appear AFTER all of the
115
+ ### Bokeh files.
36
116
  def casalib_url( ):
37
- if casalib_url.library_path is None:
38
- casalib_url.library_path = path.join(path.dirname(path.dirname(path.dirname(__file__))), '__js__', 'casalib.min.js')
39
- if not path.isfile(casalib_url.library_path):
40
- raise RuntimeError( f''''casalib' JavaScript library not found at '{casalib_url.library_path}\'''' )
41
- if not initialize_bokeh.initialized:
42
- initialize_bokeh( )
43
- return f'''file://{casalib_url.library_path}'''
44
-
45
- @static_vars( library_path=None )
117
+ prefer_local, prefer_network = get_js_loading_selection( )
118
+ if prefer_network:
119
+ return f"https://cdn.jsdelivr.net/gh/casangi/cubevis@{github_js_tag( )}/cubevis/__js__/casalib.min.js"
120
+ else:
121
+ return f"file://{casalib_path( )}"
46
122
  def cubevisjs_url( ):
47
- if cubevisjs_url.library_path is None:
48
- cubevisjs_url.library_path = path.join(path.dirname(path.dirname(path.dirname(__file__))), '__js__', 'cubevisjs.min.js')
49
- if not path.isfile(cubevisjs_url.library_path):
50
- raise RuntimeError( f''''cubevisjs' JavaScript library not found at '{cubevisjs_url.library_path}\'''' )
51
- if not initialize_bokeh.initialized:
52
- initialize_bokeh( )
53
- return f'''file://{cubevisjs_url.library_path}'''
123
+ prefer_local, prefer_network = get_js_loading_selection( )
124
+ if prefer_network:
125
+ return f"https://cdn.jsdelivr.net/gh/casangi/cubevis@{github_js_tag( )}/cubevis/__js__/bokeh-{bokeh_major_minor( )}/cubevisjs.min.js"
126
+ else:
127
+ return f"file://{cubevisjs_path( )}"
@@ -32,8 +32,9 @@
32
32
  from bokeh.models import ResetTool, Tool
33
33
  from bokeh.core.properties import Instance, Nullable
34
34
  from bokeh.models.callbacks import Callback
35
+ from .. import BokehInit
35
36
 
36
- class CBResetTool(ResetTool):
37
+ class CBResetTool(ResetTool,BokehInit):
37
38
  '''Tool that emits press and pressup events to signal start and end of drag'''
38
39
 
39
40
  precallback = Nullable(Instance(Callback), help="""
@@ -36,8 +36,9 @@ from bokeh.core.properties import Instance, Nullable
36
36
  from bokeh.models.callbacks import Callback
37
37
  from os.path import join,dirname
38
38
  from pathlib import Path
39
+ from .. import BokehInit
39
40
 
40
- class DragTool(Drag):
41
+ class DragTool(Drag,BokehInit):
41
42
  '''Tool that emits press and pressup events to signal start and end of drag'''
42
43
 
43
44
  start = Nullable(Instance(Callback), help="""
@@ -28,7 +28,6 @@
28
28
  '''Functions use in the implementation of cubevis's Bokeh extensions.'''
29
29
 
30
30
  from ._svg_icon import svg_icon
31
-
32
31
  ###
33
32
  ### axes_labels has errors on import
34
33
  ###
cubevis/exe/_setting.py CHANGED
@@ -2,3 +2,4 @@ from enum import Enum
2
2
 
3
3
  class Setting(Enum):
4
4
  CLI = "python_cli"
5
+ JPY = "jupyter_cell"
@@ -29,8 +29,8 @@
29
29
  '''End user applications supplied by ``cubevis``.'''
30
30
  import sys
31
31
  from cubevis.utils import copydoc, ImportProtectedModule
32
- from cubevis.bokeh.state import initialize_session
33
- initialize_session()
32
+ #from cubevis.bokeh.state import initialize_session
33
+ #initialize_session()
34
34
 
35
35
  ###
36
36
  ### This import roundabout was introduced when astroviper and casa6 apps were in the same
@@ -42,7 +42,9 @@ sys.modules[__name__].__class__ = ImportProtectedModule( __name__, { 'plotants':
42
42
  'CreateMask': '._createmask',
43
43
  'CreateRegion': '._createregion',
44
44
  'InteractiveClean': '._interactiveclean',
45
+ 'InteractiveCleanNotebook': '._interactivecleannotebook',
45
46
  'iclean': '..casatasks.iclean',
47
+ 'iclean_notebook': '..casatasks.iclean_notebook',
46
48
  'createmask': '..casatasks.createmask',
47
49
  'createregion': '..casatasks.createregion',
48
50
  } )
@@ -32,7 +32,9 @@ of tclean'''
32
32
  from pprint import pprint
33
33
 
34
34
  import sys
35
+ from uuid import uuid4
35
36
  from os.path import exists
37
+ from bokeh.plotting import show
36
38
  from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
37
39
 
38
40
  from cubevis.utils import find_pkg, load_pkg
@@ -84,6 +86,8 @@ class InteractiveClean:
84
86
  cell='12.0arcsec', specmode='cube',
85
87
  interpolation='nearest', ... )( ) )
86
88
  '''
89
+ self._id = uuid4( )
87
90
  context = exe.Context( exe.Mode.SYNC )
88
- exec_task = self._ui( exe.Setting.CLI, context, "interactive-clean" )
89
- return context.execute( exec_task, "interactive-clean" )
91
+ bokeh_ui, exec_task = self._ui( context, self._id )
92
+ show(bokeh_ui)
93
+ return context.execute( exec_task, self._id )
@@ -31,7 +31,9 @@ of tclean'''
31
31
  from pprint import pprint
32
32
 
33
33
  import sys
34
+ from uuid import uuid4
34
35
  from os.path import exists
36
+ from bokeh.plotting import show
35
37
  from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
36
38
 
37
39
  from cubevis.utils import find_pkg, load_pkg
@@ -1846,6 +1848,8 @@ class InteractiveClean:
1846
1848
  cell='12.0arcsec', specmode='cube',
1847
1849
  interpolation='nearest', ... )( ) )
1848
1850
  '''
1851
+ self._id = uuid4( )
1849
1852
  context = exe.Context( exe.Mode.SYNC )
1850
- exec_task = self._ui( exe.Setting.CLI, context, "interactive-clean" )
1851
- return context.execute( exec_task, "interactive-clean" )
1853
+ bokeh_ui, exec_task = self._ui( context, self._id )
1854
+ show(bokeh_ui)
1855
+ return context.execute( exec_task, self._id )