cubevis 1.0.4__tar.gz → 1.0.15__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 (163) hide show
  1. {cubevis-1.0.4 → cubevis-1.0.15}/PKG-INFO +1 -1
  2. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__js__/bokeh-3.8/cubevisjs.min.js +9 -8
  3. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/__init__.py +1 -0
  4. cubevis-1.0.15/cubevis/bokeh/models/_bokeh_app_context.py +63 -0
  5. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/_data_pipe.py +14 -2
  6. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_createmask.py +41 -33
  7. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_createregion.py +29 -21
  8. cubevis-1.0.15/cubevis/private/casatasks/iclean_notebook.py +1831 -0
  9. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_cube.py +20 -18
  10. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_interactive_clean_ui.mustache +61 -44
  11. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_interactive_clean_ui.py +61 -44
  12. {cubevis-1.0.4 → cubevis-1.0.15}/pyproject.toml +2 -2
  13. cubevis-1.0.15/tests/manual/iclean-demo/iclean-demo.ipynb +251 -0
  14. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-outlier/run-iclean.py +2 -3
  15. {cubevis-1.0.4 → cubevis-1.0.15}/LICENSE +0 -0
  16. {cubevis-1.0.4 → cubevis-1.0.15}/README.rst +0 -0
  17. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/LICENSE.rst +0 -0
  18. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/20px/fast-backward.svg +0 -0
  19. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/20px/fast-forward.svg +0 -0
  20. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/20px/step-backward.svg +0 -0
  21. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/20px/step-forward.svg +0 -0
  22. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/add-chan.png +0 -0
  23. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/add-chan.svg +0 -0
  24. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/add-cube.png +0 -0
  25. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/add-cube.svg +0 -0
  26. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/drag.png +0 -0
  27. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/drag.svg +0 -0
  28. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/mask-selected.png +0 -0
  29. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/mask.png +0 -0
  30. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/mask.svg +0 -0
  31. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/new-layer-sm-selected.png +0 -0
  32. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/new-layer-sm-selected.svg +0 -0
  33. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/new-layer-sm.png +0 -0
  34. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/new-layer-sm.svg +0 -0
  35. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/reset.png +0 -0
  36. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/reset.svg +0 -0
  37. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/sub-chan.png +0 -0
  38. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/sub-chan.svg +0 -0
  39. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/sub-cube.png +0 -0
  40. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/sub-cube.svg +0 -0
  41. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/trash.png +0 -0
  42. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/trash.svg +0 -0
  43. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/trash_full.png +0 -0
  44. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/trash_full.svg +0 -0
  45. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/trash_full_raw.png +0 -0
  46. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/zoom-to-fit.png +0 -0
  47. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__icons__/zoom-to-fit.svg +0 -0
  48. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__init__.py +0 -0
  49. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__js__/bokeh-3.6/cubevisjs.min.js +0 -0
  50. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__js__/bokeh-3.7/cubevisjs.min.js +0 -0
  51. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/__js__/casalib.min.js +0 -0
  52. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/__init__.py +0 -0
  53. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/annotations/__init__.py +0 -0
  54. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/annotations/_ev_poly_annotation.py +0 -0
  55. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/components/__init__.py +0 -0
  56. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/format/__init__.py +0 -0
  57. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/format/_time_ticks.py +0 -0
  58. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/format/_wcs_ticks.py +0 -0
  59. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_edit_span.py +0 -0
  60. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_ev_text_input.py +0 -0
  61. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_shared_dict.py +0 -0
  62. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_showable.py +0 -0
  63. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_tip.py +0 -0
  64. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/models/_tip_button.py +0 -0
  65. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/__init__.py +0 -0
  66. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/_image_data_source.py +0 -0
  67. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/_image_pipe.py +0 -0
  68. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/_spectra_data_source.py +0 -0
  69. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/sources/_updatable_data_source.py +0 -0
  70. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/__init__.py +0 -0
  71. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/_current.py +0 -0
  72. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/_initialize.py +0 -0
  73. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/_javascript.py +0 -0
  74. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/_palette.py +0 -0
  75. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/_session.py +0 -0
  76. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/bokeh-2.4.1.min.js +0 -0
  77. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/bokeh-gl-2.4.1.min.js +0 -0
  78. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/bokeh-tables-2.4.1.min.js +0 -0
  79. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/bokeh-widgets-2.4.1.min.js +0 -0
  80. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/casaguijs-v0.0.4.0-b2.4.min.js +0 -0
  81. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/casaguijs-v0.0.5.0-b2.4.min.js +0 -0
  82. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/casaguijs-v0.0.6.0-b2.4.min.js +0 -0
  83. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/state/js/casalib-v0.0.1.min.js +0 -0
  84. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/tools/__init__.py +0 -0
  85. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/tools/_cbreset_tool.py +0 -0
  86. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/tools/_drag_tool.py +0 -0
  87. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/utils/__init__.py +0 -0
  88. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/utils/_axes_labels.py +0 -0
  89. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/bokeh/utils/_svg_icon.py +0 -0
  90. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/data/__init__.py +0 -0
  91. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/data/casaimage/__init__.py +0 -0
  92. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/exe/__init__.py +0 -0
  93. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/exe/_context.py +0 -0
  94. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/exe/_mode.py +0 -0
  95. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/exe/_setting.py +0 -0
  96. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/exe/_task.py +0 -0
  97. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/_gclean.py +0 -0
  98. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/__init__.py +0 -0
  99. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_interactiveclean.mustache +0 -0
  100. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_interactiveclean.py +0 -0
  101. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_interactivecleannotebook.mustache +0 -0
  102. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_interactivecleannotebook.py +0 -0
  103. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_plotants.py +0 -0
  104. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/apps/_plotbandpass.py +0 -0
  105. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casashell/createmask.py +0 -0
  106. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casashell/iclean.py +0 -0
  107. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casatasks/__init__.py +0 -0
  108. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casatasks/createmask.py +0 -0
  109. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casatasks/createregion.py +0 -0
  110. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/private/casatasks/iclean.py +0 -0
  111. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/readme.rst +0 -0
  112. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/remote/__init__.py +0 -0
  113. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/remote/_gclean.py +0 -0
  114. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/remote/_local.py +0 -0
  115. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/remote/_remote_kernel.py +0 -0
  116. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/__init__.py +0 -0
  117. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_app_context.py +0 -0
  118. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_interactiveclean_wrappers.py +0 -0
  119. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/toolbox/_region_list.py +0 -0
  120. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_ResourceManager.py +0 -0
  121. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/__init__.py +0 -0
  122. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_browser.py +0 -0
  123. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_contextmgrchain.py +0 -0
  124. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_conversion.py +0 -0
  125. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_copydoc.py +0 -0
  126. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_docenum.py +0 -0
  127. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_git.py +0 -0
  128. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_import_protected_module.py +0 -0
  129. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_jupyter.py +0 -0
  130. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_logging.py +0 -0
  131. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_pkgs.py +0 -0
  132. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_regions.py +0 -0
  133. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_static.py +0 -0
  134. {cubevis-1.0.4 → cubevis-1.0.15}/cubevis/utils/_tiles.py +0 -0
  135. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/alma-many-chan/alma-many-chan.py +0 -0
  136. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/basic-websockets-demo/client.html +0 -0
  137. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/basic-websockets-demo/client.py +0 -0
  138. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/basic-websockets-demo/server.py +0 -0
  139. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/createmask-demo/run-createmask.py +0 -0
  140. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/createregion-demo/run-createregion.py +0 -0
  141. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/cubemask-demo/image-slider-spectra-done-stats.py +0 -0
  142. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/cubemask-demo/image-slider-spectra-done.py +0 -0
  143. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/cubemask-demo/image-slider-spectra.py +0 -0
  144. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/cubemask-demo/image-slider.py +0 -0
  145. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/cubemask-demo/image.py +0 -0
  146. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/m100_interactive.py +0 -0
  147. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/mask0-iclean.py +0 -0
  148. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/run-gclean.py +0 -0
  149. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/run-iclean-obj.py +0 -0
  150. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/run-iclean.py +0 -0
  151. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-demo/vla-sim-jet-iclean.py +0 -0
  152. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-first-look/run-fl-cont.py +0 -0
  153. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-first-look/run-fl-line.py +0 -0
  154. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-outlier/test_outlier.txt +0 -0
  155. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/iclean-remote/iclean_remote_webserver.py +0 -0
  156. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/large-cube/run-largecube.py +0 -0
  157. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/svg-test.py +0 -0
  158. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/updatable-data-source/direct-plot.py +0 -0
  159. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/updatable-data-source/simple-update.py +0 -0
  160. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/updatable-data-source/updated-plot.py +0 -0
  161. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/uranus-demo/uranus-iclean.py +0 -0
  162. {cubevis-1.0.4 → cubevis-1.0.15}/tests/manual/websocket-reconnect/client.html +0 -0
  163. {cubevis-1.0.4 → cubevis-1.0.15}/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.4
