cubevis 1.0.21__tar.gz → 1.0.33__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. {cubevis-1.0.21 → cubevis-1.0.33}/PKG-INFO +1 -1
  2. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__js__/bokeh-3.8/cubevisjs.min.js +5 -5
  3. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/__init__.py +1 -0
  4. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_showable.py +82 -13
  5. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/_data_pipe.py +28 -1
  6. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/_initialize.py +7 -0
  7. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_cube.py +1 -1
  8. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/__init__.py +1 -1
  9. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_jupyter.py +35 -12
  10. {cubevis-1.0.21 → cubevis-1.0.33}/pyproject.toml +1 -1
  11. {cubevis-1.0.21 → cubevis-1.0.33}/LICENSE +0 -0
  12. {cubevis-1.0.21 → cubevis-1.0.33}/README.rst +0 -0
  13. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/LICENSE.rst +0 -0
  14. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/20px/fast-backward.svg +0 -0
  15. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/20px/fast-forward.svg +0 -0
  16. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/20px/step-backward.svg +0 -0
  17. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/20px/step-forward.svg +0 -0
  18. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/add-chan.png +0 -0
  19. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/add-chan.svg +0 -0
  20. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/add-cube.png +0 -0
  21. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/add-cube.svg +0 -0
  22. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/drag.png +0 -0
  23. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/drag.svg +0 -0
  24. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/mask-selected.png +0 -0
  25. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/mask.png +0 -0
  26. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/mask.svg +0 -0
  27. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/new-layer-sm-selected.png +0 -0
  28. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/new-layer-sm-selected.svg +0 -0
  29. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/new-layer-sm.png +0 -0
  30. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/new-layer-sm.svg +0 -0
  31. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/reset.png +0 -0
  32. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/reset.svg +0 -0
  33. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/sub-chan.png +0 -0
  34. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/sub-chan.svg +0 -0
  35. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/sub-cube.png +0 -0
  36. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/sub-cube.svg +0 -0
  37. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/trash.png +0 -0
  38. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/trash.svg +0 -0
  39. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/trash_full.png +0 -0
  40. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/trash_full.svg +0 -0
  41. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/trash_full_raw.png +0 -0
  42. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/zoom-to-fit.png +0 -0
  43. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__icons__/zoom-to-fit.svg +0 -0
  44. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__init__.py +0 -0
  45. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__js__/bokeh-3.6/cubevisjs.min.js +0 -0
  46. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__js__/bokeh-3.7/cubevisjs.min.js +0 -0
  47. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/__js__/casalib.min.js +0 -0
  48. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/annotations/__init__.py +0 -0
  49. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/annotations/_ev_poly_annotation.py +0 -0
  50. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/components/__init__.py +0 -0
  51. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/format/__init__.py +0 -0
  52. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/format/_time_ticks.py +0 -0
  53. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/format/_wcs_ticks.py +0 -0
  54. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/__init__.py +0 -0
  55. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_bokeh_app_context.py +0 -0
  56. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_edit_span.py +0 -0
  57. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_ev_text_input.py +0 -0
  58. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_shared_dict.py +0 -0
  59. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_tip.py +0 -0
  60. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/models/_tip_button.py +0 -0
  61. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/__init__.py +0 -0
  62. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/_image_data_source.py +0 -0
  63. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/_image_pipe.py +0 -0
  64. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/_spectra_data_source.py +0 -0
  65. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/sources/_updatable_data_source.py +0 -0
  66. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/__init__.py +0 -0
  67. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/_current.py +0 -0
  68. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/_javascript.py +0 -0
  69. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/_palette.py +0 -0
  70. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/_session.py +0 -0
  71. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/bokeh-2.4.1.min.js +0 -0
  72. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/bokeh-gl-2.4.1.min.js +0 -0
  73. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/bokeh-tables-2.4.1.min.js +0 -0
  74. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/bokeh-widgets-2.4.1.min.js +0 -0
  75. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/casaguijs-v0.0.4.0-b2.4.min.js +0 -0
  76. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/casaguijs-v0.0.5.0-b2.4.min.js +0 -0
  77. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/casaguijs-v0.0.6.0-b2.4.min.js +0 -0
  78. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/state/js/casalib-v0.0.1.min.js +0 -0
  79. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/tools/__init__.py +0 -0
  80. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/tools/_cbreset_tool.py +0 -0
  81. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/tools/_drag_tool.py +0 -0
  82. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/utils/__init__.py +0 -0
  83. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/utils/_axes_labels.py +0 -0
  84. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/bokeh/utils/_svg_icon.py +0 -0
  85. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/data/__init__.py +0 -0
  86. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/data/casaimage/__init__.py +0 -0
  87. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/exe/__init__.py +0 -0
  88. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/exe/_context.py +0 -0
  89. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/exe/_mode.py +0 -0
  90. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/exe/_setting.py +0 -0
  91. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/exe/_task.py +0 -0
  92. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/_gclean.py +0 -0
  93. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/__init__.py +0 -0
  94. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_createmask.py +0 -0
  95. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_createregion.py +0 -0
  96. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_interactiveclean.mustache +0 -0
  97. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_interactiveclean.py +0 -0
  98. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_interactivecleannotebook.mustache +0 -0
  99. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_interactivecleannotebook.py +0 -0
  100. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_plotants.py +0 -0
  101. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/apps/_plotbandpass.py +0 -0
  102. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casashell/createmask.py +0 -0
  103. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casashell/iclean.py +0 -0
  104. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casatasks/__init__.py +0 -0
  105. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casatasks/createmask.py +0 -0
  106. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casatasks/createregion.py +0 -0
  107. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casatasks/iclean.py +0 -0
  108. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/private/casatasks/iclean_notebook.py +0 -0
  109. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/readme.rst +0 -0
  110. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/remote/__init__.py +0 -0
  111. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/remote/_gclean.py +0 -0
  112. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/remote/_local.py +0 -0
  113. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/remote/_remote_kernel.py +0 -0
  114. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/__init__.py +0 -0
  115. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_app_context.py +0 -0
  116. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_interactive_clean_ui.mustache +0 -0
  117. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_interactive_clean_ui.py +0 -0
  118. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_interactiveclean_wrappers.py +0 -0
  119. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/toolbox/_region_list.py +0 -0
  120. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_ResourceManager.py +0 -0
  121. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_browser.py +0 -0
  122. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_contextmgrchain.py +0 -0
  123. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_conversion.py +0 -0
  124. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_copydoc.py +0 -0
  125. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_docenum.py +0 -0
  126. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_git.py +0 -0
  127. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_import_protected_module.py +0 -0
  128. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_logging.py +0 -0
  129. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_mutual_exclusion.py +0 -0
  130. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_pkgs.py +0 -0
  131. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_regions.py +0 -0
  132. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_static.py +0 -0
  133. {cubevis-1.0.21 → cubevis-1.0.33}/cubevis/utils/_tiles.py +0 -0
  134. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/alma-many-chan/alma-many-chan.py +0 -0
  135. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/basic-websockets-demo/client.html +0 -0
  136. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/basic-websockets-demo/client.py +0 -0
  137. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/basic-websockets-demo/server.py +0 -0
  138. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/createmask-demo/run-createmask.py +0 -0
  139. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/createregion-demo/run-createregion.py +0 -0
  140. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/cubemask-demo/image-slider-spectra-done-stats.py +0 -0
  141. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/cubemask-demo/image-slider-spectra-done.py +0 -0
  142. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/cubemask-demo/image-slider-spectra.py +0 -0
  143. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/cubemask-demo/image-slider.py +0 -0
  144. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/cubemask-demo/image.py +0 -0
  145. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/iclean-demo.ipynb +0 -0
  146. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/m100_interactive.py +0 -0
  147. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/mask0-iclean.py +0 -0
  148. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/run-gclean.py +0 -0
  149. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/run-iclean-obj.py +0 -0
  150. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/run-iclean.py +0 -0
  151. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-demo/vla-sim-jet-iclean.py +0 -0
  152. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-first-look/run-fl-cont.py +0 -0
  153. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-first-look/run-fl-line.py +0 -0
  154. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-outlier/run-iclean.py +0 -0
  155. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-outlier/test_outlier.txt +0 -0
  156. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/iclean-remote/iclean_remote_webserver.py +0 -0
  157. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/large-cube/run-largecube.py +0 -0
  158. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/svg-test.py +0 -0
  159. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/updatable-data-source/direct-plot.py +0 -0
  160. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/updatable-data-source/simple-update.py +0 -0
  161. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/updatable-data-source/updated-plot.py +0 -0
  162. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/uranus-demo/uranus-iclean.py +0 -0
  163. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/websocket-reconnect/client.html +0 -0
  164. {cubevis-1.0.21 → cubevis-1.0.33}/tests/manual/websocket-reconnect/server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cubevis
