cubevis 1.0.14__py3-none-any.whl → 1.0.21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cubevis/__js__/bokeh-3.6/cubevisjs.min.js +13 -10
- cubevis/__js__/bokeh-3.7/cubevisjs.min.js +12 -8
- cubevis/__js__/bokeh-3.8/cubevisjs.min.js +10 -8
- cubevis/__version__.py +1 -1
- cubevis/bokeh/models/_bokeh_app_context.py +48 -1
- cubevis/bokeh/models/_showable.py +108 -82
- cubevis/exe/_task.py +36 -16
- cubevis/private/apps/_createmask.py +43 -41
- cubevis/private/apps/_createregion.py +31 -29
- cubevis/private/apps/_interactiveclean.mustache +2 -1
- cubevis/private/apps/_interactiveclean.py +2 -1
- cubevis/private/apps/_interactivecleannotebook.mustache +24 -1
- cubevis/private/apps/_interactivecleannotebook.py +24 -1
- cubevis/toolbox/__init__.py +0 -1
- cubevis/toolbox/_cube.py +40 -23
- cubevis/toolbox/_interactive_clean_ui.mustache +71 -44
- cubevis/toolbox/_interactive_clean_ui.py +71 -44
- cubevis/utils/__init__.py +1 -0
- cubevis/utils/_mutual_exclusion.py +117 -0
- {cubevis-1.0.14.dist-info → cubevis-1.0.21.dist-info}/METADATA +2 -2
- {cubevis-1.0.14.dist-info → cubevis-1.0.21.dist-info}/RECORD +23 -22
- {cubevis-1.0.14.dist-info → cubevis-1.0.21.dist-info}/WHEEL +0 -0
- {cubevis-1.0.14.dist-info → cubevis-1.0.21.dist-info}/licenses/LICENSE +0 -0
|
@@ -53,6 +53,7 @@ from cubevis.bokeh.models import TipButton, Tip, EvTextInput, BokehAppContext
|
|
|
53
53
|
|
|
54
54
|
from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter, find_pkg, load_pkg
|
|
55
55
|
from cubevis.utils import ContextMgrChain as CMC
|
|
56
|
+
from cubevis.utils import MutualExclusionManager
|
|
56
57
|
|
|
57
58
|
# pylint: disable=no-name-in-module
|
|
58
59
|
from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
|
|
@@ -61,7 +62,7 @@ from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
|
|
|
61
62
|
# pylint: enable=no-name-in-module
|
|
62
63
|
|
|
63
64
|
from cubevis.utils import find_ws_address, convert_masks
|
|
64
|
-
from cubevis.toolbox import CubeMask
|
|
65
|
+
from cubevis.toolbox import CubeMask
|
|
65
66
|
from cubevis.bokeh.utils import svg_icon
|
|
66
67
|
from cubevis.bokeh.sources import DataPipe
|
|
67
68
|
from cubevis.utils import DocEnum
|
|
@@ -74,6 +75,25 @@ USE_MULTIPLE_GCLEAN_HACK=False
|
|
|
74
75
|
class InteractiveCleanUI:
|
|
75
76
|
'''InteractiveCleanUI(...) implements interactive clean using Bokeh
|
|
76
77
|
'''
|
|
78
|
+
|
|
79
|
+
exclusion_mgr = MutualExclusionManager(
|
|
80
|
+
name="interactive clean",
|
|
81
|
+
valid_modes={
|
|
82
|
+
"tab": "❌ Cannot use iclean task display:\n\n" \
|
|
83
|
+
"Reason: bokeh.plotting.show() or iclean show method has already been\n" \
|
|
84
|
+
" used for display of this class. Mixing display methods within\n" \
|
|
85
|
+
" a single notebook corrupts Bokeh display within the notebook\n",
|
|
86
|
+
"cell-bokeh-show": "❌ Cannot use bokeh.plotting.show() display method:\n\n" \
|
|
87
|
+
"Reason: iclean show or task method has already been used for display\n" \
|
|
88
|
+
" of this class. Mixing display methods within a single notebook\n" \
|
|
89
|
+
" corrupts Bokeh display within the notebook\n",
|
|
90
|
+
"cell-custom-show": "❌ Cannot use iclean show method:\n\n" \
|
|
91
|
+
"Reason: bokeh.plotting.show() or task has already been used for display\n" \
|
|
92
|
+
" of this class. Mixing display methods within a single notebook\n" \
|
|
93
|
+
" corrupts Bokeh display within the notebook\n",
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
77
97
|
def __stop( self, _=None ):
|
|
78
98
|
self.__result_future.set_result(self.__retrieve_result( ))
|
|
79
99
|
|
|
@@ -164,11 +184,6 @@ class InteractiveCleanUI:
|
|
|
164
184
|
### the image display.
|
|
165
185
|
###
|
|
166
186
|
self._conv_spect_plot_width = 450
|
|
167
|
-
###
|
|
168
|
-
### Create application context (which includes a temporary directory).
|
|
169
|
-
### This sets the title of the plot.
|
|
170
|
-
###
|
|
171
|
-
self._app_state = AppContext( 'Interactive Clean' )
|
|
172
187
|
|
|
173
188
|
###
|
|
174
189
|
### Whether or not the Interactive Clean session is running remotely
|
|
@@ -302,11 +317,13 @@ class InteractiveCleanUI:
|
|
|
302
317
|
init_script=CustomJS( args=dict( initial_convergence_state=self._init_values["convergence_state"],
|
|
303
318
|
clean_ctrl=self._control['iteration'],
|
|
304
319
|
name=imid ),
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
clean_ctrl.
|
|
309
|
-
|
|
320
|
+
### save appstate as _appstate in image source for future access
|
|
321
|
+
code='''cb_obj.appstate.convergence_data = initial_convergence_state
|
|
322
|
+
cb_obj.origin._appstate = cb_obj.appstate
|
|
323
|
+
clean_ctrl.continue.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
324
|
+
clean_ctrl.finish.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
325
|
+
clean_ctrl.stop.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
326
|
+
cb_obj.origin.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
|
|
310
327
|
if idx == 0 else None )
|
|
311
328
|
|
|
312
329
|
###
|
|
@@ -678,7 +695,7 @@ class InteractiveCleanUI:
|
|
|
678
695
|
ctrl={ 'converge': self._clean['converge'] },
|
|
679
696
|
stopdescmap=ImagingDict.get_summaryminor_stopdesc( ) ),
|
|
680
697
|
code=self._js['update-converge'] +
|
|
681
|
-
'''update_convergence_single( img_state,
|
|
698
|
+
'''update_convergence_single( img_state, cb_obj._appstate.convergence_data.convergence[imid] )''' ) )
|
|
682
699
|
|
|
683
700
|
###
|
|
684
701
|
### collect toolbars for syncing selection
|
|
@@ -810,7 +827,8 @@ class InteractiveCleanUI:
|
|
|
810
827
|
logbutton=self._log_button,
|
|
811
828
|
stopdescmap=ImagingDict.get_summaryminor_stopdesc( )
|
|
812
829
|
),
|
|
813
|
-
code=
|
|
830
|
+
code="const appstate = Bokeh.find.appState(cb_obj.origin);" +
|
|
831
|
+
self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
|
|
814
832
|
self._js['clean-enable'] + self._js['clean-status-update'] +
|
|
815
833
|
self._js['iter-gui-update'] + self._js['clean-wait'] +
|
|
816
834
|
'''function invalid_niter( s ) {
|
|
@@ -859,11 +877,11 @@ class InteractiveCleanUI:
|
|
|
859
877
|
// { action: 'stop',
|
|
860
878
|
// value: { } },
|
|
861
879
|
// update_gui )
|
|
862
|
-
|
|
880
|
+
appstate.window_closed = true
|
|
863
881
|
/*** this will close the tab >>>>---------+ ***/
|
|
864
882
|
/*** | ***/
|
|
865
|
-
/***
|
|
866
|
-
|
|
883
|
+
/*** vvvvvvvvv-----------------------+ ***/
|
|
884
|
+
appstate.cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
|
|
867
885
|
}
|
|
868
886
|
} else if ( state.mode === 'continuous' &&
|
|
869
887
|
cb_obj.origin.name === 'stop' &&
|
|
@@ -942,13 +960,13 @@ class InteractiveCleanUI:
|
|
|
942
960
|
self._control['iteration']['stop'], self._control['iteration']['continue'], self._control['iteration']['finish'], sizing_mode="scale_width" ),
|
|
943
961
|
row( image_tabs, height_policy='max', width_policy='max' ),
|
|
944
962
|
height_policy='max', width_policy='max' ),
|
|
945
|
-
app_state={
|
|
946
|
-
'name': 'interactive clean',
|
|
947
|
-
'initialized': True
|
|
948
|
-
} )
|
|
963
|
+
app_state={ ### while the state dictionary itself
|
|
964
|
+
'name': 'interactive clean', ### is used, these particular element
|
|
965
|
+
'initialized': True ### are not currently used for anything
|
|
966
|
+
}, title='Interactive Clean' )
|
|
949
967
|
|
|
950
968
|
###
|
|
951
|
-
### Keep track of which image is currently active in
|
|
969
|
+
### Keep track of which image is currently active in appstate.image_name (which is
|
|
952
970
|
### initialized in self._js['initialize']). Also, update the current control sub-tab
|
|
953
971
|
### when the field main-tab is changed. An attempt to manage this all within the
|
|
954
972
|
### control sub-tabs using a reference to self._image_control_tab_groups from
|
|
@@ -956,13 +974,17 @@ class InteractiveCleanUI:
|
|
|
956
974
|
###
|
|
957
975
|
### bokeh.core.serialization.SerializationError: circular reference
|
|
958
976
|
###
|
|
977
|
+
### This set of tabs is the primary, outer tabs where each tab contains the complete
|
|
978
|
+
### set of image controls
|
|
979
|
+
###
|
|
959
980
|
image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._clean_targets.items( ) ],
|
|
960
981
|
itergroups=self._image_control_tab_groups ),
|
|
961
|
-
code='''
|
|
962
|
-
|
|
982
|
+
code='''const appstate = Bokeh.find.appState(cb_obj)
|
|
983
|
+
if ( ! hasprop(appstate,'last_control_tab') ) {
|
|
984
|
+
appstate.last_control_tab = 0
|
|
963
985
|
}
|
|
964
|
-
|
|
965
|
-
itergroups[
|
|
986
|
+
appstate.image_name = names[cb_obj.active]
|
|
987
|
+
itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
|
|
966
988
|
|
|
967
989
|
# Change display type depending on runtime environment
|
|
968
990
|
#if self._is_notebook:
|
|
@@ -1017,8 +1039,11 @@ class InteractiveCleanUI:
|
|
|
1017
1039
|
self._image_control_tab_groups = { }
|
|
1018
1040
|
|
|
1019
1041
|
self._image_control_tab_groups[imid] = result
|
|
1042
|
+
|
|
1043
|
+
### This set of tabs is the secondary, inner tabs for different controls for an individual image
|
|
1020
1044
|
result.js_on_change( 'active', CustomJS( args=dict( ),
|
|
1021
|
-
code='''
|
|
1045
|
+
code='''const appstate = Bokeh.find.appState(cb_obj)
|
|
1046
|
+
appstate.last_control_tab = cb_obj.active''' ) )
|
|
1022
1047
|
return result
|
|
1023
1048
|
|
|
1024
1049
|
def _create_image_panel( self, imagetuple ):
|
|
@@ -1285,20 +1310,22 @@ class InteractiveCleanUI:
|
|
|
1285
1310
|
|
|
1286
1311
|
def _initialize_javascript( self ):
|
|
1287
1312
|
self._js = { ### initialize state
|
|
1288
|
-
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1289
|
-
### --
|
|
1290
|
-
###
|
|
1291
|
-
|
|
1313
|
+
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1314
|
+
### -- "logbutton" is a random GUI model which can be used to locate the --
|
|
1315
|
+
### -- appstate that is used storing state --
|
|
1316
|
+
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1317
|
+
'initialize': '''const appstate = Bokeh.find.appState(logbutton)
|
|
1318
|
+
if ( ! appstate.ic_initialized ) {
|
|
1292
1319
|
console.log(`casalib version: ${casalib.version}`)
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1320
|
+
appstate.image_name = initial_image
|
|
1321
|
+
appstate.ic_initialized = true
|
|
1322
|
+
appstate.window_closed = false
|
|
1296
1323
|
window.addEventListener( 'beforeunload',
|
|
1297
1324
|
function (e) {
|
|
1298
1325
|
// if the window is already closed this message is never
|
|
1299
1326
|
// delivered (unless interactive clean is called again then
|
|
1300
1327
|
// the event shows up in the newly created control pipe)
|
|
1301
|
-
if (
|
|
1328
|
+
if ( appstate.window_closed == false ) {
|
|
1302
1329
|
ctrl_pipe.send( ids['stop'],
|
|
1303
1330
|
{ action: 'stop', value: { } },
|
|
1304
1331
|
undefined ) } } )
|
|
@@ -1374,13 +1401,13 @@ class InteractiveCleanUI:
|
|
|
1374
1401
|
|
|
1375
1402
|
function update_convergence( recurse=false ) {
|
|
1376
1403
|
let convdata
|
|
1377
|
-
if ( hasprop(
|
|
1378
|
-
convdata =
|
|
1404
|
+
if ( hasprop(appstate,'convergence_data') ) {
|
|
1405
|
+
convdata = appstate.convergence_data
|
|
1379
1406
|
} else {
|
|
1380
1407
|
if ( ! recurse ) {
|
|
1381
1408
|
ctrl.converge.pipe.send( ctrl.converge.id, { action: 'retrieve' },
|
|
1382
1409
|
(msg) => { if ( hasprop( msg.result, 'convergence' ) ) {
|
|
1383
|
-
|
|
1410
|
+
appstate.convergence_data = { convergence: msg.result.convergence,
|
|
1384
1411
|
cyclethreshold: msg.result.cyclethreshold }
|
|
1385
1412
|
update_convergence(true)
|
|
1386
1413
|
} } )
|
|
@@ -1415,8 +1442,8 @@ class InteractiveCleanUI:
|
|
|
1415
1442
|
}
|
|
1416
1443
|
|
|
1417
1444
|
if ( hasprop(clean_msg,'convergence') && clean_msg.convergence != null ) {
|
|
1418
|
-
|
|
1419
|
-
|
|
1445
|
+
appstate.convergence_data = { convergence: clean_msg.convergence,
|
|
1446
|
+
cyclethreshold: clean_msg.cyclethreshold }
|
|
1420
1447
|
}
|
|
1421
1448
|
}
|
|
1422
1449
|
|
|
@@ -1498,19 +1525,19 @@ class InteractiveCleanUI:
|
|
|
1498
1525
|
'Stopping criteria encountered',
|
|
1499
1526
|
'Unrecognized stop code' ]
|
|
1500
1527
|
if ( typeof status === 'number' ) {
|
|
1501
|
-
images_state[
|
|
1528
|
+
images_state[appstate.image_name]['status'].text =
|
|
1502
1529
|
'<p>' +
|
|
1503
1530
|
stopstr[ status < 0 || status >= stopstr.length ?
|
|
1504
1531
|
stopstr.length - 1 : status ] +
|
|
1505
1532
|
'</p>'
|
|
1506
1533
|
} else {
|
|
1507
|
-
images_state[
|
|
1534
|
+
images_state[appstate.image_name]['status'].text = `<p>${status}</p>`
|
|
1508
1535
|
}
|
|
1509
1536
|
}''',
|
|
1510
1537
|
|
|
1511
1538
|
'iter-gui-update': '''function get_update_dictionary( ) {
|
|
1512
|
-
//const amste = images_state[
|
|
1513
|
-
//const clste = images_state[
|
|
1539
|
+
//const amste = images_state[appstate.image_name]['automask']
|
|
1540
|
+
//const clste = images_state[appstate.image_name]['iteration']
|
|
1514
1541
|
// Assumption is that there is ONE set of iteration and automask updates
|
|
1515
1542
|
// for ALL imaging fields...
|
|
1516
1543
|
const amobj = Object.entries(images_state)[0][1].automask
|
|
@@ -1529,7 +1556,7 @@ class InteractiveCleanUI:
|
|
|
1529
1556
|
|
|
1530
1557
|
const masks = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.masks( ); return acc }, { } )
|
|
1531
1558
|
const breadcrumbs = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.breadcrumbs( ); return acc }, { } )
|
|
1532
|
-
return { iteration, automask, masks, breadcrumbs, current_image:
|
|
1559
|
+
return { iteration, automask, masks, breadcrumbs, current_image: appstate.image_name }
|
|
1533
1560
|
}
|
|
1534
1561
|
function update_log( log_lines ) {
|
|
1535
1562
|
let b = logbutton
|
|
@@ -52,6 +52,7 @@ from cubevis.bokeh.models import TipButton, Tip, EvTextInput, BokehAppContext
|
|
|
52
52
|
|
|
53
53
|
from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter, find_pkg, load_pkg
|
|
54
54
|
from cubevis.utils import ContextMgrChain as CMC
|
|
55
|
+
from cubevis.utils import MutualExclusionManager
|
|
55
56
|
|
|
56
57
|
# pylint: disable=no-name-in-module
|
|
57
58
|
from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
|
|
@@ -60,7 +61,7 @@ from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
|
|
|
60
61
|
# pylint: enable=no-name-in-module
|
|
61
62
|
|
|
62
63
|
from cubevis.utils import find_ws_address, convert_masks
|
|
63
|
-
from cubevis.toolbox import CubeMask
|
|
64
|
+
from cubevis.toolbox import CubeMask
|
|
64
65
|
from cubevis.bokeh.utils import svg_icon
|
|
65
66
|
from cubevis.bokeh.sources import DataPipe
|
|
66
67
|
from cubevis.utils import DocEnum
|
|
@@ -73,6 +74,25 @@ USE_MULTIPLE_GCLEAN_HACK=False
|
|
|
73
74
|
class InteractiveCleanUI:
|
|
74
75
|
'''InteractiveCleanUI(...) implements interactive clean using Bokeh
|
|
75
76
|
'''
|
|
77
|
+
|
|
78
|
+
exclusion_mgr = MutualExclusionManager(
|
|
79
|
+
name="interactive clean",
|
|
80
|
+
valid_modes={
|
|
81
|
+
"tab": "❌ Cannot use iclean task display:\n\n" \
|
|
82
|
+
"Reason: bokeh.plotting.show() or iclean show method has already been\n" \
|
|
83
|
+
" used for display of this class. Mixing display methods within\n" \
|
|
84
|
+
" a single notebook corrupts Bokeh display within the notebook\n",
|
|
85
|
+
"cell-bokeh-show": "❌ Cannot use bokeh.plotting.show() display method:\n\n" \
|
|
86
|
+
"Reason: iclean show or task method has already been used for display\n" \
|
|
87
|
+
" of this class. Mixing display methods within a single notebook\n" \
|
|
88
|
+
" corrupts Bokeh display within the notebook\n",
|
|
89
|
+
"cell-custom-show": "❌ Cannot use iclean show method:\n\n" \
|
|
90
|
+
"Reason: bokeh.plotting.show() or task has already been used for display\n" \
|
|
91
|
+
" of this class. Mixing display methods within a single notebook\n" \
|
|
92
|
+
" corrupts Bokeh display within the notebook\n",
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
76
96
|
def __stop( self, _=None ):
|
|
77
97
|
self.__result_future.set_result(self.__retrieve_result( ))
|
|
78
98
|
|
|
@@ -163,11 +183,6 @@ class InteractiveCleanUI:
|
|
|
163
183
|
### the image display.
|
|
164
184
|
###
|
|
165
185
|
self._conv_spect_plot_width = 450
|
|
166
|
-
###
|
|
167
|
-
### Create application context (which includes a temporary directory).
|
|
168
|
-
### This sets the title of the plot.
|
|
169
|
-
###
|
|
170
|
-
self._app_state = AppContext( 'Interactive Clean' )
|
|
171
186
|
|
|
172
187
|
###
|
|
173
188
|
### Whether or not the Interactive Clean session is running remotely
|
|
@@ -301,11 +316,13 @@ class InteractiveCleanUI:
|
|
|
301
316
|
init_script=CustomJS( args=dict( initial_convergence_state=self._init_values["convergence_state"],
|
|
302
317
|
clean_ctrl=self._control['iteration'],
|
|
303
318
|
name=imid ),
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
clean_ctrl.
|
|
308
|
-
|
|
319
|
+
### save appstate as _appstate in image source for future access
|
|
320
|
+
code='''cb_obj.appstate.convergence_data = initial_convergence_state
|
|
321
|
+
cb_obj.origin._appstate = cb_obj.appstate
|
|
322
|
+
clean_ctrl.continue.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
323
|
+
clean_ctrl.finish.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
324
|
+
clean_ctrl.stop.disable_add_sub = cb_obj.origin.disable_add_sub.values
|
|
325
|
+
cb_obj.origin.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
|
|
309
326
|
if idx == 0 else None )
|
|
310
327
|
|
|
311
328
|
###
|
|
@@ -677,7 +694,7 @@ class InteractiveCleanUI:
|
|
|
677
694
|
ctrl={ 'converge': self._clean['converge'] },
|
|
678
695
|
stopdescmap=ImagingDict.get_summaryminor_stopdesc( ) ),
|
|
679
696
|
code=self._js['update-converge'] +
|
|
680
|
-
'''update_convergence_single( img_state,
|
|
697
|
+
'''update_convergence_single( img_state, cb_obj._appstate.convergence_data.convergence[imid] )''' ) )
|
|
681
698
|
|
|
682
699
|
###
|
|
683
700
|
### collect toolbars for syncing selection
|
|
@@ -809,7 +826,8 @@ class InteractiveCleanUI:
|
|
|
809
826
|
logbutton=self._log_button,
|
|
810
827
|
stopdescmap=ImagingDict.get_summaryminor_stopdesc( )
|
|
811
828
|
),
|
|
812
|
-
code=
|
|
829
|
+
code="const appstate = Bokeh.find.appState(cb_obj.origin);" +
|
|
830
|
+
self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
|
|
813
831
|
self._js['clean-enable'] + self._js['clean-status-update'] +
|
|
814
832
|
self._js['iter-gui-update'] + self._js['clean-wait'] +
|
|
815
833
|
'''function invalid_niter( s ) {
|
|
@@ -858,11 +876,11 @@ class InteractiveCleanUI:
|
|
|
858
876
|
// { action: 'stop',
|
|
859
877
|
// value: { } },
|
|
860
878
|
// update_gui )
|
|
861
|
-
|
|
879
|
+
appstate.window_closed = true
|
|
862
880
|
/*** this will close the tab >>>>---------+ ***/
|
|
863
881
|
/*** | ***/
|
|
864
|
-
/***
|
|
865
|
-
|
|
882
|
+
/*** vvvvvvvvv-----------------------+ ***/
|
|
883
|
+
appstate.cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
|
|
866
884
|
}
|
|
867
885
|
} else if ( state.mode === 'continuous' &&
|
|
868
886
|
cb_obj.origin.name === 'stop' &&
|
|
@@ -941,13 +959,13 @@ class InteractiveCleanUI:
|
|
|
941
959
|
self._control['iteration']['stop'], self._control['iteration']['continue'], self._control['iteration']['finish'], sizing_mode="scale_width" ),
|
|
942
960
|
row( image_tabs, height_policy='max', width_policy='max' ),
|
|
943
961
|
height_policy='max', width_policy='max' ),
|
|
944
|
-
app_state={
|
|
945
|
-
'name': 'interactive clean',
|
|
946
|
-
'initialized': True
|
|
947
|
-
} )
|
|
962
|
+
app_state={ ### while the state dictionary itself
|
|
963
|
+
'name': 'interactive clean', ### is used, these particular element
|
|
964
|
+
'initialized': True ### are not currently used for anything
|
|
965
|
+
}, title='Interactive Clean' )
|
|
948
966
|
|
|
949
967
|
###
|
|
950
|
-
### Keep track of which image is currently active in
|
|
968
|
+
### Keep track of which image is currently active in appstate.image_name (which is
|
|
951
969
|
### initialized in self._js['initialize']). Also, update the current control sub-tab
|
|
952
970
|
### when the field main-tab is changed. An attempt to manage this all within the
|
|
953
971
|
### control sub-tabs using a reference to self._image_control_tab_groups from
|
|
@@ -955,13 +973,17 @@ class InteractiveCleanUI:
|
|
|
955
973
|
###
|
|
956
974
|
### bokeh.core.serialization.SerializationError: circular reference
|
|
957
975
|
###
|
|
976
|
+
### This set of tabs is the primary, outer tabs where each tab contains the complete
|
|
977
|
+
### set of image controls
|
|
978
|
+
###
|
|
958
979
|
image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._clean_targets.items( ) ],
|
|
959
980
|
itergroups=self._image_control_tab_groups ),
|
|
960
|
-
code='''
|
|
961
|
-
|
|
981
|
+
code='''const appstate = Bokeh.find.appState(cb_obj)
|
|
982
|
+
if ( ! hasprop(appstate,'last_control_tab') ) {
|
|
983
|
+
appstate.last_control_tab = 0
|
|
962
984
|
}
|
|
963
|
-
|
|
964
|
-
itergroups[
|
|
985
|
+
appstate.image_name = names[cb_obj.active]
|
|
986
|
+
itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
|
|
965
987
|
|
|
966
988
|
# Change display type depending on runtime environment
|
|
967
989
|
#if self._is_notebook:
|
|
@@ -1016,8 +1038,11 @@ class InteractiveCleanUI:
|
|
|
1016
1038
|
self._image_control_tab_groups = { }
|
|
1017
1039
|
|
|
1018
1040
|
self._image_control_tab_groups[imid] = result
|
|
1041
|
+
|
|
1042
|
+
### This set of tabs is the secondary, inner tabs for different controls for an individual image
|
|
1019
1043
|
result.js_on_change( 'active', CustomJS( args=dict( ),
|
|
1020
|
-
code='''
|
|
1044
|
+
code='''const appstate = Bokeh.find.appState(cb_obj)
|
|
1045
|
+
appstate.last_control_tab = cb_obj.active''' ) )
|
|
1021
1046
|
return result
|
|
1022
1047
|
|
|
1023
1048
|
def _create_image_panel( self, imagetuple ):
|
|
@@ -1284,20 +1309,22 @@ class InteractiveCleanUI:
|
|
|
1284
1309
|
|
|
1285
1310
|
def _initialize_javascript( self ):
|
|
1286
1311
|
self._js = { ### initialize state
|
|
1287
|
-
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1288
|
-
### --
|
|
1289
|
-
###
|
|
1290
|
-
|
|
1312
|
+
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1313
|
+
### -- "logbutton" is a random GUI model which can be used to locate the --
|
|
1314
|
+
### -- appstate that is used storing state --
|
|
1315
|
+
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1316
|
+
'initialize': '''const appstate = Bokeh.find.appState(logbutton)
|
|
1317
|
+
if ( ! appstate.ic_initialized ) {
|
|
1291
1318
|
console.log(`casalib version: ${casalib.version}`)
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1319
|
+
appstate.image_name = initial_image
|
|
1320
|
+
appstate.ic_initialized = true
|
|
1321
|
+
appstate.window_closed = false
|
|
1295
1322
|
window.addEventListener( 'beforeunload',
|
|
1296
1323
|
function (e) {
|
|
1297
1324
|
// if the window is already closed this message is never
|
|
1298
1325
|
// delivered (unless interactive clean is called again then
|
|
1299
1326
|
// the event shows up in the newly created control pipe)
|
|
1300
|
-
if (
|
|
1327
|
+
if ( appstate.window_closed == false ) {
|
|
1301
1328
|
ctrl_pipe.send( ids['stop'],
|
|
1302
1329
|
{ action: 'stop', value: { } },
|
|
1303
1330
|
undefined ) } } )
|
|
@@ -1373,13 +1400,13 @@ class InteractiveCleanUI:
|
|
|
1373
1400
|
|
|
1374
1401
|
function update_convergence( recurse=false ) {
|
|
1375
1402
|
let convdata
|
|
1376
|
-
if ( hasprop(
|
|
1377
|
-
convdata =
|
|
1403
|
+
if ( hasprop(appstate,'convergence_data') ) {
|
|
1404
|
+
convdata = appstate.convergence_data
|
|
1378
1405
|
} else {
|
|
1379
1406
|
if ( ! recurse ) {
|
|
1380
1407
|
ctrl.converge.pipe.send( ctrl.converge.id, { action: 'retrieve' },
|
|
1381
1408
|
(msg) => { if ( hasprop( msg.result, 'convergence' ) ) {
|
|
1382
|
-
|
|
1409
|
+
appstate.convergence_data = { convergence: msg.result.convergence,
|
|
1383
1410
|
cyclethreshold: msg.result.cyclethreshold }
|
|
1384
1411
|
update_convergence(true)
|
|
1385
1412
|
} } )
|
|
@@ -1414,8 +1441,8 @@ class InteractiveCleanUI:
|
|
|
1414
1441
|
}
|
|
1415
1442
|
|
|
1416
1443
|
if ( hasprop(clean_msg,'convergence') && clean_msg.convergence != null ) {
|
|
1417
|
-
|
|
1418
|
-
|
|
1444
|
+
appstate.convergence_data = { convergence: clean_msg.convergence,
|
|
1445
|
+
cyclethreshold: clean_msg.cyclethreshold }
|
|
1419
1446
|
}
|
|
1420
1447
|
}
|
|
1421
1448
|
|
|
@@ -1497,19 +1524,19 @@ class InteractiveCleanUI:
|
|
|
1497
1524
|
'Stopping criteria encountered',
|
|
1498
1525
|
'Unrecognized stop code' ]
|
|
1499
1526
|
if ( typeof status === 'number' ) {
|
|
1500
|
-
images_state[
|
|
1527
|
+
images_state[appstate.image_name]['status'].text =
|
|
1501
1528
|
'<p>' +
|
|
1502
1529
|
stopstr[ status < 0 || status >= stopstr.length ?
|
|
1503
1530
|
stopstr.length - 1 : status ] +
|
|
1504
1531
|
'</p>'
|
|
1505
1532
|
} else {
|
|
1506
|
-
images_state[
|
|
1533
|
+
images_state[appstate.image_name]['status'].text = `<p>${status}</p>`
|
|
1507
1534
|
}
|
|
1508
1535
|
}''',
|
|
1509
1536
|
|
|
1510
1537
|
'iter-gui-update': '''function get_update_dictionary( ) {
|
|
1511
|
-
//const amste = images_state[
|
|
1512
|
-
//const clste = images_state[
|
|
1538
|
+
//const amste = images_state[appstate.image_name]['automask']
|
|
1539
|
+
//const clste = images_state[appstate.image_name]['iteration']
|
|
1513
1540
|
// Assumption is that there is ONE set of iteration and automask updates
|
|
1514
1541
|
// for ALL imaging fields...
|
|
1515
1542
|
const amobj = Object.entries(images_state)[0][1].automask
|
|
@@ -1528,7 +1555,7 @@ class InteractiveCleanUI:
|
|
|
1528
1555
|
|
|
1529
1556
|
const masks = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.masks( ); return acc }, { } )
|
|
1530
1557
|
const breadcrumbs = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.breadcrumbs( ); return acc }, { } )
|
|
1531
|
-
return { iteration, automask, masks, breadcrumbs, current_image:
|
|
1558
|
+
return { iteration, automask, masks, breadcrumbs, current_image: appstate.image_name }
|
|
1532
1559
|
}
|
|
1533
1560
|
function update_log( log_lines ) {
|
|
1534
1561
|
let b = logbutton
|
cubevis/utils/__init__.py
CHANGED
|
@@ -67,6 +67,7 @@ from ._static import static_vars, static_dir
|
|
|
67
67
|
from ._tiles import TMSTiles
|
|
68
68
|
from ._contextmgrchain import ContextMgrChain
|
|
69
69
|
from ._import_protected_module import ImportProtectedModule
|
|
70
|
+
from ._mutual_exclusion import MutualExclusionManager
|
|
70
71
|
|
|
71
72
|
@static_vars(mgr=None)
|
|
72
73
|
def resource_manager( ):
|