3
+ Version: 1.0.15
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,23 +42,24 @@
42
42
  }
43
43
  })
44
44
  ({
45
- "0a6f8c037f": function _(a,e,t,o,c){o();const i=a("tslib"),n=a("5108a98ed0");c("DataPipe",n.DataPipe);const s=a("2889e0dd45");c("ImagePipe",s.ImagePipe);const p=a("de65005924");c("ImageDataSource",p.ImageDataSource);const r=a("02e3c3e46c");c("SpectraDataSource",r.SpectraDataSource);const S=a("64b16deff9");c("UpdatableDataSource",S.UpdatableDataSource);const l=a("b6ae454f0d");c("WcsTicks",l.WcsTicks);const d=a("cb7d28d6b3");c("DragTool",d.DragTool);const D=a("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=a("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const u=a("9f961622ce");c("TipButton",u.TipButton);const b=a("ca4c845905");c("Tip",b.Tip);const f=a("5e5f767c53");c("Showable",f.Showable);const g=a("50a1e32f01");c("SharedDict",g.SharedDict);const E=a("b55081402e");c("EditSpan",E.EditSpan);const I=a("9144bfc7a5");c("EvTextInput",I.EvTextInput);const P=a("74e0abef8a");c("EvPolyAnnotation",P.EvPolyAnnotation);const m=i.__importStar(a("44f332a4cc"));t.find=m;(0,a("@bokehjs/base").register_models)({DataPipe:n.DataPipe,ImagePipe:s.ImagePipe,ImageDataSource:p.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:S.UpdatableDataSource,WcsTicks:l.WcsTicks,DragTool:d.DragTool,CBResetTool:D.CBResetTool,Tip:b.Tip,TipButton:u.TipButton,SharedDict:g.SharedDict,Showable:f.Showable,EditSpan:E.EditSpan,EvTextInput:I.EvTextInput,EvPolyAnnotation:P.EvPolyAnnotation})},
46
- "5108a98ed0": 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");class l 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)}isJupyterContext(){return void 0!==window.Jupyter||void 0!==window._jupyter_labextension_metadata||null!==window.frameElement&&window.parent!==window}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.isJupyterContext()){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(){return`${this.address[0]}_${this.address[1]}`}initialize(){if(super.initialize(),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)})()}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=l,o=l,l.__name__="DataPipe",l.__module__="cubevis.bokeh.sources._data_pipe",o.define((({Any:e,Tuple:s,String:t,Number:i})=>({init_script:[e,null],address:[s(t,i)]})))},
45
+ "e2864cf297": function _(e,t,a,o,c){o();const n=e("tslib"),i=e("87aeec7876");c("DataPipe",i.DataPipe);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 l=e("b6ae454f0d");c("WcsTicks",l.WcsTicks);const d=e("cb7d28d6b3");c("DragTool",d.DragTool);const D=e("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=e("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const u=e("9f961622ce");c("TipButton",u.TipButton);const b=e("ca4c845905");c("Tip",b.Tip);const f=e("5e5f767c53");c("Showable",f.Showable);const g=e("467d2716b0");c("BokehAppContext",g.BokehAppContext);const h=e("50a1e32f01");c("SharedDict",h.SharedDict);const B=e("b55081402e");c("EditSpan",B.EditSpan);const E=e("9144bfc7a5");c("EvTextInput",E.EvTextInput);const I=e("74e0abef8a");c("EvPolyAnnotation",I.EvPolyAnnotation);const P=n.__importStar(e("389c724eb9"));a.find=P;(0,e("@bokehjs/base").register_models)({DataPipe:i.DataPipe,ImagePipe:p.ImagePipe,ImageDataSource:s.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:S.UpdatableDataSource,WcsTicks:l.WcsTicks,DragTool:d.DragTool,CBResetTool:D.CBResetTool,Tip:b.Tip,TipButton:u.TipButton,SharedDict:h.SharedDict,Showable:f.Showable,BokehAppContext:g.BokehAppContext,EditSpan:B.EditSpan,EvTextInput:E.EvTextInput,EvPolyAnnotation:I.EvPolyAnnotation})},
46
+ "87aeec7876": function _(e,s,t,i,n){var o;i();const c=e("@bokehjs/models/sources/data_source"),a=e("e3901fa9f2"),l=e("@bokehjs/core/util/callbacks");class r extends c.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(),console.log("**** TypeScript initialize ****"),console.log("conflict_check value:",this.conflict_check),console.log("conflict_check type:",typeof this.conflict_check),console.log("All properties:",this.properties),console.log("*******************************"),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,a.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,a.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,a.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,a.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,l.execute)(this.init_script,this)})()}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 c of this.send_queue[e])i(c.msg.message)&&(c.msg=n,c.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:l,msg:r}=this.send_queue[e].shift();if(this.pending[e]={cb:l},this.websocket.readyState===WebSocket.OPEN)this.websocket.send((0,a.serialize)(r));else{let d=20,h=this;function u(){h.websocket.readyState===WebSocket.OPEN?h.websocket.send((0,a.serialize)(r)):(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,a.serialize)(n));else{let g=20,_=this;function b(){_.websocket.readyState===WebSocket.OPEN?(_.pending[e]={cb:t},_.websocket.send((0,a.serialize)(n))):(g-=1,g>0&&setTimeout(b,3e3))}setTimeout(b,3e3)}}}t.DataPipe=r,o=r,r.__name__="DataPipe",r.__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
- "2889e0dd45": function _(i,e,s,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("5108a98ed0");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]})))},
48
+ "2889e0dd45": function _(i,e,s,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("87aeec7876");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]})))},
49
49
  "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)]})))},
50
50
  "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)]})))},
51
- "64b16deff9": function _(e,s,i,t,a){var n;t();const u=e("@bokehjs/models/sources/column_data_source"),l=e("5108a98ed0"),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]})))},
51
+ "64b16deff9": function _(e,s,i,t,a){var n;t();const u=e("@bokehjs/models/sources/column_data_source"),l=e("87aeec7876"),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]})))},
52
52
  "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)]})))},
53
- "cb7d28d6b3": function _(i,e,t,o,s){var d;o();const l=i("@bokehjs/models/tools/gestures/gesture_tool"),r=i("949501ff1c"),_=i("44f332a4cc"),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]})))},
54
- "949501ff1c": function _(e,t,a,s,n){s();const _=e("@bokehjs/core/bokeh_events");class r extends _.Pan{}a.Drag=r,r.__name__="Drag";class l extends _.PanStart{constructor(e,t,a,s,n,_,r){super(e,t,a,s,r),this.delta_x=n,this.delta_y=_}get event_values(){const{delta_x:e,delta_y:t}=this;return Object.assign(Object.assign({},super.event_values),{delta_x:e,delta_y:t})}}a.DragStart=l,l.__name__="DragStart";class d extends _.PanEnd{constructor(e,t,a,s,n,_,r){super(e,t,a,s,r),this.delta_x=n,this.delta_y=_}get event_values(){const{delta_x:e,delta_y:t}=this;return Object.assign(Object.assign({},super.event_values),{delta_x:e,delta_y:t})}}a.DragEnd=d,d.__name__="DragEnd"},
55
- "44f332a4cc": function _(e,n,o,t,r){t(),o.view=function(e){function n(o){if(o.model===e)return o;for(const e of o.children()){const o=n(e);if(o)return o}return null}const o=e.document;if(!o)return null;const t=o.views_manager;if(!t)return null;const r=t.roots;for(const e of r){const o=n(e);if(o)return o}return null},o.span_coords=function(e){function n(e,n,o,t,r){if(null!=e)switch(n){case"canvas":return r.compute(e);case"screen":return t.compute(e);case"data":return o.compute(e)}return NaN}const{frame:o,canvas:t}=e.plot_view,{x_scale:r,y_scale:i}=e.coordinates;let c,_,u,f,m=e.model.dimension;"width"==e.model.dimension?(u=n(e.model.location,e.model.location_units,i,o.bbox.yview,t.bbox.y_screen),_=o.bbox.left,f=o.bbox.width,c=e.model.line_width):(u=o.bbox.top,_=n(e.model.location,e.model.location_units,r,o.bbox.xview,t.bbox.y_screen),f=e.model.line_width,c=o.bbox.height);return{stop:u,sleft:_,width:f,height:c,orientation:m}},o.px_from_sx=function(e,n){return e.frame.bbox.x_view.invert(n)},o.py_from_sy=function(e,n){return e.frame.bbox.y_view.invert(n)},o.dx_from_px=function(e,n){const o=e.frame.bbox.x_view.compute(n);return e.frame.x_scale.invert(o)},o.dy_from_py=function(e,n){const o=e.frame.bbox.y_view.compute(n);return e.frame.y_scale.invert(o)},o.sx_from_dx=function(e,n){return e.frame.x_scale.compute(n)},o.sy_from_dy=function(e,n){return e.frame.y_scale.compute(n)},o.v_px_from_sx=function(e,n){return e.frame.bbox.x_view.v_invert(n)},o.v_py_from_sy=function(e,n){return e.frame.bbox.y_view.v_invert(n)},o.v_dx_from_px=function(e,n){const o=e.frame.bbox.x_view.v_compute(n);return e.frame.x_scale.v_invert(o)},o.v_dy_from_py=function(e,n){const o=e.frame.bbox.y_view.v_compute(n);return e.frame.y_scale.v_invert(o)},o.v_sx_from_dx=function(e,n){return e.frame.x_scale.v_compute(n)},o.v_sy_from_dy=function(e,n){return e.frame.y_scale.v_compute(n)}},
53
+ "cb7d28d6b3": function _(e,i,t,o,s){var d;o();const l=e("@bokehjs/models/tools/gestures/gesture_tool"),r=e("8fc7a9e935"),_=e("389c724eb9"),m=e("@bokehjs/core/util/callbacks");class a extends l.GestureToolView{_pan_start(e){var i;null===(i=this.model.document)||void 0===i||i.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,e.sx),o=(0,_.py_from_sy)(this.plot_view,e.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:e.dx,delta_y:-e.dy,shift:"modifiers"in e?e.modifiers.shift:void 0,ctrl:"modifiers"in e?e.modifiers.ctrl:void 0,alt:"modifiers"in e?e.modifiers.alt:void 0}):this.model.trigger_event(new r.DragStart(t,o,s,d,e.dx,-e.dy,e.modifiers))}_pan(e){var i;null===(i=this.model.document)||void 0===i||i.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,e.sx),o=(0,_.py_from_sy)(this.plot_view,e.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:e.dx,delta_y:-e.dy,shift:"modifiers"in e?e.modifiers.shift:void 0,ctrl:"modifiers"in e?e.modifiers.ctrl:void 0,alt:"modifiers"in e?e.modifiers.alt:void 0}):this.model.trigger_event(new r.Drag(t,o,s,d,e.dx,-e.dy,e.modifiers))}_pan_end(e){const i=(0,_.px_from_sx)(this.plot_view,e.sx),t=(0,_.py_from_sy)(this.plot_view,e.sy),o=(0,_.dx_from_px)(this.plot_view,i),s=(0,_.dy_from_py)(this.plot_view,t),{end:d}=this.model;d?(0,m.execute)(d,this.model,{sx:i,sy:t,x:o,y:s,delta_x:e.dx,delta_y:-e.dy,shift:"modifiers"in e?e.modifiers.shift:void 0,ctrl:"modifiers"in e?e.modifiers.ctrl:void 0,alt:"modifiers"in e?e.modifiers.alt:void 0}):this.model.trigger_event(new r.DragEnd(i,t,o,s,e.dx,-e.dy,e.modifiers))}}t.DragToolView=a,a.__name__="DragToolView";class n extends l.GestureTool{constructor(e){super(e),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:e,Nullable:i})=>({start:[i(e),null],move:[i(e),null],end:[i(e),null]})))},
54
+ "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"},
55
+ "389c724eb9": function _(n,o,e,t,r){t(),e.view=function(n){function o(e){if(e.model===n)return e;for(const n of e.children()){const e=o(n);if(e)return e}return null}const e=n.document;if(!e)return null;const t=e.views_manager;if(!t)return null;const r=t.roots;for(const n of r){const e=o(n);if(e)return e}return null},e.span_coords=function(n){function o(n,o,e,t,r){if(null!=n)switch(o){case"canvas":return r.compute(n);case"screen":return t.compute(n);case"data":return e.compute(n)}return NaN}const{frame:e,canvas:t}=n.plot_view,{x_scale:r,y_scale:i}=n.coordinates;let c,u,s,f,_=n.model.dimension;"width"==n.model.dimension?(s=o(n.model.location,n.model.location_units,i,e.bbox.yview,t.bbox.y_screen),u=e.bbox.left,f=e.bbox.width,c=n.model.line_width):(s=e.bbox.top,u=o(n.model.location,n.model.location_units,r,e.bbox.xview,t.bbox.y_screen),f=n.model.line_width,c=e.bbox.height);return{stop:s,sleft:u,width:f,height:c,orientation:_}},e.px_from_sx=function(n,o){return n.frame.bbox.x_view.invert(o)},e.py_from_sy=function(n,o){return n.frame.bbox.y_view.invert(o)},e.dx_from_px=function(n,o){const e=n.frame.bbox.x_view.compute(o);return n.frame.x_scale.invert(e)},e.dy_from_py=function(n,o){const e=n.frame.bbox.y_view.compute(o);return n.frame.y_scale.invert(e)},e.sx_from_dx=function(n,o){return n.frame.x_scale.compute(o)},e.sy_from_dy=function(n,o){return n.frame.y_scale.compute(o)},e.v_px_from_sx=function(n,o){return n.frame.bbox.x_view.v_invert(o)},e.v_py_from_sy=function(n,o){return n.frame.bbox.y_view.v_invert(o)},e.v_dx_from_px=function(n,o){const e=n.frame.bbox.x_view.v_compute(o);return n.frame.x_scale.v_invert(e)},e.v_dy_from_py=function(n,o){const e=n.frame.bbox.y_view.v_compute(o);return n.frame.y_scale.v_invert(e)},e.v_sx_from_dx=function(n,o){return n.frame.x_scale.v_compute(o)},e.v_sy_from_dy=function(n,o){return n.frame.y_scale.v_compute(o)},e.context=u,e.appState=function(n){var o,e;const t=u(n);if(t){return null===(e=(null===(o=null===window||void 0===window?void 0:window.cubevisAppSession)||void 0===o?void 0:o.applications)[t.app_id])||void 0===e?void 0:e.state}return};const i=n("@bokehjs/model");function c(n,o,e=new Set){if(e.has(n))return;if(e.add(n),o(n))return n;const t=["children","items","panes","tabs","child","ui"];for(const r of t){const t=n[r];if(t){const n=Array.isArray(t)?t:[t];for(const t of n)if(t instanceof i.Model&&!e.has(t)){const n=c(t,o,e);if(n)return n}}}}function u(n){var o;const e=null===(o=null==n?void 0:n.document)||void 0===o?void 0:o.all_roots;if(e){const o=e.flatMap((n=>{const o=n;return o&&"cubevis.bokeh.models._bokeh_app_context.BokehAppContext"===o.type?[o]:[]}));return o.find((o=>Boolean(c(o,(o=>o.id===n.id)))))}}},
56
56
  "9d3c34ff8e": function _(e,o,l,s,t){var c;s();const _=e("@bokehjs/models/tools/actions/reset_tool"),i=e("@bokehjs/styles/icons.css"),a=e("@bokehjs/core/util/callbacks");class n extends _.ResetToolView{doit(){const{precallback:e,postcallback:o}=this.model;null!=e&&(0,a.execute)(e,this.model),this.plot_view.reset(),null!=o&&(0,a.execute)(o,this.model)}}l.CBResetToolView=n,n.__name__="CBResetToolView";class r extends _.ResetTool{constructor(e){super(e),this.tool_name="CBReset",this.tool_icon=i.tool_icon_reset}}l.CBResetTool=r,c=r,r.__name__="CBResetTool",r.__module__="cubevis.bokeh.tools._cbreset_tool",c.prototype.default_view=n,c.define((({Any:e,Nullable:o})=>({precallback:[o(e),null],postcallback:[o(e),null]}))),c.register_alias("cbreset",(()=>new c))},
57
57
  "9f961622ce": function _(e,t,i,o,s){var n;o();const l=e("@bokehjs/models/widgets/abstract_button"),c=e("@bokehjs/models/ui/tooltip"),d=e("@bokehjs/models/ui/icons/builtin_icon"),u=e("@bokehjs/core/build_views"),h=e("@bokehjs/core/bokeh_events"),r=e("@bokehjs/core/util/object");class a extends l.AbstractButtonView{constructor(){super(...arguments),this.isMouseInside=!1}click(){this.model.trigger_event(new h.ButtonClick),super.click()}*children(){yield*super.children(),yield this.tooltip}Show(){this.tooltip.model.setv({visible:!0,closable:!1})}unShow(){this.tooltip.model.setv({visible:!1,closable:!1})}async lazy_initialize(){const{hover_wait:e}=this.model;this.debouncedShow=casalib.debounce((()=>{this.isMouseInside&&this.Show()}),1e3*e),await super.lazy_initialize();const{tooltip:t}=this.model;this.tooltip=await(0,u.build_view)(t,{parent:this})}remove(){this.tooltip.remove(),super.remove()}render(){super.render(),this.el.addEventListener("mouseenter",(()=>{this.isMouseInside=!0,this.debouncedShow()})),this.el.addEventListener("mouseleave",(()=>{this.isMouseInside=!1,this.debouncedShow.cancel(),this.unShow()})),document.addEventListener("mousedown",(e=>{if(void 0===(0,r.dict)(this.model.js_event_callbacks).get(h.ButtonClick.prototype.event_name)){if(e.composedPath().includes(this.tooltip.el))return;this.debouncedShow.cancel(),this.unShow()}else this.isMouseInside=!1,this.debouncedShow.cancel(),this.unShow()})),window.addEventListener("blur",(()=>{this.debouncedShow.cancel(),this.unShow()}))}}i.TipButtonView=a,a.__name__="TipButtonView";class b extends l.AbstractButton{constructor(e){super(e)}on_click(e){this.on_event(h.ButtonClick,e)}}i.TipButton=b,n=b,b.__name__="TipButton",b.__module__="cubevis.bokeh.models._tip_button",n.prototype.default_view=a,n.define((({Ref:e,Number:t})=>({tooltip:[e(c.Tooltip)],hover_wait:[t,1.5]}))),n.override({label:"",icon:new d.BuiltinIcon({icon_name:"help",size:18}),button_type:"default"})},
58
58
  "ca4c845905": function _(e,i,s,t,o){var l;t();const d=e("@bokehjs/models/layouts/layout_dom"),n=e("@bokehjs/models/ui/ui_element"),h=e("@bokehjs/models/ui/tooltip"),r=e("@bokehjs/core/dom"),a=e("@bokehjs/core/build_views");class c extends d.LayoutDOMView{constructor(){super(...arguments),this.isMouseInside=!1}stylesheets(){return[...super.stylesheets(),"*, *:before, *:after { box-sizing: border-box; } fieldset { border: 0px; margin: 0px; padding: 0px; }"]}Show(){this.tooltip.model.setv({visible:!0,closable:!1})}unShow(){this.tooltip.model.setv({visible:!1,closable:!1})}async lazy_initialize(){const{hover_wait:e}=this.model;this.debouncedShow=casalib.debounce((()=>{this.isMouseInside&&this.Show()}),1e3*e),await super.lazy_initialize(),await this.build_child_views();const{tooltip:i}=this.model;this.tooltip=await(0,a.build_view)(i,{parent:this})}remove(){this.tooltip.remove(),super.remove()}connect_signals(){super.connect_signals();const{child:e}=this.model.properties;this.on_change(e,(()=>this.update_children())),this.el.addEventListener("mouseenter",(e=>{this.mouseenter.emit(e)})),this.el.addEventListener("mouseleave",(e=>{this.mouseleave.emit(e)}))}*children(){yield*super.children(),yield this.tooltip}get child_models(){return[this.model.child]}render(){super.render(),this.el.addEventListener("mouseenter",(()=>{this.isMouseInside=!0,this.debouncedShow()})),this.el.addEventListener("mouseleave",(()=>{this.isMouseInside=!1,this.debouncedShow.cancel(),this.unShow()})),window.addEventListener("blur",(()=>{this.debouncedShow.cancel(),this.unShow()})),this.el.addEventListener("click",(()=>{this.debouncedShow.cancel(),this.unShow()}));const e=this.child_views.map((e=>e.el));this.fieldset_el=(0,r.fieldset)({},...e),this.shadow_el.appendChild(this.fieldset_el)}_update_children(){const e=this.child_views.map((e=>e.el));this.fieldset_el.append(...e)}}s.TipView=c,c.__name__="TipView";class u extends d.LayoutDOM{constructor(e){super(e)}}s.Tip=u,l=u,u.__name__="Tip",u.__module__="cubevis.bokeh.models._tip",l.prototype.default_view=c,l.define((({Ref:e,Number:i})=>({child:[e(n.UIElement)],tooltip:[e(h.Tooltip)],hover_wait:[i,1.5]})))},
59
59
  "5e5f767c53": function _(e,i,t,s,l){var a;s();const o=e("@bokehjs/models/layouts/layout_dom"),n=e("@bokehjs/models/ui/ui_element");class u extends o.LayoutDOMView{get child_models(){return null!=this.model.ui?[this.model.ui]:[]}initialize(){super.initialize(),this.el.setAttribute("data-lm-suppress-shortcuts","true")}async lazy_initialize(){await super.lazy_initialize()}connect_signals(){super.connect_signals()}_update_layout(){super._update_layout()}render(){super.render(),0===this.child_views.length&&null==this.model.ui&&(this.el.innerHTML='<div style="color: gray; padding: 10px; border: 1px dashed gray;">\n Showable: No UI element set\n </div>')}after_layout(){super.after_layout()}_intrinsic_display(){return super._intrinsic_display()}remove(){super.remove()}}t.ShowableView=u,u.__name__="ShowableView";class r extends o.LayoutDOM{constructor(e){super(e)}}t.Showable=r,a=r,r.__name__="Showable",r.__module__="cubevis.bokeh.models._showable",a.prototype.default_view=u,a.define((({Ref:e})=>({ui:[e(n.UIElement)]})))},
60
+ "467d2716b0": function _(e,i,s,t,o){var n;t();const p=e("@bokehjs/models/layouts/layout_dom"),a=e("@bokehjs/models/ui/ui_element");class l extends p.LayoutDOMView{get child_models(){return null!=this.model.ui?[this.model.ui]:[]}initialize(){super.initialize(),this.el&&(this.el.style.padding="0",this.el.style.margin="0",this.el.style.border="none",this.el.style.background="transparent",this.el.style.display="contents"),this.connect(this.model.properties.app_state.change,(()=>{const e=window.cubevisAppSession;(null==e?void 0:e.applications[this.model.app_id])&&(e.applications[this.model.app_id].state=this.model.app_state)}))}}s.BokehAppContextView=l,l.__name__="BokehAppContextView";class d extends p.LayoutDOM{constructor(e){super(e)}initialize(){super.initialize(),window.cubevisAppSession||(window.cubevisAppSession={sessionId:this.session_id,applications:{}},console.log(`Initialized Bokeh session: ${this.session_id}`));const e=window.cubevisAppSession;e.applications[this.app_id]||(e.applications[this.app_id]={appId:this.app_id,state:this.app_state,createdAt:(new Date).toISOString()},console.log(`Registered application: ${this.app_id}`))}}s.BokehAppContext=d,n=d,d.__name__="BokehAppContext",d.__module__="cubevis.bokeh.models._bokeh_app_context",n.prototype.default_view=l,n.define((({Ref:e,Nullable:i,Dict:s,String:t,Unknown:o})=>({ui:[i(e(a.UIElement)),null],app_id:[t,""],session_id:[t,""],app_state:[s(o),{}]})))},
60
61
  "50a1e32f01": function _(e,s,i,n,t){var a;n();const c=e("@bokehjs/core/view"),o=e("@bokehjs/model");class _ extends c.View{initialize(){super.initialize()}connect_signals(){super.connect_signals();const{values:e}=this.model.properties;this.on_change(e,(()=>this.values_changed()))}values_changed(){}}i.SharedDictView=_,_.__name__="SharedDictView";class d extends o.Model{constructor(e){super(e)}}i.SharedDict=d,a=d,d.__name__="SharedDict",d.__module__="cubevis.bokeh.models._shared_dict",a.prototype.default_view=_,a.define((({Dict:e,Unknown:s})=>({values:[e(s),{}]})))},
61
62
  "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},
62
63
  "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=_},
63
64
  "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=_},
64
- }, "0a6f8c037f", {"index":"0a6f8c037f","src/bokeh/sources/data_pipe":"5108a98ed0","src/bokeh/util/conversions":"e3901fa9f2","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":"949501ff1c","src/bokeh/util/find":"44f332a4cc","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"5e5f767c53","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"}, {});});
65
+ }, "e2864cf297", {"index":"e2864cf297","src/bokeh/sources/data_pipe":"87aeec7876","src/bokeh/util/conversions":"e3901fa9f2","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":"389c724eb9","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"5e5f767c53","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"}, {});});
@@ -4,3 +4,4 @@ from ._edit_span import EditSpan
4
4
  from ._ev_text_input import EvTextInput
5
5
  from ._showable import Showable
6
6
  from ._shared_dict import SharedDict
7
+ from ._bokeh_app_context import BokehAppContext
@@ -0,0 +1,63 @@
1
+ import logging
2
+ from bokeh.core.properties import String, Dict, Any, Nullable, Instance
3
+ from bokeh.models.layouts import LayoutDOM
4
+ from bokeh.models.ui import UIElement
5
+ from uuid import uuid4
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+ class BokehAppContext(LayoutDOM):
10
+ """
11
+ Custom Bokeh model that bridges Python AppContext with JavaScript.
12
+ Initializes session-level data structure and app-specific state.
13
+ """
14
+ ui = Nullable(Instance(UIElement), help="""
15
+ A UI element, which can be plots, layouts, widgets, or any other UIElement.
16
+ """)
17
+
18
+ app_id = String(default="")
19
+ session_id = String(default="")
20
+ app_state = Dict(String, Any, default={})
21
+
22
+ # Class-level session ID shared across all apps in the same Python session
23
+ _session_id = None
24
+
25
+ @classmethod
26
+ def get_session_id(cls):
27
+ """Get or create a session ID for this Python session"""
28
+ if cls._session_id is None:
29
+ cls._session_id = str(uuid4())
30
+ return cls._session_id
31
+
32
+ def __init__( self, ui=None, **kwargs ):
33
+ logger.debug(f"\tBokehAppContext::__init__(ui={type(ui).__name__ if ui else None}, {kwargs}): {id(self)}")
34
+
35
+ if ui is not None and 'ui' in kwargs:
36
+ raise RuntimeError( "'ui' supplied as both a positional parameter and a keyword parameter" )
37
+
38
+ kwargs['session_id'] = self.get_session_id( )
39
+
40
+ if 'ui' not in kwargs:
41
+ kwargs['ui'] = ui
42
+ if 'app_id' not in kwargs:
43
+ kwargs['app_id'] = str(uuid4())
44
+
45
+ super().__init__(**kwargs)
46
+
47
+ def _sphinx_height_hint(self):
48
+ """Delegate height hint to the wrapped UI element"""
49
+ logger.debug(f"\tShowable::_sphinx_height_hint(): {id(self)}")
50
+ if self.ui and hasattr(self.ui, '_sphinx_height_hint'):
51
+ return self.ui._sphinx_height_hint()
52
+ return None
53
+
54
+ def update_app_state(self, state_updates):
55
+ """
56
+ Update the application state (will be in the generated HTML/JS)
57
+
58
+ Args:
59
+ state_updates: dict of state key-value pairs to update
60
+ """
61
+ current_state = dict(self.app_state)
62
+ current_state.update(state_updates)
63
+ self.app_state = current_state
@@ -36,13 +36,14 @@ import asyncio
36
36
  import traceback
37
37
  import time
38
38
  import json
39
+ from uuid import uuid4
39
40
 
40
41
  from bokeh.models.sources import DataSource
41
42
  from bokeh.util.compiler import TypeScript
42
- from bokeh.core.properties import Tuple, String, Int, Instance, Nullable
43
+ from bokeh.core.properties import Tuple, String, Int, Instance, Nullable, Bool
43
44
  from bokeh.models.callbacks import Callback
44
45
 
45
- from ...utils import serialize, deserialize
46
+ from ...utils import serialize, deserialize, is_interactive_jupyter
46
47
  from ..state import casalib_url, cubevisjs_url
47
48
  from .. import BokehInit
48
49
 
@@ -72,6 +73,10 @@ class DataPipe(DataSource,BokehInit):
72
73
 
73
74
  address = Tuple( String, Int, help="two integer sequence representing the address and port to use for the websocket" )
74
75
 
76
+ instance_id = String( help="Unique ID for each DataPipe object" )
77
+
78
+ conflict_check = Bool( default=True, help="Perform check to avoid reuse of URL for GUI. Not needed in the Jupyter context" )
79
+
75
80
  # Class-level session tracking to prevent multiple connections
76
81
  _active_sessions = {} # session_id -> {'websocket': ws, 'timestamp': time, 'datapipe': instance}
77
82
  _session_lock = threading.Lock()
@@ -82,7 +87,14 @@ class DataPipe(DataSource,BokehInit):
82
87
  #__javascript__ = [ casalib_url( ), cubevisjs_url( ) ]
83
88
 
84
89
  def __init__( self, *args, abort=None, **kwargs ):
90
+
91
+ if 'conflict_check' not in kwargs:
92
+ kwargs['conflict_check'] = not is_interactive_jupyter( )
93
+ if 'instance_id' not in kwargs:
94
+ kwargs['instance_id'] = str(uuid4( ))
95
+
85
96
  super( ).__init__( *args, **kwargs )
97
+
86
98
  self.__send_queue = { }
87
99
  self.__pending = { }
88
100
  self.__incoming_callbacks = { }
@@ -43,7 +43,7 @@ from bokeh.models.dom import HTML
43
43
  from bokeh.models.ui.tooltips import Tooltip
44
44
  from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter
45
45
  from cubevis.data import casaimage
46
- from cubevis.bokeh.models import TipButton, Tip
46
+ from cubevis.bokeh.models import TipButton, Tip, BokehAppContext
47
47
  from cubevis.utils import ContextMgrChain as CMC
48
48
 
49
49
  class CreateMask:
@@ -243,23 +243,7 @@ class CreateMask:
243
243
  ### If debugging this, make only a small change before confirming that exit from the
244
244
  ### Python asyncio loop continues to work... seems to be fiddly
245
245
  ###
246
- imdetails['gui']['cube'] = CubeMask( paths[0], mask=paths[1],
247
- init_script = None if initialization_registered else \
248
- CustomJS( args={ }, code='''
249
- window.addEventListener( 'beforeunload',
250
- (event) => {
251
- function donePromise( ) {
252
-
253
- return new Promise( (resolve,reject) => {
254
- // call by name does not work here:
255
- // document._cube_done(cb=resolve) ???
256
- if ( document._cube_done ) document._cube_done(null,resolve)
257
- } )
258
- }
259
- ( async () => { await donePromise( ) } )( )
260
- } )''' ) )
261
-
262
- initialization_registered = True
246
+ imdetails['gui']['cube'] = CubeMask( paths[0], mask=paths[1] )
263
247
  imdetails['image-channels'] = imdetails['gui']['cube'].shape( )[3]
264
248
 
265
249
 
@@ -276,6 +260,23 @@ class CreateMask:
276
260
  self._fig['status'] = imdetails['gui']['status'] = imdetails['gui']['cube'].status_text( "<p>initialization</p>" , width=230, reuse=self._fig['status'] )
277
261
  self._image_bitmask_controls = imdetails['gui']['cube'].bitmask_ctrl( reuse=self._image_bitmask_controls, button_type='light' )
278
262
 
263
+
264
+ ,
265
+ imdetails['gui']['cube'].init_script = None if initialization_registered else \
266
+ CustomJS( args={ 'status': self._fig['status'] },
267
+ ### app state is found based on one of the GUI's models
268
+ code='''const appstate = Bokeh.find.appState(status)
269
+ window.addEventListener( 'beforeunload',
270
+ (event) => {
271
+ function donePromise( ) {
272
+ return new Promise( (resolve,reject) => {
273
+ appstate?.cube_done?.(null,resolve)
274
+ } )
275
+ }
276
+ ( async () => { await donePromise( ) } )( )
277
+ } )''' )
278
+ initialization_registered = True
279
+
279
280
  ###
280
281
  ### spectrum plot must be disabled during iteration due to "tap to change channel" functionality
281
282
  ###
@@ -319,7 +320,8 @@ class CreateMask:
319
320
 
320
321
  self._image_control_tab_groups[imid] = result
321
322
  result.js_on_change( 'active', CustomJS( args={ },
322
- code='''document._casa_last_control_tab = cb_obj.active''' ) )
323
+ code='''const appstate = Bokeh.find.appState(cb_obj)
324
+ appstate.last_control_tab = cb_obj.active''' ) )
323
325
  return result
324
326
 
325
327
  def _create_image_panel( self, imagetuple ):
@@ -356,7 +358,8 @@ class CreateMask:
356
358
 
357
359
  self._ctrl_state['stop'].js_on_click( CustomJS( args={ },
358
360
  code='''if ( confirm( "Are you sure you want to end this mask creation session and close the GUI?" ) ) {
359
- if ( document._cube_done ) document._cube_done( )
361
+ const appstate = Bokeh.find.appState(cb_obj)
362
+ appstate?.cube_done?.( )
360
363
  }''' ) )
361
364
 
362
365
 
@@ -368,17 +371,21 @@ class CreateMask:
368
371
 
369
372
  image_tabs = Tabs( tabs=tab_panels, tabs_location='below', height_policy='max', width_policy='max' )
370
373
 
371
- self._fig['layout'] = column(
372
- row( self._fig['help'],
373
- Spacer( height=self._ctrl_state['stop'].height, sizing_mode="scale_width" ),
374
- Div( text="<div><b>status:</b></div>" ),
375
- self._fig['status'],
376
- self._ctrl_state['stop'], sizing_mode="scale_width" ),
377
- row( image_tabs, height_policy='max', width_policy='max' ),
378
- height_policy='max', width_policy='max' )
374
+ self._fig['layout'] = BokehAppContext(
375
+ column( row( self._fig['help'],
376
+ Spacer( height=self._ctrl_state['stop'].height, sizing_mode="scale_width" ),
377
+ Div( text="<div><b>status:</b></div>" ),
378
+ self._fig['status'],
379
+ self._ctrl_state['stop'], sizing_mode="scale_width" ),
380
+ row( image_tabs, height_policy='max', width_policy='max' ),
381
+ height_policy='max', width_policy='max' ),
382
+ app_state={ ### while the state dictionary itself
383
+ 'name': 'create mask', ### is used, these particular element
384
+ 'initialized': True ### are not currently used for anything
385
+ } )
379
386
 
380
387
  ###
381
- ### Keep track of which image is currently active in document._casa_image_name (which is
388
+ ### Keep track of which image is currently active in appstate.image_name (which is
382
389
  ### initialized in self._js['initialize']). Also, update the current control sub-tab
383
390
  ### when the field main-tab is changed. An attempt to manage this all within the
384
391
  ### control sub-tabs using a reference to self._image_control_tab_groups from
@@ -388,11 +395,12 @@ class CreateMask:
388
395
  ###
389
396
  image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._mask_state.items( ) ],
390
397
  itergroups=self._image_control_tab_groups ),
391
- code='''if ( ! hasprop(document,'_casa_last_control_tab') ) {
392
- document._casa_last_control_tab = 0
398
+ code='''const appstate = Bokeh.find.appState(cb_obj)
399
+ if ( ! hasprop(appstate,'last_control_tab') ) {
400
+ appstate.last_control_tab = 0
393
401
  }
394
- document._casa_image_name = names[cb_obj.active]
395
- itergroups[document._casa_image_name].active = document._casa_last_control_tab''' ) )
402
+ appstate.image_name = names[cb_obj.active]
403
+ itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
396
404
 
397
405
  # Change display type depending on runtime environment
398
406
  if is_interactive_jupyter( ):
@@ -43,7 +43,7 @@ from bokeh.models.dom import HTML
43
43
  from bokeh.models.ui.tooltips import Tooltip
44
44
  from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter
45
45
  from cubevis.data import casaimage
46
- from cubevis.bokeh.models import TipButton, Tip
46
+ from cubevis.bokeh.models import TipButton, Tip, BokehAppContext
47
47
  from cubevis.utils import ContextMgrChain as CMC
48
48
 
49
49
  class CreateRegion:
@@ -190,7 +190,7 @@ class CreateRegion:
190
190
 
191
191
  ###
192
192
  ### Use CubeMask init_script to set up a 'beforeunload' handler which will signal to
193
- ### CubeMask that the app is shuting down (with 'document._cube_done( )'). It should then
193
+ ### CubeMask that the app is shuting down (with 'appstate.cube_done( )'). It should then
194
194
  ### send the final results to Python and then call the provided callback (the Promise
195
195
  ### resolve function).
196
196
  ###
@@ -231,7 +231,8 @@ class CreateRegion:
231
231
  imdetails['gui']['slider'] = None
232
232
  imdetails['gui']['goto'] = None
233
233
 
234
- init_args = { 'sources': { } }
234
+ init_args = { 'status': self._fig['status'],
235
+ 'sources': { } }
235
236
  last_cube = None
236
237
  for k,v in self._region_state.items( ):
237
238
  init_args['sources'][k] = v['gui']['image']['src']
@@ -246,8 +247,9 @@ class CreateRegion:
246
247
  acc[src.id] = img
247
248
  if ( source == null ) source = src
248
249
  return acc }}, sources, {{ }} )
249
- if ( source && document._cube_done )
250
- document._cube_done(
250
+ const appstate = Bokeh.find.appState(status)
251
+ if ( source && appstate?.cube_done )
252
+ appstate.cube_done(
251
253
  casalib.reduce(
252
254
  (acc, poly) => {{
253
255
  acc[srcmap[poly.source.id]][poly.label] = {{
@@ -265,8 +267,8 @@ class CreateRegion:
265
267
  ## ImageDataSources (which is an element of CubeMask). This resulted in a circular
266
268
  ## reference when the plot was being rendered.
267
269
  ##
268
- ## The document._cube_done callback ( `(msg) => { resolve(true); return false }` ) can
269
- ## return `false` (indicating that the window should not be closed by _cube_done)
270
+ ## The appstate.cube_done callback ( `(msg) => { resolve(true); return false }` ) can
271
+ ## return `false` (indicating that the window should not be closed by cube_done)
270
272
  ## because the window is already being closed when this beforeunload callback
271
273
  ## is called.
272
274
  ##
@@ -385,7 +387,8 @@ class CreateRegion:
385
387
 
386
388
  self._image_control_tab_groups[imid] = result
387
389
  result.js_on_change( 'active', CustomJS( args=dict( ),
388
- code='''document._casa_last_control_tab = cb_obj.active''' ) )
390
+ code='''const appstate = Bokeh.find.appState(cb_obj)
391
+ appstate.last_control_tab = cb_obj.active''' ) )
389
392
  return result
390
393
 
391
394
  def _create_image_panel( self, imagetuple ):
@@ -421,17 +424,21 @@ class CreateRegion:
421
424
 
422
425
  image_tabs = Tabs( tabs=tab_panels, tabs_location='below', height_policy='max', width_policy='max' )
423
426
 
424
- self._fig['layout'] = column(
425
- row( self._fig['help'],
426
- Spacer( height=self._ctrl_state['stop'].height, sizing_mode="scale_width" ),
427
- Div( text="<div><b>status:</b></div>" ),
428
- self._fig['status'],
429
- self._ctrl_state['stop'], sizing_mode="scale_width" ),
430
- row( image_tabs, height_policy='max', width_policy='max' ),
431
- height_policy='max', width_policy='max' )
427
+ self._fig['layout'] = BokehAppContext(
428
+ column( row( self._fig['help'],
429
+ Spacer( height=self._ctrl_state['stop'].height, sizing_mode="scale_width" ),
430
+ Div( text="<div><b>status:</b></div>" ),
431
+ self._fig['status'],
432
+ self._ctrl_state['stop'], sizing_mode="scale_width" ),
433
+ row( image_tabs, height_policy='max', width_policy='max' ),
434
+ height_policy='max', width_policy='max' ),
435
+ app_state={ ### while the state dictionary itself
436
+ 'name': 'create region', ### is used, these particular element
437
+ 'initialized': True ### are not currently used for anything
438
+ } )
432
439
 
433
440
  ###
434
- ### Keep track of which image is currently active in document._casa_image_name (which is
441
+ ### Keep track of which image is currently active in appstate.image_name (which is
435
442
  ### initialized in self._js['initialize']). Also, update the current control sub-tab
436
443
  ### when the field main-tab is changed. An attempt to manage this all within the
437
444
  ### control sub-tabs using a reference to self._image_control_tab_groups from
@@ -441,11 +448,12 @@ class CreateRegion:
441
448
  ###
442
449
  image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._region_state.items( ) ],
443
450
  itergroups=self._image_control_tab_groups ),
444
- code='''if ( ! hasprop(document,'_casa_last_control_tab') ) {
445
- document._casa_last_control_tab = 0
451
+ code='''const appstate = Bokeh.find.appState(cb_obj)
452
+ if ( ! hasprop(appstate,'last_control_tab') ) {
453
+ appstate.last_control_tab = 0
446
454
  }
447
- document._casa_image_name = names[cb_obj.active]
448
- itergroups[document._casa_image_name].active = document._casa_last_control_tab''' ) )
455
+ appstate.image_name = names[cb_obj.active]
456
+ itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
449
457
 
450
458
  # Change display type depending on runtime environment
451
459
  if is_interactive_jupyter( ):