3
- Version: 1.0.21
3
+ Version: 1.0.33
4
4
  Summary: visualization toolkit and apps for casa
5
5
  License: LGPL
6
6
  Author-email: Darrell Schiebel <darrell@schiebel.us>,Pam Harris <pharris@nrao.edu>
@@ -42,15 +42,15 @@
42
42
  }
43
43
  })
44
44
  ({
45
- "07c9fde72b": function _(e,a,t,o,c){o();const i=e("tslib"),n=e("f8eca7a5dd");c("DataPipe",n.DataPipe);c("activeDataPipes",e("5179d11e71").activeDataPipes);const p=e("2889e0dd45");c("ImagePipe",p.ImagePipe);const s=e("de65005924");c("ImageDataSource",s.ImageDataSource);const r=e("02e3c3e46c");c("SpectraDataSource",r.SpectraDataSource);const d=e("64b16deff9");c("UpdatableDataSource",d.UpdatableDataSource);const S=e("b6ae454f0d");c("WcsTicks",S.WcsTicks);const l=e("cb7d28d6b3");c("DragTool",l.DragTool);const D=e("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=e("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const b=e("9f961622ce");c("TipButton",b.TipButton);const u=e("ca4c845905");c("Tip",u.Tip);const f=e("a6e757a69a");c("Showable",f.Showable);const P=e("467d2716b0");c("BokehAppContext",P.BokehAppContext);const g=e("50a1e32f01");c("SharedDict",g.SharedDict);const h=e("b55081402e");c("EditSpan",h.EditSpan);const B=e("9144bfc7a5");c("EvTextInput",B.EvTextInput);const E=e("74e0abef8a");c("EvPolyAnnotation",E.EvPolyAnnotation);const I=i.__importStar(e("484bb85d20"));t.find=I;(0,e("@bokehjs/base").register_models)({DataPipe:n.DataPipe,ImagePipe:p.ImagePipe,ImageDataSource:s.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:d.UpdatableDataSource,WcsTicks:S.WcsTicks,DragTool:l.DragTool,CBResetTool:D.CBResetTool,Tip:u.Tip,TipButton:b.TipButton,SharedDict:g.SharedDict,Showable:f.Showable,BokehAppContext:P.BokehAppContext,EditSpan:h.EditSpan,EvTextInput:B.EvTextInput,EvPolyAnnotation:E.EvPolyAnnotation})},
46
- "f8eca7a5dd": function _(e,s,t,i,n){var o;i();const a=e("@bokehjs/models/sources/data_source"),c=e("e3901fa9f2"),r=e("@bokehjs/core/util/callbacks"),l=e("5179d11e71");class d extends a.DataSource{constructor(e){super(e),this.send_queue={},this.connection_queue=[],this.pending={},this.incoming_callbacks={},this.session_id=casalib.object_id(this)}checkSessionConflict(){try{if("undefined"==typeof Storage)return console.warn("localStorage not available, skipping session conflict detection"),!0;const e=localStorage.getItem(this.session_storage_key);if(e){const s=JSON.parse(e);if(s.sessionId!==this.session_id&&Date.now()-s.timestamp<12e4){if(this.conflict_check){const e=`CubeVis DataPipe (${this.instance_key}) is already running in another browser window or tab.\n\nPlease close other instances and refresh this page, or\nclose this window to continue using the other instance.`;return alert(e),window.opener||1===window.history.length?window.close():window.location.href="about:blank",!1}console.group(`DataPipe ${this.instance_key} conflict detected in Jupyter context`),console.log("Current session ID:",this.session_id),console.log("Existing session ID:",s.sessionId),console.log("Existing timestamp:",new Date(s.timestamp).toISOString()),console.log("Age of existing session (ms):",Date.now()-s.timestamp),console.log("Address:",this.address),console.log("Instance key:",this.instance_key),console.log("Storage key:",this.session_storage_key),console.log("Existing data:",s),console.log("All localStorage keys:",Object.keys(localStorage).filter((e=>e.startsWith("cubevis_datapipe_")))),console.groupEnd()}}return this.updateSessionHeartbeat(),!0}catch(e){return console.warn("Session conflict detection failed:",e),!0}}updateSessionHeartbeat(){try{"undefined"!=typeof Storage&&localStorage.setItem(this.session_storage_key,JSON.stringify({sessionId:this.session_id,timestamp:Date.now(),instanceKey:this.instance_key}))}catch(e){console.warn("Session heartbeat update failed:",e)}}startHeartbeat(){this.heartbeat_interval=window.setInterval((()=>{this.updateSessionHeartbeat()}),3e4)}stopHeartbeat(){this.heartbeat_interval&&(clearInterval(this.heartbeat_interval),this.heartbeat_interval=void 0)}cleanupSession(){try{if("undefined"!=typeof Storage){const e=localStorage.getItem(this.session_storage_key);if(e){JSON.parse(e).sessionId===this.session_id&&localStorage.removeItem(this.session_storage_key)}}}catch(e){console.warn("Session cleanup failed:",e)}this.stopHeartbeat()}handleSessionConflictMessage(e){console.error("Session conflict detected by server:",e);let s="Session conflict detected by server.";"session_conflict"===e.type?s=e.error||s:"session_corruption"===e.type&&(s=`Session corruption detected.\nExpected: ${e.expected}\nReceived: ${e.received}`),alert(s+"\n\nThis window will be closed to prevent data corruption."),this.cleanupSession();const t=new CustomEvent("cubevis_session_conflict",{detail:{message:e,sessionId:this.session_id}});window.dispatchEvent(t),setTimeout((()=>{window.opener||1===window.history.length?window.close():window.location.href="about:blank"}),2e3)}generateInstanceKey(){const e=`${this.address[0]}_${this.address[1]}`;return`${this.instance_id}_${e}`}initialize(){if(super.initialize(),l.activeDataPipes.register(this),this.instance_key=this.generateInstanceKey(),this.session_storage_key=`cubevis_datapipe_${this.instance_key}`,!this.checkSessionConflict())return;let e=`ws://${this.address[0]}:${this.address[1]}`;console.log("datapipe url:",e);var s=void 0;document.shutdown_in_progress_=!1;var t=()=>{void 0!==this.websocket&&this.websocket.close(),this.websocket=new WebSocket(e),this.websocket.binaryType="arraybuffer",this.websocket.addEventListener("error",(e=>{console.log("error encountered:",e)})),this.websocket.onmessage=e=>{if("string"==typeof e.data||e.data instanceof String){let s=(0,c.deserialize)(e.data);if("id"in s&&"direction"in s&&"message"in s){let{id:e,message:t,direction:i}=s;if("error"===i&&("session_conflict"===e||e===this.session_id)&&t&&("session_conflict"===t.type||"session_corruption"===t.type||"close_duplicate"===t.action))return void this.handleSessionConflictMessage(t);if(void 0===t&&console.log("Error, event failure",s),"j2p"==i)if(e in this.pending){let{cb:i}=this.pending[e];if(delete this.pending[e],e in this.send_queue&&this.send_queue[e].length>0){let{cb:s,msg:t}=this.send_queue[e].shift();this.pending[e]={cb:s},this.websocket.send((0,c.serialize)(t))}void 0===t?console.log("DROPPING ERROR FOR NOW (maybe need error callbacks)",s):i(t)}else console.log("message received but could not find id");else if(e in this.incoming_callbacks){let s=this.incoming_callbacks[e](t);this.websocket.send((0,c.serialize)({id:e,direction:i,message:s,session:this.session_id}))}}else console.log(`datapipe received message without one of 'id', 'message' or 'direction': ${s}`)}else console.log("datapipe received binary data",e.data.byteLength,"bytes")},this.websocket.onopen=()=>{for(s?0==s.connected&&console.log(`connection reestablished at ${new Date}`):(this.websocket.send((0,c.serialize)({id:"initialize",direction:"j2p",session:this.session_id})),this.startHeartbeat()),s=new casalib.ReconnectState;this.connection_queue.length>0;){let e=this.connection_queue.shift();this.send.apply(e[0],e[1])}},this.websocket.onclose=()=>{if(s&&1==s.connected&&(console.log(`connection lost at ${new Date}`),s.connected=!1,!document.shutdown_in_progress_)){console.log(`connection lost at ${new Date}`);var e=s;function i(n){0==s.connected&&(console.log(`${n+1}\treconnection attempt ${new Date}`),t(),e.backoff(),e.retries>0?setTimeout(i,e.timeout,n+1):0==s.connected&&console.log(`aborting reconnection after ${n} attempts ${new Date}`))}i(0)}}};window.addEventListener("beforeunload",(()=>{this.cleanupSession()})),document.addEventListener("visibilitychange",(()=>{"hidden"===document.visibilityState?this.stopHeartbeat():"visible"===document.visibilityState&&(this.updateSessionHeartbeat(),this.startHeartbeat())})),t();(()=>{null!=this.init_script&&(0,r.execute)(this.init_script,this)})()}destroy(){l.activeDataPipes.unregister(this),super.destroy()}register(e,s){this.incoming_callbacks[e]=s}send(e,s,t,i=!1){let n={id:e,message:s,direction:"j2p",session:this.session_id};if(!this.websocket||e in this.pending)if(e in this.send_queue)if("boolean"==typeof i&&i&&this.send_queue[e].length>0)this.send_queue[e][0].msg=n,this.send_queue[e][0].cb=t;else if("function"==typeof i&&this.send_queue[e].length>0){let o=!1;for(const a of this.send_queue[e])i(a.msg.message)&&(a.msg=n,a.cb=t,o=!0);o||this.send_queue[e].push({cb:t,msg:n})}else this.send_queue[e].push({cb:t,msg:n});else this.send_queue[e]=[{cb:t,msg:n}];else if(this.websocket.readyState===WebSocket.CONNECTING)this.connection_queue.push([this,[e,s,t]]);else if(e in this.send_queue&&this.send_queue[e].length>0){this.send_queue[e].push({cb:t,msg:n});{let{cb:r,msg:l}=this.send_queue[e].shift();if(this.pending[e]={cb:r},this.websocket.readyState===WebSocket.OPEN)this.websocket.send((0,c.serialize)(l));else{let d=20,h=this;function u(){h.websocket.readyState===WebSocket.OPEN?h.websocket.send((0,c.serialize)(l)):(d-=1,d>0&&setTimeout(u,3e3))}setTimeout(u,3e3)}}}else if(this.websocket.readyState===WebSocket.OPEN)this.pending[e]={cb:t},this.websocket.send((0,c.serialize)(n));else{let g=20,b=this;function _(){b.websocket.readyState===WebSocket.OPEN?(b.pending[e]={cb:t},b.websocket.send((0,c.serialize)(n))):(g-=1,g>0&&setTimeout(_,3e3))}setTimeout(_,3e3)}}}t.DataPipe=d,o=d,d.__name__="DataPipe",d.__module__="cubevis.bokeh.sources._data_pipe",o.define((({Any:e,Tuple:s,String:t,Number:i,Bool:n})=>({init_script:[e,null],address:[s(t,i)],instance_id:[t],conflict_check:[n,!0]})))},
45
+ "07c9fde72b": function _(e,t,a,o,c){o();const i=e("tslib"),n=e("2295368b65");c("DataPipe",n.DataPipe);c("activeDataPipes",e("5179d11e71").activeDataPipes);const p=e("2889e0dd45");c("ImagePipe",p.ImagePipe);const s=e("de65005924");c("ImageDataSource",s.ImageDataSource);const r=e("02e3c3e46c");c("SpectraDataSource",r.SpectraDataSource);const S=e("64b16deff9");c("UpdatableDataSource",S.UpdatableDataSource);const d=e("b6ae454f0d");c("WcsTicks",d.WcsTicks);const l=e("cb7d28d6b3");c("DragTool",l.DragTool);const D=e("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=e("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const b=e("9f961622ce");c("TipButton",b.TipButton);const u=e("ca4c845905");c("Tip",u.Tip);const P=e("a6e757a69a");c("Showable",P.Showable);const f=e("467d2716b0");c("BokehAppContext",f.BokehAppContext);const g=e("50a1e32f01");c("SharedDict",g.SharedDict);const h=e("b55081402e");c("EditSpan",h.EditSpan);const B=e("9144bfc7a5");c("EvTextInput",B.EvTextInput);const E=e("74e0abef8a");c("EvPolyAnnotation",E.EvPolyAnnotation);const I=i.__importStar(e("484bb85d20"));a.find=I;(0,e("@bokehjs/base").register_models)({DataPipe:n.DataPipe,ImagePipe:p.ImagePipe,ImageDataSource:s.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:S.UpdatableDataSource,WcsTicks:d.WcsTicks,DragTool:l.DragTool,CBResetTool:D.CBResetTool,Tip:u.Tip,TipButton:b.TipButton,SharedDict:g.SharedDict,Showable:P.Showable,BokehAppContext:f.BokehAppContext,EditSpan:h.EditSpan,EvTextInput:B.EvTextInput,EvPolyAnnotation:E.EvPolyAnnotation})},
46
+ "2295368b65": function _(e,s,t,i,n){var o;i();const a=e("@bokehjs/models/sources/data_source"),c=e("e3901fa9f2"),r=e("@bokehjs/core/util/callbacks"),l=e("5179d11e71");class d extends a.DataSource{constructor(e){super(e),this.send_queue={},this.connection_queue=[],this.pending={},this.incoming_callbacks={},this.session_id=casalib.object_id(this)}isColab(){return void 0!==window.google&&void 0!==window.google.colab&&void 0!==window.google.colab.kernel}async getWebSocketUrl(){const[e,s]=this.address;if(this.isColab())try{const e=window.google,t=(await e.colab.kernel.proxyPort(s,{cache:!0})).replace(/^https:/,"wss:");return console.log(`Colab proxy URL for port ${s}: ${t}`),t}catch(t){return console.error("Error getting Colab proxy URL:",t),`ws://${e}:${s}`}return`ws://${e}:${s}`}checkSessionConflict(){try{if("undefined"==typeof Storage)return console.warn("localStorage not available, skipping session conflict detection"),!0;const e=localStorage.getItem(this.session_storage_key);if(e){const s=JSON.parse(e);if(s.sessionId!==this.session_id&&Date.now()-s.timestamp<12e4){if(this.conflict_check){const e=`CubeVis DataPipe (${this.instance_key}) is already running in another browser window or tab.\n\nPlease close other instances and refresh this page, or\nclose this window to continue using the other instance.`;return alert(e),window.opener||1===window.history.length?window.close():window.location.href="about:blank",!1}console.group(`DataPipe ${this.instance_key} conflict detected in Jupyter context`),console.log("Current session ID:",this.session_id),console.log("Existing session ID:",s.sessionId),console.log("Existing timestamp:",new Date(s.timestamp).toISOString()),console.log("Age of existing session (ms):",Date.now()-s.timestamp),console.log("Address:",this.address),console.log("Instance key:",this.instance_key),console.log("Storage key:",this.session_storage_key),console.log("Existing data:",s),console.log("All localStorage keys:",Object.keys(localStorage).filter((e=>e.startsWith("cubevis_datapipe_")))),console.groupEnd()}}return this.updateSessionHeartbeat(),!0}catch(e){return console.warn("Session conflict detection failed:",e),!0}}updateSessionHeartbeat(){try{"undefined"!=typeof Storage&&localStorage.setItem(this.session_storage_key,JSON.stringify({sessionId:this.session_id,timestamp:Date.now(),instanceKey:this.instance_key}))}catch(e){console.warn("Session heartbeat update failed:",e)}}startHeartbeat(){this.heartbeat_interval=window.setInterval((()=>{this.updateSessionHeartbeat()}),3e4)}stopHeartbeat(){this.heartbeat_interval&&(clearInterval(this.heartbeat_interval),this.heartbeat_interval=void 0)}cleanupSession(){try{if("undefined"!=typeof Storage){const e=localStorage.getItem(this.session_storage_key);if(e){JSON.parse(e).sessionId===this.session_id&&localStorage.removeItem(this.session_storage_key)}}}catch(e){console.warn("Session cleanup failed:",e)}this.stopHeartbeat()}handleSessionConflictMessage(e){console.error("Session conflict detected by server:",e);let s="Session conflict detected by server.";"session_conflict"===e.type?s=e.error||s:"session_corruption"===e.type&&(s=`Session corruption detected.\nExpected: ${e.expected}\nReceived: ${e.received}`),alert(s+"\n\nThis window will be closed to prevent data corruption."),this.cleanupSession();const t=new CustomEvent("cubevis_session_conflict",{detail:{message:e,sessionId:this.session_id}});window.dispatchEvent(t),setTimeout((()=>{window.opener||1===window.history.length?window.close():window.location.href="about:blank"}),2e3)}generateInstanceKey(){const e=`${this.address[0]}_${this.address[1]}`;return`${this.instance_id}_${e}`}async initializeWebSocket(){const e=await this.getWebSocketUrl();console.log("datapipe url:",e);var s=void 0;document.shutdown_in_progress_=!1;var t=()=>{void 0!==this.websocket&&this.websocket.close(),this.websocket=new WebSocket(e),this.websocket.binaryType="arraybuffer",this.websocket.addEventListener("error",(e=>{console.log("error encountered:",e)})),this.websocket.onmessage=e=>{if("string"==typeof e.data||e.data instanceof String){let s=(0,c.deserialize)(e.data);if("id"in s&&"direction"in s&&"message"in s){let{id:e,message:t,direction:i}=s;if("error"===i&&("session_conflict"===e||e===this.session_id)&&t&&("session_conflict"===t.type||"session_corruption"===t.type||"close_duplicate"===t.action))return void this.handleSessionConflictMessage(t);if(void 0===t&&console.log("Error, event failure",s),"j2p"==i)if(e in this.pending){let{cb:i}=this.pending[e];if(delete this.pending[e],e in this.send_queue&&this.send_queue[e].length>0){let{cb:s,msg:t}=this.send_queue[e].shift();this.pending[e]={cb:s},this.websocket.send((0,c.serialize)(t))}void 0===t?console.log("DROPPING ERROR FOR NOW (maybe need error callbacks)",s):i(t)}else console.log("message received but could not find id");else if(e in this.incoming_callbacks){let s=this.incoming_callbacks[e](t);this.websocket.send((0,c.serialize)({id:e,direction:i,message:s,session:this.session_id}))}}else console.log(`datapipe received message without one of 'id', 'message' or 'direction': ${s}`)}else console.log("datapipe received binary data",e.data.byteLength,"bytes")},this.websocket.onopen=()=>{for(s?0==s.connected&&console.log(`connection reestablished at ${new Date}`):(this.websocket.send((0,c.serialize)({id:"initialize",direction:"j2p",session:this.session_id})),this.startHeartbeat()),s=new casalib.ReconnectState;this.connection_queue.length>0;){let e=this.connection_queue.shift();this.send.apply(e[0],e[1])}},this.websocket.onclose=()=>{if(s&&1==s.connected&&(console.log(`connection lost at ${new Date}`),s.connected=!1,!document.shutdown_in_progress_)){console.log(`connection lost at ${new Date}`);var e=s;function i(n){0==s.connected&&(console.log(`${n+1}\treconnection attempt ${new Date}`),t(),e.backoff(),e.retries>0?setTimeout(i,e.timeout,n+1):0==s.connected&&console.log(`aborting reconnection after ${n} attempts ${new Date}`))}i(0)}}};window.addEventListener("beforeunload",(()=>{this.cleanupSession()})),document.addEventListener("visibilitychange",(()=>{"hidden"===document.visibilityState?this.stopHeartbeat():"visible"===document.visibilityState&&(this.updateSessionHeartbeat(),this.startHeartbeat())})),t()}initialize(){if(super.initialize(),l.activeDataPipes.register(this),this.instance_key=this.generateInstanceKey(),this.session_storage_key=`cubevis_datapipe_${this.instance_key}`,!this.checkSessionConflict())return;this.initializeWebSocket();(()=>{null!=this.init_script&&(0,r.execute)(this.init_script,this)})()}destroy(){l.activeDataPipes.unregister(this),super.destroy()}register(e,s){this.incoming_callbacks[e]=s}send(e,s,t,i=!1){let n={id:e,message:s,direction:"j2p",session:this.session_id};if(!this.websocket||e in this.pending)if(e in this.send_queue)if("boolean"==typeof i&&i&&this.send_queue[e].length>0)this.send_queue[e][0].msg=n,this.send_queue[e][0].cb=t;else if("function"==typeof i&&this.send_queue[e].length>0){let o=!1;for(const a of this.send_queue[e])i(a.msg.message)&&(a.msg=n,a.cb=t,o=!0);o||this.send_queue[e].push({cb:t,msg:n})}else this.send_queue[e].push({cb:t,msg:n});else this.send_queue[e]=[{cb:t,msg:n}];else if(this.websocket.readyState===WebSocket.CONNECTING)this.connection_queue.push([this,[e,s,t]]);else if(e in this.send_queue&&this.send_queue[e].length>0){this.send_queue[e].push({cb:t,msg:n});{let{cb:r,msg:l}=this.send_queue[e].shift();if(this.pending[e]={cb:r},this.websocket.readyState===WebSocket.OPEN)this.websocket.send((0,c.serialize)(l));else{let d=20,h=this;function u(){h.websocket.readyState===WebSocket.OPEN?h.websocket.send((0,c.serialize)(l)):(d-=1,d>0&&setTimeout(u,3e3))}setTimeout(u,3e3)}}}else if(this.websocket.readyState===WebSocket.OPEN)this.pending[e]={cb:t},this.websocket.send((0,c.serialize)(n));else{let g=20,b=this;function p(){b.websocket.readyState===WebSocket.OPEN?(b.pending[e]={cb:t},b.websocket.send((0,c.serialize)(n))):(g-=1,g>0&&setTimeout(p,3e3))}setTimeout(p,3e3)}}}t.DataPipe=d,o=d,d.__name__="DataPipe",d.__module__="cubevis.bokeh.sources._data_pipe",o.define((({Any:e,Tuple:s,String:t,Number:i,Bool:n})=>({init_script:[e,null],address:[s(t,i)],instance_id:[t],conflict_check:[n,!0]})))},
47
47
  "e3901fa9f2": function _(e,r,s,i,o){i();const l=e("@bokehjs/base"),a=e("@bokehjs/core/resolvers"),t=e("@bokehjs/core/serialization/deserializer"),n=e("@bokehjs/core/serialization/serializer"),{deserialize:c}=new class{constructor(){this.resolver=new a.ModelResolver(l.default_resolver),this.deserializer=new t.Deserializer(this.resolver),this.deserialize=e=>{try{return this.deserializer.decode(JSON.parse(e))}catch(r){return console.group("deserialize error"),console.log(e),console.log(r),console.groupEnd(),{}}}}};s.deserialize=c;const{serialize:z}=new class{constructor(){this.serializer=new n.Serializer,this.serialize=e=>JSON.stringify(this.serializer.encode(e))}};s.serialize=z},
48
48
  "5179d11e71": function _(a,e,n,c,t){c();const i=a("30b45c52a1");n.activeDataPipes=new i.ModelManager},
49
49
  "30b45c52a1": function _(e,n,s,t,i){t();class r{constructor(){this.instances=new Map}register(e){this.instances.set(e.id,e),console.log(`registered instance ${e.id}`)}unregister(e){this.instances.delete(e.id),console.log(`unregistered instance ${e.id}`)}getInstances(){return Array.from(this.instances.values())}getInstance(e){return this.instances.get(e)}}s.ModelManager=r,r.__name__="ModelManager"},
50
- "2889e0dd45": function _(i,e,s,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("f8eca7a5dd");class r extends d.DataPipe{constructor(i){super(i),this.position={},this._wcs=null}initialize(){super.initialize(),this.fits_header_json&&(this._wcs=new casalib.coordtxl.WCSTransform(new casalib.coordtxl.MapKeywordProvider(JSON.parse(this.fits_header_json))))}channel(i,e,s){this.position[s]={index:i};let t={action:"channel",index:i,id:s};super.send(this.dataid,t,(i=>{null!=this._histogram_source&&"hist"in i&&"top"in i.hist&&"bottom"in i.hist&&"left"in i.hist&&"right"in i.hist&&(this._histogram_source.data=i.hist),e(i)}))}spectrum(i,e,s,t=!1){let n={action:"spectrum",index:i,id:s};super.send(this.dataid,n,e,t)}adjust_colormap(i,e,s,t,n=!1){const a={action:"adjust-colormap",bounds:i,transfer:e,id:t};super.send(this.dataid,a,s,n)}refresh(i,e,s=[0,0]){let{index:t}=e in this.position?this.position[e]:{index:s};if(2===t.length){let s={action:"channel",index:t,id:e};super.send(this.dataid,s,i)}else if(3===t.length){let s={action:"spectrum",index:t,id:e};super.send(this.dataid,s,i)}}wcs(){return this._wcs}}s.ImagePipe=r,a=r,r.__name__="ImagePipe",r.__module__="cubevis.bokeh.sources._image_pipe",a.define((({Number:i,Nullable:e,String:s,Tuple:t,Ref:n})=>({dataid:[s],shape:[t(i,i,i,i)],fits_header_json:[e(s),null],_histogram_source:[e(n(o.ColumnDataSource)),null]})))},
50
+ "2889e0dd45": function _(i,s,e,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("2295368b65");class r extends d.DataPipe{constructor(i){super(i),this.position={},this._wcs=null}initialize(){super.initialize(),this.fits_header_json&&(this._wcs=new casalib.coordtxl.WCSTransform(new casalib.coordtxl.MapKeywordProvider(JSON.parse(this.fits_header_json))))}channel(i,s,e){this.position[e]={index:i};let t={action:"channel",index:i,id:e};super.send(this.dataid,t,(i=>{null!=this._histogram_source&&"hist"in i&&"top"in i.hist&&"bottom"in i.hist&&"left"in i.hist&&"right"in i.hist&&(this._histogram_source.data=i.hist),s(i)}))}spectrum(i,s,e,t=!1){let n={action:"spectrum",index:i,id:e};super.send(this.dataid,n,s,t)}adjust_colormap(i,s,e,t,n=!1){const a={action:"adjust-colormap",bounds:i,transfer:s,id:t};super.send(this.dataid,a,e,n)}refresh(i,s,e=[0,0]){let{index:t}=s in this.position?this.position[s]:{index:e};if(2===t.length){let e={action:"channel",index:t,id:s};super.send(this.dataid,e,i)}else if(3===t.length){let e={action:"spectrum",index:t,id:s};super.send(this.dataid,e,i)}}wcs(){return this._wcs}}e.ImagePipe=r,a=r,r.__name__="ImagePipe",r.__module__="cubevis.bokeh.sources._image_pipe",a.define((({Number:i,Nullable:s,String:e,Tuple:t,Ref:n})=>({dataid:[e],shape:[t(i,i,i,i)],fits_header_json:[s(e),null],_histogram_source:[s(n(o.ColumnDataSource)),null]})))},
51
51
  "de65005924": function _(s,a,t,c,i){var o;c();const e=s("@bokehjs/models/sources/column_data_source"),n=s("@bokehjs/core/util/string"),u=s("2889e0dd45"),h=s("@bokehjs/core/util/callbacks");class r extends e.ColumnDataSource{constructor(s){super(s),this.imid=(0,n.uuid4)()}_mask_contour(s){const a=casalib.d3.contours().size(this.image_source.shape.slice(0,2)).thresholds([1])(s[0])[0].coordinates.map((s=>s.map((s=>s.reduce(((s,a)=>(s[0].push(a[0]),s[1].push(a[1]),s)),[[],[]])))));return{xs:[a.map((s=>s.map((s=>s[0]))))],ys:[a.map((s=>s.map((s=>s[1]))))]}}initialize(){if(super.initialize(),null!=this._mask_contour_source&&"msk"in this.data&&this.data.msk.length>0&&this.data.msk[0].length>0){const s=this.data.msk;this._mask_contour_source.data=this._mask_contour(s)}void 0===this.last_chan&&(this.last_chan=[this.cur_chan[0].valueOf(),this.cur_chan[1].valueOf()]);(()=>{null!=this.init_script&&(0,h.execute)(this.init_script,this)})()}channel(s,a=0,t){this.image_source.channel([a,s],(c=>{void 0!==c&&void 0!==c.chan||console.log("ImageDataSource ERROR ENCOUNTERED <1>",c),this.last_chan=[this.cur_chan[0].valueOf(),this.cur_chan[1].valueOf()],this.cur_chan=[a,s],null!=this._mask_contour_source&&"chan"in c&&"msk"in c.chan&&(c.msk_contour=this._mask_contour(c.chan.msk),this._mask_contour_source.data=c.msk_contour),t&&t(c),this.data=c.chan}),this.imid)}adjust_colormap(s,a,t){this.image_source.adjust_colormap(s,a,t,this.imid,!0)}signal_change(){this.change.emit()}refresh(s){this.image_source.refresh((a=>{void 0!==a&&void 0!==a.chan||console.log("ImageDataSource ERROR ENCOUNTERED <2>",a),null!=this._mask_contour_source&&"chan"in a&&"msk"in a.chan&&(a.msk_contour=this._mask_contour(a.chan.msk),this._mask_contour_source.data=a.msk_contour),s&&s(a),this.data=a.chan}),this.imid,[0,0])}wcs(){return this.image_source.wcs()}}t.ImageDataSource=r,o=r,r.__name__="ImageDataSource",r.__module__="cubevis.bokeh.sources._image_data_source",o.define((({Tuple:s,Number:a,Ref:t,Nullable:c,Any:i})=>({init_script:[i,null],image_source:[t(u.ImagePipe)],_mask_contour_source:[c(t(e.ColumnDataSource)),null],num_chans:[s(a,a)],cur_chan:[s(a,a)]})))},
52
52
  "02e3c3e46c": function _(e,s,i,t,r){var a;t();const c=e("@bokehjs/models/sources/column_data_source"),u=e("@bokehjs/core/util/string"),o=e("2889e0dd45");class _ extends c.ColumnDataSource{constructor(e){super(e),this.imid=(0,u.uuid4)()}initialize(){super.initialize()}spectra(e,s,i=0,t=!1){this.image_source.spectrum([e,s,i],(e=>this.data=e.spectrum),this.imid,t)}refresh(){this.image_source.refresh((e=>this.data=e.spectrum),this.imid,[0,0,0])}}i.SpectraDataSource=_,a=_,_.__name__="SpectraDataSource",_.__module__="cubevis.bokeh.sources._spectra_data_source",a.define((({Ref:e})=>({image_source:[e(o.ImagePipe)]})))},
53
- "64b16deff9": function _(e,s,i,a,t){var n;a();const u=e("@bokehjs/models/sources/column_data_source"),l=e("f8eca7a5dd"),o=e("@bokehjs/core/util/callbacks");class c extends u.ColumnDataSource{constructor(e){super(e)}send(e,s){this.pipe.send(this.session_id.valueOf(),{action:"callback",message:e},(e=>{s("result"in e?e.result:{error:`expected to find a "result" in "${e}"`,msg:e})}))}initialize(){super.initialize();(()=>{null!=this.js_init&&(0,o.execute)(this.js_init,this)})()}}i.UpdatableDataSource=c,n=c,c.__name__="UpdatableDataSource",c.__module__="cubevis.bokeh.sources._updatable_data_source",n.define((({Ref:e,Any:s,String:i})=>({js_init:[s,null],js_update:[s,null],pipe:[e(l.DataPipe)],session_id:[i]})))},
53
+ "64b16deff9": function _(e,s,i,t,a){var n;t();const u=e("@bokehjs/models/sources/column_data_source"),l=e("2295368b65"),o=e("@bokehjs/core/util/callbacks");class c extends u.ColumnDataSource{constructor(e){super(e)}send(e,s){this.pipe.send(this.session_id.valueOf(),{action:"callback",message:e},(e=>{s("result"in e?e.result:{error:`expected to find a "result" in "${e}"`,msg:e})}))}initialize(){super.initialize();(()=>{null!=this.js_init&&(0,o.execute)(this.js_init,this)})()}}i.UpdatableDataSource=c,n=c,c.__name__="UpdatableDataSource",c.__module__="cubevis.bokeh.sources._updatable_data_source",n.define((({Ref:e,Any:s,String:i})=>({js_init:[s,null],js_update:[s,null],pipe:[e(l.DataPipe)],session_id:[i]})))},
54
54
  "b6ae454f0d": function _(s,i,o,t,e){var r;t();const a=s("@bokehjs/models/formatters/tick_formatter"),c=s("de65005924");class l extends a.TickFormatter{constructor(s){super(s),this._axis=null,this._coord="world"}initialize(){super.initialize(),"x"==this.axis||"X"==this.axis||"y"==this.axis||"Y"==this.axis?this._axis="x"==this.axis||"X"==this.axis?"x":"y":console.log("ERROR: WcsTicks formatter created with invalid axis:",this.axis)}doFormat(s){const i=[];if(this._axis&&this.image_source.wcs()&&"world"==this._coord)for(let o=0,t=s.length;o<t;o++)if("x"==this._axis){const t=new casalib.coordtxl.Point2D(Number(s[o]),0);this.image_source.wcs().imageToWorldCoords(t,!1),i.push(new casalib.coordtxl.WorldCoords(t.getX(),t.getY()).format(2e3)[0])}else{const t=new casalib.coordtxl.Point2D(0,Number(s[o]));this.image_source.wcs().imageToWorldCoords(t,!1),i.push(new casalib.coordtxl.WorldCoords(t.getX(),t.getY()).format(2e3)[1])}else for(let o=0,t=s.length;o<t;o++)i.push(""+s[o]);return i}coordinates(s){return s!=this._coord&&("world"!=s&&"pixel"!=s||(this._coord=s)),this._coord}}o.WcsTicks=l,r=l,l.__name__="WcsTicks",l.__module__="cubevis.bokeh.format._wcs_ticks",r.define((({Ref:s,String:i})=>({axis:[i],image_source:[s(c.ImageDataSource)]})))},
55
55
  "cb7d28d6b3": function _(i,e,t,o,s){var d;o();const l=i("@bokehjs/models/tools/gestures/gesture_tool"),r=i("8fc7a9e935"),_=i("484bb85d20"),m=i("@bokehjs/core/util/callbacks");class a extends l.GestureToolView{_pan_start(i){var e;null===(e=this.model.document)||void 0===e||e.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,i.sx),o=(0,_.py_from_sy)(this.plot_view,i.sy),s=(0,_.dx_from_px)(this.plot_view,t),d=(0,_.dy_from_py)(this.plot_view,o),{start:l}=this.model;l?(0,m.execute)(l,this.model,{sx:t,sy:o,x:s,y:d,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.DragStart(t,o,s,d,i.dx,-i.dy,i.modifiers))}_pan(i){var e;null===(e=this.model.document)||void 0===e||e.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,i.sx),o=(0,_.py_from_sy)(this.plot_view,i.sy),s=(0,_.dx_from_px)(this.plot_view,t),d=(0,_.dy_from_py)(this.plot_view,o),{move:l}=this.model;l?(0,m.execute)(l,this.model,{sx:t,sy:o,x:s,y:d,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.Drag(t,o,s,d,i.dx,-i.dy,i.modifiers))}_pan_end(i){const e=(0,_.px_from_sx)(this.plot_view,i.sx),t=(0,_.py_from_sy)(this.plot_view,i.sy),o=(0,_.dx_from_px)(this.plot_view,e),s=(0,_.dy_from_py)(this.plot_view,t),{end:d}=this.model;d?(0,m.execute)(d,this.model,{sx:e,sy:t,x:o,y:s,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.DragEnd(e,t,o,s,i.dx,-i.dy,i.modifiers))}}t.DragToolView=a,a.__name__="DragToolView";class n extends l.GestureTool{constructor(i){super(i),this.tool_name="Drag",this.event_type="pan",this.default_order=10}}t.DragTool=n,d=n,n.__name__="DragTool",n.__module__="cubevis.bokeh.tools._drag_tool",d.prototype.default_view=a,d.define((({Any:i,Nullable:e})=>({start:[e(i),null],move:[e(i),null],end:[e(i),null]})))},
56
56
  "8fc7a9e935": function _(e,t,a,s,_){s();const n=e("@bokehjs/core/bokeh_events");class r extends n.Pan{}a.Drag=r,r.__name__="Drag";class l extends n.PanStart{constructor(e,t,a,s,_,n,r){super(e,t,a,s,r),this.delta_x=_,this.delta_y=n}get event_values(){const{delta_x:e,delta_y:t}=this;return{...super.event_values,delta_x:e,delta_y:t}}}a.DragStart=l,l.__name__="DragStart";class d extends n.PanEnd{constructor(e,t,a,s,_,n,r){super(e,t,a,s,r),this.delta_x=_,this.delta_y=n}get event_values(){const{delta_x:e,delta_y:t}=this;return{...super.event_values,delta_x:e,delta_y:t}}}a.DragEnd=d,d.__name__="DragEnd"},
@@ -64,4 +64,4 @@
64
64
  "b55081402e": function _(e,n,t,_,s){var a;_();const o=e("@bokehjs/models/annotations/span"),p=e("@bokehjs/core/bokeh_events");class r extends o.SpanView{on_pan_start(e){const n=super.on_pan_start(e);return this.model.trigger_event(new p.LODStart),n}on_pan(e){super.on_pan(e)}on_pan_end(e){super.on_pan_end(e),this.model.trigger_event(new p.LODEnd)}}t.EditSpanView=r,r.__name__="EditSpanView";class d extends o.Span{constructor(e){super(e)}}t.EditSpan=d,a=d,d.__name__="EditSpan",d.__module__="cubevis.bokeh.models._edit_span",a.prototype.default_view=r},
65
65
  "9144bfc7a5": function _(e,t,s,n,r){var i;n();const l=e("@bokehjs/models/widgets/text_input"),o=e("@bokehjs/core/dom"),u=e("@bokehjs/core/bokeh_events");class _ extends l.TextInputView{stylesheets(){return[...super.stylesheets(),new o.InlineStyleSheet(".bk-input-prefix { padding: 0 var(--padding-vertical); }")]}connect_signals(){super.connect_signals(),this.el.addEventListener("mouseenter",(e=>{this.model.trigger_event(new u.MouseEnter(e.screenX,e.screenY,e.x,e.y,{shift:e.shiftKey,ctrl:e.ctrlKey,alt:e.altKey}))})),this.el.addEventListener("mouseleave",(e=>{this.model.trigger_event(new u.MouseLeave(e.screenX,e.screenY,e.x,e.y,{shift:e.shiftKey,ctrl:e.ctrlKey,alt:e.altKey}))}))}render(){super.render()}}s.EvTextInputView=_,_.__name__="EvTextInputView";class c extends l.TextInput{constructor(e){super(e)}}s.EvTextInput=c,i=c,c.__name__="EvTextInput",c.__module__="cubevis.bokeh.models._ev_text_input",i.prototype.default_view=_},
66
66
  "74e0abef8a": function _(e,t,n,s,o){var i;s();const r=e("@bokehjs/models/annotations/poly_annotation"),a=e("@bokehjs/core/bokeh_events");class _ extends r.PolyAnnotationView{on_enter(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.MouseEnter(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt}),o=super.on_enter(e);return this.model.trigger_event(s),o}on_leave(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.MouseLeave(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt});super.on_leave(e),this.model.trigger_event(s)}on_pan_start(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.PanStart(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt}),o=super.on_pan_start(e);return this.model.trigger_event(s),o}on_pan_end(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.PanEnd(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt});super.on_pan_end(e),this.model.trigger_event(s)}on_pan(e){super.on_pan(e);const t=new a.RangesUpdate(e.sx,e.sx+e.dx,e.sy,e.sy+e.dy);this.model.trigger_event(t)}}n.EvPolyAnnotationView=_,_.__name__="EvPolyAnnotationView";class l extends r.PolyAnnotation{constructor(e){super(e)}}n.EvPolyAnnotation=l,i=l,l.__name__="EvPolyAnnotation",l.__module__="cubevis.bokeh.annotations._ev_poly_annotation",i.prototype.default_view=_},
67
- }, "07c9fde72b", {"index":"07c9fde72b","src/bokeh/sources/data_pipe":"f8eca7a5dd","src/bokeh/util/conversions":"e3901fa9f2","src/bokeh/sources/active_data_pipes":"5179d11e71","src/bokeh/util/model_manager":"30b45c52a1","src/bokeh/sources/image_pipe":"2889e0dd45","src/bokeh/sources/image_data_source":"de65005924","src/bokeh/sources/spectra_data_source":"02e3c3e46c","src/bokeh/sources/updatable_data_source":"64b16deff9","src/bokeh/format/wcs_ticks":"b6ae454f0d","src/bokeh/tools/drag_tool":"cb7d28d6b3","src/bokeh/events":"8fc7a9e935","src/bokeh/util/find":"484bb85d20","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"a6e757a69a","src/bokeh/models/bokeh_app_context":"467d2716b0","src/bokeh/models/shared_dict":"50a1e32f01","src/bokeh/models/edit_span":"b55081402e","src/bokeh/models/ev_text_input":"9144bfc7a5","src/bokeh/annotations/ev_poly_annotation":"74e0abef8a"}, {});});
67
+ }, "07c9fde72b", {"index":"07c9fde72b","src/bokeh/sources/data_pipe":"2295368b65","src/bokeh/util/conversions":"e3901fa9f2","src/bokeh/sources/active_data_pipes":"5179d11e71","src/bokeh/util/model_manager":"30b45c52a1","src/bokeh/sources/image_pipe":"2889e0dd45","src/bokeh/sources/image_data_source":"de65005924","src/bokeh/sources/spectra_data_source":"02e3c3e46c","src/bokeh/sources/updatable_data_source":"64b16deff9","src/bokeh/format/wcs_ticks":"b6ae454f0d","src/bokeh/tools/drag_tool":"cb7d28d6b3","src/bokeh/events":"8fc7a9e935","src/bokeh/util/find":"484bb85d20","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"a6e757a69a","src/bokeh/models/bokeh_app_context":"467d2716b0","src/bokeh/models/shared_dict":"50a1e32f01","src/bokeh/models/edit_span":"b55081402e","src/bokeh/models/ev_text_input":"9144bfc7a5","src/bokeh/annotations/ev_poly_annotation":"74e0abef8a"}, {});});
@@ -30,6 +30,7 @@ provided by Bokeh'''
30
30
 
31
31
  from .state import order_bokeh_js as _order_bokeh_js
32
32
  from .state import register_model as _register_model
33
+ from .state._initialize import get_bokeh_js_paths
33
34
  from .state import set_cubevis_lib
34
35
 
35
36
  class BokehInit:
@@ -5,6 +5,7 @@ from bokeh.core.properties import Instance, String
5
5
 
6
6
  from bokeh.io import curdoc
7
7
  from .. import BokehInit
8
+ from ...utils import is_colab
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
 
@@ -272,8 +273,11 @@ class Showable(LayoutDOM,BokehInit):
272
273
  Common logic for generating HTML in notebook environments.
273
274
  Returns the HTML string to display, or None if not in a notebook.
274
275
  """
275
- from bokeh.embed import components
276
+ from bokeh.embed import components, json_item
276
277
  from bokeh.io.state import curstate
278
+ from bokeh.resources import CDN
279
+ import sys
280
+ import json as json_lib
277
281
 
278
282
  state = curstate()
279
283
 
@@ -284,31 +288,96 @@ class Showable(LayoutDOM,BokehInit):
284
288
  return '<div style="color: red; padding: 10px; border: 1px solid red;">Showable object with no UI set</div>'
285
289
 
286
290
  if self._display_context:
287
- self._display_context.on_show( )
291
+ self._display_context.on_show()
288
292
 
289
293
  if self._notebook_rendering:
290
294
  # Return a lightweight reference instead of re-rendering the full GUI
291
295
  return f'''
292
296
  <div style="padding: 10px; background: #f0f8f0; border-left: 4px solid #4CAF50; margin: 5px 0;">
293
- <strong>↑ iclean GUI active above</strong>
297
+ <strong>→ iclean GUI active above</strong>
294
298
  <small style="color: #666; display: block; margin-top: 5px;">
295
299
  Showable ID: {self.id[-8:]} | Backend: Running
296
300
  </small>
297
301
  </div>
298
302
  '''
299
303
 
300
- # Apply notebook sizing for Jupyter context
301
- ###if self._notebook_sizing == 'fixed':
302
- ### self.sizing_mode = None
303
- ### self.width = self._notebook_width
304
- ### self.height = self._notebook_height
304
+ if is_colab( ):
305
+ # Get all JS paths from the existing function
306
+ # This returns paths in the correct order:
307
+ # [casalib, bokeh-core, bokeh-widgets, bokeh-tables, cubevisjs]
308
+ from cubevis.bokeh import get_bokeh_js_paths
309
+ js_paths = get_bokeh_js_paths( )
310
+
311
+ # Build script tags for all libraries in order
312
+ all_scripts = '\n'.join([
313
+ f'<script type="text/javascript" src="{url}"></script>'
314
+ for url in js_paths
315
+ ])
316
+
317
+ print( "-----scripts-being-used-----------------------------------------------" )
318
+ print( all_scripts )
319
+ print( "----------------------------------------------------------------------" )
320
+
321
+ # Use json_item approach which is more reliable in iframes
322
+ item = json_item(self, target=f"bokeh-{self.id}")
323
+ item_json = json_lib.dumps(item)
324
+
325
+ # Build complete HTML with proper loading sequence
326
+ # get_bokeh_js_paths() already returns libs in the correct order:
327
+ # 1. casalib (third-party libs for CustomJS)
328
+ # 2. bokeh-core
329
+ # 3. bokeh-widgets
330
+ # 4. bokeh-tables
331
+ # 5. cubevisjs (custom Bokeh models)
332
+ html = f'''
333
+ {f'<link href="{CDN.css_files[0]}" rel="stylesheet" type="text/css">' if CDN.css_files else ""}
334
+ <div id="bokeh-{self.id}" class="bk-root"></div>
335
+ {all_scripts}
336
+ <script type="text/javascript">
337
+ (function() {{
338
+ var item = {item_json};
339
+
340
+ function embedWhenReady() {{
341
+ // Check if all required libraries are loaded
342
+ if (typeof Bokeh !== 'undefined' && Bokeh.embed) {{
343
+ var target = document.getElementById("bokeh-{self.id}");
344
+ if (target) {{
345
+ try {{
346
+ Bokeh.embed.embed_item(item);
347
+ console.log("Bokeh plot embedded successfully");
348
+ }} catch(e) {{
349
+ console.error("Error embedding Bokeh plot:", e);
350
+ }}
351
+ }} else {{
352
+ console.error("Target element not found");
353
+ setTimeout(embedWhenReady, 50);
354
+ }}
355
+ }} else {{
356
+ setTimeout(embedWhenReady, 50);
357
+ }}
358
+ }}
359
+
360
+ if (document.readyState === 'loading') {{
361
+ document.addEventListener('DOMContentLoaded', embedWhenReady);
362
+ }} else {{
363
+ embedWhenReady();
364
+ }}
365
+ }})();
366
+ </script>
367
+ '''
305
368
 
306
- script, div = components(self)
307
- if start_backend:
308
- self._start_backend()
369
+ if start_backend:
370
+ self._start_backend()
309
371
 
310
- self._notebook_rendering = f'{script}\n{div}'
311
- return self._notebook_rendering
372
+ self._notebook_rendering = html
373
+ return html
374
+ else:
375
+ # In Jupyter Lab/Classic, use components() as before
376
+ script, div = components(self)
377
+ if start_backend:
378
+ self._start_backend()
379
+ self._notebook_rendering = f'{script}\n{div}'
380
+ return self._notebook_rendering
312
381
 
313
382
  def _repr_mimebundle_(self, include=None, exclude=None):
314
383
  """
@@ -43,7 +43,7 @@ from bokeh.util.compiler import TypeScript
43
43
  from bokeh.core.properties import Tuple, String, Int, Instance, Nullable, Bool
44
44
  from bokeh.models.callbacks import Callback
45
45
 
46
- from ...utils import serialize, deserialize, is_interactive_jupyter
46
+ from ...utils import serialize, deserialize, is_interactive_jupyter, is_colab
47
47
  from ..state import casalib_url, cubevisjs_url
48
48
  from .. import BokehInit
49
49
 
@@ -86,6 +86,27 @@ class DataPipe(DataSource,BokehInit):
86
86
  ###################################################################
87
87
  #__javascript__ = [ casalib_url( ), cubevisjs_url( ) ]
88
88
 
89
+ def _expose_colab_port(self):
90
+ """Expose the WebSocket port through Colab's proxy"""
91
+ try:
92
+ from google.colab import output
93
+ port = self.address[1]
94
+
95
+ # Use serve_kernel_port_as_iframe for newer Colab
96
+ # This doesn't open a popup, just registers the port
97
+ try:
98
+ output.serve_kernel_port_as_iframe(port)
99
+ print(f"✓ Colab: Exposed WebSocket port {port} via iframe proxy")
100
+ except AttributeError:
101
+ # Fallback to older method
102
+ output.serve_kernel_port_as_window(port)
103
+ print(f"✓ Colab: Exposed WebSocket port {port} via window proxy")
104
+
105
+ except Exception as e:
106
+ print(f"⚠ Warning: Could not expose port {port} in Colab: {e}")
107
+ import traceback
108
+ traceback.print_exc()
109
+
89
110
  def __init__( self, *args, abort=None, **kwargs ):
90
111
 
91
112
  if 'conflict_check' not in kwargs:
@@ -106,6 +127,10 @@ class DataPipe(DataSource,BokehInit):
106
127
  if self.__abort is not None and not callable(self.__abort):
107
128
  raise RuntimeError(f'abort function must be callable ({type(self.__abort)} is not)')
108
129
 
130
+ # Expose port in Colab
131
+ if is_colab( ):
132
+ self._expose_colab_port()
133
+
109
134
  def __enqueue_send( self, ident, msg, callback ):
110
135
  ### it is assumed that this is called AFTER the lock has been aquired
111
136
  if ident in self.__send_queue:
@@ -266,6 +291,8 @@ class DataPipe(DataSource,BokehInit):
266
291
  self.__websocket = websocket
267
292
  session_established = False
268
293
 
294
+ print(f"✓ WebSocket server received connection on port {self.address[1]}")
295
+
269
296
  async for message in websocket:
270
297
  msg = deserialize(message)
271
298
  if 'session' not in msg:
@@ -321,6 +321,13 @@ def order_bokeh_js():
321
321
  resources.Resources.js_files = property(js_files)
322
322
  return
323
323
 
324
+ #def get_bokeh_js_paths( ):
325
+ # modes = ['cdn','inline','server','server-dev','relative','relative-dev','absolute','absolute-dev']
326
+ # return { 'new': { mode: resources.Resources(mode=mode).js_files for mode in modes },
327
+ # 'old': { mode: resources.Resources(mode=mode)._old_js_files for mode in modes } }
328
+ def get_bokeh_js_paths( ):
329
+ return resources.Resources(mode='cdn').js_files
330
+
324
331
  def get_jupyter_state( ):
325
332
  """Get the package-level Jupyter state"""
326
333
  return _JUPYTER_STATE
@@ -1082,7 +1082,7 @@ class CubeMask:
1082
1082
  ### Firefox incorrectly sizes the colormap histogram plot resulting in the right
1083
1083
  ### side being outside of the browser window... this may have to be tweaked again
1084
1084
  ### when Jupyter notebooks are supported...
1085
- ( [ Spacer( width=120 ) ] if have_firefox( ) else [ ] ), sizing_mode='stretch_both' ),
1085
+ ( [ Spacer( width=120 ) ] if not is_interactive_jupyter( ) and have_firefox( ) else [ ] ), sizing_mode='stretch_both' ),
1086
1086
  row( Tip( self._cm_adjust['min input'],
1087
1087
  tooltip=Tooltip( content=HTML("set minimum clip here or drag the left red line above"),
1088
1088
  position="top" ) ),
@@ -43,7 +43,7 @@ from ._regions import polygon_indexes
43
43
  from ._docenum import DocEnum
44
44
  from ._copydoc import copydoc
45
45
  from ._pkgs import find_pkg, load_pkg
46
- from ._jupyter import is_interactive_jupyter
46
+ from ._jupyter import is_interactive_jupyter, is_colab
47
47
  from ._browser import have_firefox
48
48
  from ._git import max_git_version
49
49
 
@@ -1,3 +1,5 @@
1
+ import os
2
+ import sys
1
3
  import logging
2
4
 
3
5
  logger = logging.getLogger(__name__)
@@ -17,6 +19,15 @@ logger = logging.getLogger(__name__)
17
19
  # except NameError:
18
20
  # return False
19
21
 
22
+ def is_colab():
23
+ """
24
+ Detects if the current environment is Google Colab.
25
+ Combines module check (process-level) and env-var check (VM-level).
26
+ """
27
+ # 1. Check for the Colab-specific environment variable (VM level)
28
+ # 2. Check for the google.colab module (Python process level)
29
+ return os.getenv("COLAB_RELEASE_TAG") is not None or 'google.colab' in sys.modules
30
+
20
31
  def is_interactive_jupyter( ) -> bool:
21
32
  """
22
33
  Detect if running in an interactive Jupyter notebook with frontend connection.
@@ -25,6 +36,7 @@ def is_interactive_jupyter( ) -> bool:
25
36
  - Interactive Jupyter notebook/lab with frontend (returns True)
26
37
  - Standalone Jupyter kernel without frontend (returns False)
27
38
  - Regular Python interpreter (returns False)
39
+ - Support Google Colab and legacy Jupyter versions.
28
40
 
29
41
  Returns:
30
42
  bool: True if running in interactive Jupyter with frontend, False otherwise
@@ -37,12 +49,21 @@ def is_interactive_jupyter( ) -> bool:
37
49
  logger.debug(f"\tis_interactive_jupyter<1>: False")
38
50
  return False
39
51
 
40
- # Check if we're in a ZMQ-based shell (kernel)
41
- if ipython.__class__.__name__ != 'ZMQInteractiveShell':
52
+ # Allow Colab's 'Shell' class in addition to standard 'ZMQInteractiveShell'
53
+ shell_class = ipython.__class__.__name__
54
+ is_colab = 'google.colab' in sys.modules
55
+
56
+ # Check if we're in a ZMQ-based shell (kernel) or Colab's 'Shell'
57
+ if shell_class not in ['ZMQInteractiveShell', 'Shell'] and not is_colab:
42
58
  logger.debug(f"\tis_interactive_jupyter<2>: False")
43
59
  return False
44
60
 
45
- # Check for active frontend connection
61
+ # If we are in Colab, the existence of the shell itself implies
62
+ # an interactive frontend, as Colab sessions are inherently interactive.
63
+ if is_colab:
64
+ return True
65
+
66
+ # Check for active frontend connection (Standard Jupyter/Legacy)
46
67
  if hasattr(ipython, 'kernel') and ipython.kernel is not None:
47
68
  kernel = ipython.kernel
48
69
 
@@ -51,14 +72,15 @@ def is_interactive_jupyter( ) -> bool:
51
72
  # For newer Jupyter versions, check connection count
52
73
  if hasattr(kernel, 'connection_count'):
53
74
  logger.debug(f"\tis_interactive_jupyter<3>: {kernel.connection_count > 0}")
54
- return kernel.connection_count > 0
75
+ if kernel.connection_count > 0:
76
+ return True
55
77
 
56
78
  # For older versions, check if socket is connected
57
79
  try:
58
80
  # Try to get socket state - if it fails, likely no frontend
59
- socket_state = kernel.shell_socket.closed
60
81
  logger.debug(f"\tis_interactive_jupyter<4>: {not socket_state}")
61
- return not socket_state
82
+ if not kernel.shell_socket.closed:
83
+ return True
62
84
  except AttributeError:
63
85
  pass
64
86
 
@@ -68,7 +90,8 @@ def is_interactive_jupyter( ) -> bool:
68
90
  parent = kernel.get_parent()
69
91
  # If there's a parent message, we're likely in interactive mode
70
92
  logger.debug(f"\tis_interactive_jupyter<5>: {parent is not None and len(parent) > 0}")
71
- return parent is not None and len(parent) > 0
93
+ if parent is not None and len(parent) > 0:
94
+ return True
72
95
  except Exception:
73
96
  pass
74
97
 
@@ -77,12 +100,12 @@ def is_interactive_jupyter( ) -> bool:
77
100
  logger.debug(f"\tis_interactive_jupyter<6>: True")
78
101
  return True
79
102
 
80
- # Fallback: Check for common Jupyter notebook environment indicators
81
- # This catches cases where kernel introspection doesn't work
82
- import os
103
+ # Fallback: Check for environment indicators (Legacy/Containerized Jupyter)
83
104
  jupyter_indicators = [
84
- 'JPY_PARENT_PID', # JupyterLab/Notebook sets this
105
+ 'JPY_PARENT_PID', # JupyterLab/Notebook sets this
85
106
  'JUPYTER_RUNTIME_DIR',
107
+ 'COLAB_RELEASE_DEVICE', # Additional Colab-specific env check
108
+ 'COLAB_GPU' # Additional Colab-specific env check
86
109
  ]
87
110
 
88
111
  for indicator in jupyter_indicators:
@@ -99,6 +122,6 @@ def is_interactive_jupyter( ) -> bool:
99
122
  logger.debug(f"\tis_interactive_jupyter<8>: False")
100
123
  return False
101
124
 
102
- except ImportError:
125
+ except (ImportError, Exception):
103
126
  logger.debug(f"\tis_interactive_jupyter<9>: False")
104
127
  return False
@@ -16,7 +16,7 @@ dependencies = [
16
16
  ]
17
17
  requires-python = ">=3.11"
18
18
  readme = "README.rst"
19
- version = "1.0.21"
19
+ version = "1.0.33"
20
20
 
21
21
  [project.license]
22
22
  text = "LGPL"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes