cubevis 0.5.23__py3-none-any.whl → 0.5.25__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.
Potentially problematic release.
This version of cubevis might be problematic. Click here for more details.
- cubevis/__js__/cubevisjs.min.js +3 -2
- cubevis/__version__.py +1 -1
- cubevis/bokeh/models/__init__.py +1 -0
- cubevis/bokeh/models/_shared_dict.py +23 -0
- cubevis/toolbox/_cube.py +58 -16
- cubevis/toolbox/_interactive_clean_ui.mustache +239 -91
- cubevis/toolbox/_interactive_clean_ui.py +239 -91
- {cubevis-0.5.23.dist-info → cubevis-0.5.25.dist-info}/METADATA +1 -1
- {cubevis-0.5.23.dist-info → cubevis-0.5.25.dist-info}/RECORD +11 -10
- {cubevis-0.5.23.dist-info → cubevis-0.5.25.dist-info}/WHEEL +0 -0
- {cubevis-0.5.23.dist-info → cubevis-0.5.25.dist-info}/licenses/LICENSE +0 -0
|
@@ -44,12 +44,13 @@ import asyncio
|
|
|
44
44
|
import shutil
|
|
45
45
|
import websockets
|
|
46
46
|
from os.path import basename, abspath, exists, join
|
|
47
|
+
import numpy as np
|
|
47
48
|
from uuid import uuid4
|
|
48
49
|
from html import escape as html_escape
|
|
49
50
|
from contextlib import asynccontextmanager
|
|
50
51
|
from bokeh.models import Button, TextInput, Checkbox, Div, LinearAxis, CustomJS, Spacer, Span, HoverTool, DataRange1d, Step, InlineStyleSheet
|
|
51
52
|
from bokeh.events import ModelEvent, MouseEnter
|
|
52
|
-
from bokeh.models import TabPanel, Tabs
|
|
53
|
+
from bokeh.models import TabPanel, Tabs, Range1d
|
|
53
54
|
from bokeh.plotting import ColumnDataSource, figure, show
|
|
54
55
|
from bokeh.layouts import column, row, layout
|
|
55
56
|
from bokeh.io import reset_output as reset_bokeh_output, output_notebook
|
|
@@ -277,6 +278,23 @@ class InteractiveCleanUI:
|
|
|
277
278
|
imdetails['path']['residual'] = join( output_dir, self._clean['gclean_paths'][imid]['residualname'] )
|
|
278
279
|
imdetails['path']['mask'] = join( output_dir, self._clean['gclean_paths'][imid]['maskname'] )
|
|
279
280
|
|
|
281
|
+
###
|
|
282
|
+
### There is one set of tclean controls for all images/outlier/etc. because
|
|
283
|
+
### in the final version gclean will handle the iterations for all fields...
|
|
284
|
+
###
|
|
285
|
+
cwidth = 64
|
|
286
|
+
cheight = 40
|
|
287
|
+
self._control['iteration'] = { }
|
|
288
|
+
self._control['iteration']['continue'] = TipButton( max_width=cwidth, max_height=cheight, name='continue',
|
|
289
|
+
icon=svg_icon(icon_name="iclean-continue", size=18),
|
|
290
|
+
tooltip=Tooltip( content=HTML( '''Stop after <b>one major cycle</b> or when any stopping criteria is met.''' ), position='left') )
|
|
291
|
+
self._control['iteration']['finish'] = TipButton( max_width=cwidth, max_height=cheight, name='finish',
|
|
292
|
+
icon=svg_icon(icon_name="iclean-finish", size=18),
|
|
293
|
+
tooltip=Tooltip( content=HTML( '''<b>Continue</b> until some stopping criteria is met.''' ), position='left') )
|
|
294
|
+
self._control['iteration']['stop'] = TipButton( button_type="danger", max_width=cwidth, max_height=cheight, name='stop',
|
|
295
|
+
icon=svg_icon(icon_name="iclean-stop", size=18),
|
|
296
|
+
tooltip=Tooltip( content=HTML( '''<p>Clicking a <font color="red">red</font> stop button will cause this tab to close and control will return to Python.<p>Clicking an <font color="orange">orange</font> stop button will cause <tt>tclean</tt> to stop after the current major cycle.''' ), position='left' ) )
|
|
297
|
+
|
|
280
298
|
for idx, (imid, imdetails) in enumerate(self._clean_targets.items( )):
|
|
281
299
|
imdetails['gui'] = { }
|
|
282
300
|
|
|
@@ -289,8 +307,13 @@ class InteractiveCleanUI:
|
|
|
289
307
|
###
|
|
290
308
|
imdetails['gui']['cube'] = CubeMask( imdetails['path']['residual'], mask=imdetails['path']['mask'], abort=self._abort_handler,
|
|
291
309
|
init_script=CustomJS( args=dict( initial_convergence_state=self._init_values["convergence_state"],
|
|
310
|
+
clean_ctrl=self._control['iteration'],
|
|
292
311
|
name=imid ),
|
|
293
|
-
code='''document._casa_convergence_data = initial_convergence_state
|
|
312
|
+
code='''document._casa_convergence_data = initial_convergence_state
|
|
313
|
+
clean_ctrl.continue.disable_add_sub = this.disable_add_sub.values
|
|
314
|
+
clean_ctrl.finish.disable_add_sub = this.disable_add_sub.values
|
|
315
|
+
clean_ctrl.stop.disable_add_sub = this.disable_add_sub.values
|
|
316
|
+
this.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
|
|
294
317
|
if idx == 0 else None )
|
|
295
318
|
|
|
296
319
|
###
|
|
@@ -342,57 +365,159 @@ class InteractiveCleanUI:
|
|
|
342
365
|
</div>'''
|
|
343
366
|
|
|
344
367
|
hover = HoverTool( tooltips=TOOLTIPS )
|
|
345
|
-
imdetails['gui']['convergence'] = figure( sizing_mode=sizing_mode, y_axis_location="right",
|
|
346
|
-
tools=[ hover ], toolbar_location=None, **kw )
|
|
347
368
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
###
|
|
370
|
+
### Data source that will be used for updating the convergence plot
|
|
371
|
+
###
|
|
372
|
+
stokes = 0
|
|
373
|
+
convergence = imdetails['converge']['chan'][0][stokes]
|
|
374
|
+
imdetails['converge-data'] = { }
|
|
375
|
+
imdetails['converge-data']['flux'] = ColumnDataSource( data=dict( values=convergence['modelFlux'], iterations=convergence['iterations'],
|
|
376
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
377
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
378
|
+
type=['flux'] * len(convergence['iterations']) ) )
|
|
379
|
+
imdetails['converge-data']['residual'] = ColumnDataSource( data=dict( values=convergence['peakRes'], iterations=convergence['iterations'],
|
|
380
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
381
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
382
|
+
type=['residual'] * len(convergence['iterations'])) )
|
|
383
|
+
imdetails['converge-data']['cyclethreshold'] = ColumnDataSource( data=dict( values=convergence['cycleThresh'], iterations=convergence['iterations'] ) )
|
|
384
|
+
|
|
385
|
+
# Calculate explicit ranges for each dataset
|
|
386
|
+
flux_values = convergence['modelFlux']
|
|
387
|
+
residual_values = convergence['peakRes']
|
|
388
|
+
iterations = convergence['iterations']
|
|
389
|
+
cyclethresh_values = convergence['cycleThresh']
|
|
390
|
+
|
|
391
|
+
# Calculate ranges with padding
|
|
392
|
+
if len(flux_values) > 0:
|
|
393
|
+
flux_min, flux_max = np.min(flux_values), np.max(flux_values)
|
|
394
|
+
flux_padding = max((flux_max - flux_min) * 0.1, abs(flux_max * 0.05)) if flux_max != flux_min else abs(flux_max * 0.1)
|
|
395
|
+
else:
|
|
396
|
+
flux_min, flux_max, flux_padding = 0, 1, 0.1
|
|
371
397
|
|
|
398
|
+
if len(residual_values) > 0:
|
|
399
|
+
residual_min, residual_max = np.min(residual_values), np.max(residual_values)
|
|
400
|
+
residual_padding = max((residual_max - residual_min) * 0.1, abs(residual_max * 0.05)) if residual_max != residual_min else abs(residual_max * 0.1)
|
|
372
401
|
else:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
402
|
+
residual_min, residual_max, residual_padding = 0, 1, 0.1
|
|
403
|
+
|
|
404
|
+
# Create Range1d objects
|
|
405
|
+
flux_range = Range1d(start=flux_min - flux_padding, end=flux_max + flux_padding)
|
|
406
|
+
residual_range = Range1d(start=residual_min - residual_padding, end=residual_max + residual_padding)
|
|
407
|
+
|
|
408
|
+
# Ensure ranges are valid (non-zero span)
|
|
409
|
+
if flux_range.end - flux_range.start < 1e-10:
|
|
410
|
+
center = flux_range.start
|
|
411
|
+
if abs(center) < 1e-10: # If center is essentially 0
|
|
412
|
+
flux_range.start = -0.1
|
|
413
|
+
flux_range.end = 1.0
|
|
414
|
+
else:
|
|
415
|
+
span = max(abs(center * 0.2), 0.1)
|
|
416
|
+
flux_range.start = center - span
|
|
417
|
+
flux_range.end = center + span
|
|
418
|
+
|
|
419
|
+
if residual_range.end - residual_range.start < 1e-10:
|
|
420
|
+
center = residual_range.start
|
|
421
|
+
span = max(abs(center * 0.2), 0.1)
|
|
422
|
+
residual_range.start = center - span
|
|
423
|
+
residual_range.end = center + span
|
|
424
|
+
|
|
425
|
+
# ORIENTATION CONFIGURATION - this eliminates the conditional branches
|
|
426
|
+
config = {
|
|
427
|
+
'vertical': {
|
|
428
|
+
'iteration_axis': 'y',
|
|
429
|
+
'data_axis': 'x',
|
|
430
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
431
|
+
'residual_axis_label': 'Peak Residual',
|
|
432
|
+
'flux_axis_label': 'Total Flux',
|
|
433
|
+
'residual_axis_pos': 'above',
|
|
434
|
+
'flux_axis_pos': 'above',
|
|
435
|
+
'extra_ranges_key': 'extra_x_ranges',
|
|
436
|
+
'glyph_coords': ('values', 'iterations'), # (x, y)
|
|
437
|
+
'range_name_param': 'x_range_name'
|
|
438
|
+
},
|
|
439
|
+
'horizontal': {
|
|
440
|
+
'iteration_axis': 'x',
|
|
441
|
+
'data_axis': 'y',
|
|
442
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
443
|
+
'residual_axis_label': 'Peak Residual',
|
|
444
|
+
'flux_axis_label': 'Total Flux',
|
|
445
|
+
'residual_axis_pos': 'right',
|
|
446
|
+
'flux_axis_pos': 'right',
|
|
447
|
+
'extra_ranges_key': 'extra_y_ranges',
|
|
448
|
+
'glyph_coords': ('iterations', 'values'), # (x, y)
|
|
449
|
+
'range_name_param': 'y_range_name'
|
|
450
|
+
}
|
|
451
|
+
}
|
|
395
452
|
|
|
453
|
+
cfg = config[orient]
|
|
454
|
+
|
|
455
|
+
# Create figure with no default axes; to control the axes they must
|
|
456
|
+
# be explicitly set to None
|
|
457
|
+
imdetails['gui']['convergence'] = figure( sizing_mode=sizing_mode,
|
|
458
|
+
x_axis_location=None, y_axis_location=None,
|
|
459
|
+
tools=[ hover ], toolbar_location=None, **kw )
|
|
460
|
+
|
|
461
|
+
# Set up extra ranges
|
|
462
|
+
setattr(imdetails['gui']['convergence'], cfg['extra_ranges_key'], {
|
|
463
|
+
'residual_range': residual_range,
|
|
464
|
+
'flux_range': flux_range
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
# Store references for JavaScript updates
|
|
468
|
+
imdetails['converge-ranges'] = {
|
|
469
|
+
'residual_range': residual_range,
|
|
470
|
+
'flux_range': flux_range
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
# Create main iteration axis
|
|
474
|
+
main_axis = LinearAxis(axis_label=cfg['main_axis_label'])
|
|
475
|
+
main_axis_pos = 'below' if cfg['iteration_axis'] == 'x' else 'left'
|
|
476
|
+
imdetails['gui']['convergence'].add_layout(main_axis, main_axis_pos)
|
|
477
|
+
|
|
478
|
+
# Create glyphs using configuration
|
|
479
|
+
x_coord, y_coord = cfg['glyph_coords']
|
|
480
|
+
range_param = {cfg['range_name_param']: 'residual_range'}
|
|
481
|
+
|
|
482
|
+
imdetails['gui']['convergence'].step( x_coord, y_coord, source=imdetails['converge-data']['cyclethreshold'],
|
|
483
|
+
line_color='red', line_dash='dotted', line_width=2, **range_param )
|
|
484
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
485
|
+
line_color=self._converge_color['residual'], **range_param )
|
|
486
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
487
|
+
color=self._converge_color['residual'], size=10, **range_param )
|
|
488
|
+
|
|
489
|
+
# Flux glyphs
|
|
490
|
+
range_param = {cfg['range_name_param']: 'flux_range'}
|
|
491
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
492
|
+
line_color=self._converge_color['flux'], **range_param )
|
|
493
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
494
|
+
color=self._converge_color['flux'], size=10, **range_param )
|
|
495
|
+
|
|
496
|
+
# Create and style residual axis
|
|
497
|
+
residual_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'residual_range'}
|
|
498
|
+
residual_axis = LinearAxis(axis_label=cfg['residual_axis_label'], **residual_axis_param)
|
|
499
|
+
residual_axis.axis_line_color = self._converge_color['residual']
|
|
500
|
+
residual_axis.major_label_text_color = self._converge_color['residual']
|
|
501
|
+
residual_axis.axis_label_text_color = self._converge_color['residual']
|
|
502
|
+
residual_axis.major_tick_line_color = self._converge_color['residual']
|
|
503
|
+
residual_axis.minor_tick_line_color = self._converge_color['residual']
|
|
504
|
+
imdetails['gui']['convergence'].add_layout(residual_axis, cfg['residual_axis_pos'])
|
|
505
|
+
|
|
506
|
+
# Create and style flux axis
|
|
507
|
+
flux_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'flux_range'}
|
|
508
|
+
flux_axis = LinearAxis(axis_label=cfg['flux_axis_label'], **flux_axis_param)
|
|
509
|
+
flux_axis.axis_line_color = self._converge_color['flux']
|
|
510
|
+
flux_axis.major_label_text_color = self._converge_color['flux']
|
|
511
|
+
flux_axis.axis_label_text_color = self._converge_color['flux']
|
|
512
|
+
flux_axis.major_tick_line_color = self._converge_color['flux']
|
|
513
|
+
flux_axis.minor_tick_line_color = self._converge_color['flux']
|
|
514
|
+
imdetails['gui']['convergence'].add_layout(flux_axis, cfg['flux_axis_pos'])
|
|
515
|
+
|
|
516
|
+
# Store axis references for JavaScript access
|
|
517
|
+
imdetails['converge-axes'] = {
|
|
518
|
+
'residual_axis': residual_axis,
|
|
519
|
+
'flux_axis': flux_axis
|
|
520
|
+
}
|
|
396
521
|
|
|
397
522
|
def _launch_gui( self ):
|
|
398
523
|
'''create and show GUI
|
|
@@ -484,24 +609,6 @@ class InteractiveCleanUI:
|
|
|
484
609
|
#print("%s: %s" % ( btn, self._clean_ids[btn] ) )
|
|
485
610
|
self._pipe['control'].register( self._clean_ids[btn], clean_handler )
|
|
486
611
|
|
|
487
|
-
|
|
488
|
-
###
|
|
489
|
-
### There is one set of tclean controls for all images/outlier/etc. because
|
|
490
|
-
### in the final version gclean will handle the iterations for all fields...
|
|
491
|
-
###
|
|
492
|
-
cwidth = 64
|
|
493
|
-
cheight = 40
|
|
494
|
-
self._control['iteration'] = { }
|
|
495
|
-
self._control['iteration']['continue'] = TipButton( max_width=cwidth, max_height=cheight, name='continue',
|
|
496
|
-
icon=svg_icon(icon_name="iclean-continue", size=18),
|
|
497
|
-
tooltip=Tooltip( content=HTML( '''Stop after <b>one major cycle</b> or when any stopping criteria is met.''' ), position='left') )
|
|
498
|
-
self._control['iteration']['finish'] = TipButton( max_width=cwidth, max_height=cheight, name='finish',
|
|
499
|
-
icon=svg_icon(icon_name="iclean-finish", size=18),
|
|
500
|
-
tooltip=Tooltip( content=HTML( '''<b>Continue</b> until some stopping criteria is met.''' ), position='left') )
|
|
501
|
-
self._control['iteration']['stop'] = TipButton( button_type="danger", max_width=cwidth, max_height=cheight, name='stop',
|
|
502
|
-
icon=svg_icon(icon_name="iclean-stop", size=18),
|
|
503
|
-
tooltip=Tooltip( content=HTML( '''<p>Clicking a <font color="red">red</font> stop button will cause this tab to close and control will return to Python.<p>Clicking an <font color="orange">orange</font> stop button will cause <tt>tclean</tt> to stop after the current major cycle.''' ), position='left' ) )
|
|
504
|
-
|
|
505
612
|
###
|
|
506
613
|
### The single SHARED help button will be supplied by the first CubeMask...
|
|
507
614
|
###
|
|
@@ -533,23 +640,6 @@ class InteractiveCleanUI:
|
|
|
533
640
|
|
|
534
641
|
self._clean['converge']['pipe'].register( self._clean['converge']['id'], convergence_handler )
|
|
535
642
|
|
|
536
|
-
###
|
|
537
|
-
### Data source that will be used for updating the convergence plot
|
|
538
|
-
###
|
|
539
|
-
stokes = 0
|
|
540
|
-
convergence = imdetails['converge']['chan'][0][stokes]
|
|
541
|
-
imdetails['converge-data'] = { }
|
|
542
|
-
imdetails['converge-data']['flux'] = ColumnDataSource( data=dict( values=convergence['modelFlux'], iterations=convergence['iterations'],
|
|
543
|
-
cyclethreshold=convergence['cycleThresh'],
|
|
544
|
-
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
545
|
-
type=['flux'] * len(convergence['iterations']) ) )
|
|
546
|
-
imdetails['converge-data']['residual'] = ColumnDataSource( data=dict( values=convergence['peakRes'], iterations=convergence['iterations'],
|
|
547
|
-
cyclethreshold=convergence['cycleThresh'],
|
|
548
|
-
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
549
|
-
type=['residual'] * len(convergence['iterations'])) )
|
|
550
|
-
imdetails['converge-data']['cyclethreshold'] = ColumnDataSource( data=dict( values=convergence['cycleThresh'], iterations=convergence['iterations'] ) )
|
|
551
|
-
|
|
552
|
-
|
|
553
643
|
###
|
|
554
644
|
### help page for cube interactions
|
|
555
645
|
###
|
|
@@ -584,8 +674,12 @@ class InteractiveCleanUI:
|
|
|
584
674
|
imdetails['gui']['image']['src'] = imdetails['gui']['cube'].js_obj( )
|
|
585
675
|
imdetails['gui']['image']['fig'] = imdetails['gui']['cube'].image( grid=False, height_policy='max', width_policy='max',
|
|
586
676
|
channelcb=CustomJS( args=dict( img_state={ 'src': imdetails['gui']['image']['src'],
|
|
587
|
-
'flux': imdetails['converge-data']['flux'],
|
|
588
|
-
|
|
677
|
+
'flux': { 'source': imdetails['converge-data']['flux'],
|
|
678
|
+
'axis': imdetails['converge-axes']['flux_axis'],
|
|
679
|
+
'range': imdetails['converge-ranges']['flux_range'] },
|
|
680
|
+
'residual': { 'source': imdetails['converge-data']['residual'],
|
|
681
|
+
'axis': imdetails['converge-axes']['residual_axis'],
|
|
682
|
+
'range': imdetails['converge-ranges']['residual_range'] },
|
|
589
683
|
'cyclethreshold': imdetails['converge-data']['cyclethreshold'] },
|
|
590
684
|
imid=imid,
|
|
591
685
|
ctrl={ 'converge': self._clean['converge'] },
|
|
@@ -694,6 +788,7 @@ class InteractiveCleanUI:
|
|
|
694
788
|
margin=(-1, 0, -10, 0), button_type='light',
|
|
695
789
|
stylesheets=[ InlineStyleSheet( css='''.bk-btn { border: 0px solid #ccc; padding: 0 var(--padding-vertical) var(--padding-horizontal); margin-top: 3px; }''' ) ] )
|
|
696
790
|
|
|
791
|
+
|
|
697
792
|
self._control['iteration']['cb'] = CustomJS( args=dict( images_state={ k: { 'status': v['gui']['stopcode'],
|
|
698
793
|
'automask': v['gui']['params']['automask'],
|
|
699
794
|
'iteration': v['gui']['params']['iteration'],
|
|
@@ -701,9 +796,13 @@ class InteractiveCleanUI:
|
|
|
701
796
|
'src': v['gui']['cube'].js_obj( ),
|
|
702
797
|
'spectrum': v['gui']['spectrum'],
|
|
703
798
|
'src': v['gui']['image']['src'],
|
|
704
|
-
'flux': v['converge-data']['flux'],
|
|
799
|
+
'flux': { 'source': v['converge-data']['flux'],
|
|
800
|
+
'axis': v['converge-axes']['flux_axis'],
|
|
801
|
+
'range': v['converge-ranges']['flux_range'] },
|
|
705
802
|
'cyclethreshold': v['converge-data']['cyclethreshold'],
|
|
706
|
-
'residual': v['converge-data']['residual'],
|
|
803
|
+
'residual': { 'source': v['converge-data']['residual'],
|
|
804
|
+
'axis': v['converge-axes']['residual_axis'],
|
|
805
|
+
'range': v['converge-ranges']['residual_range'] },
|
|
707
806
|
'navi': { 'slider': v['gui']['slider'],
|
|
708
807
|
'goto': v['gui']['goto'],
|
|
709
808
|
## it doesn't seem like pixel tracking must be disabled
|
|
@@ -1215,7 +1314,52 @@ class InteractiveCleanUI:
|
|
|
1215
1314
|
### -- The "Insert here ..." code seems to be called when when the stokes plane is changed --
|
|
1216
1315
|
### -- but there have been no tclean iterations yet... --
|
|
1217
1316
|
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1218
|
-
'update-converge': '''function
|
|
1317
|
+
'update-converge': '''function updateAxisRange(source, range_obj, axis_obj, axis_name) {
|
|
1318
|
+
const data = source.data;
|
|
1319
|
+
const values = data['values'];
|
|
1320
|
+
|
|
1321
|
+
if (values.length === 0) return;
|
|
1322
|
+
|
|
1323
|
+
// Calculate data bounds
|
|
1324
|
+
const min_val = Math.min(...values);
|
|
1325
|
+
const max_val = Math.max(...values);
|
|
1326
|
+
|
|
1327
|
+
// Add padding (10% of range, with minimum padding)
|
|
1328
|
+
const span = max_val - min_val;
|
|
1329
|
+
const padding = max_val != min_val ? Math.max(span * 0.1, Math.abs(max_val * 0.02)) : Math.abs(max_val * 0.1);
|
|
1330
|
+
|
|
1331
|
+
// Update range
|
|
1332
|
+
range_obj.start = min_val - padding;
|
|
1333
|
+
range_obj.end = max_val + padding;
|
|
1334
|
+
|
|
1335
|
+
// Ensure ranges are valid (non-zero span)
|
|
1336
|
+
if ( range_obj.end - range_obj.start < 1e-10 ) {
|
|
1337
|
+
const center = range_obj.start
|
|
1338
|
+
if ( Math.abs(center) < 1e-10 ) {
|
|
1339
|
+
// If center is essentially 0
|
|
1340
|
+
range_obj.start = -0.1
|
|
1341
|
+
range_obj.end = 1.0
|
|
1342
|
+
} else {
|
|
1343
|
+
const span = Math.max(Math.abs(center * 0.2), 0.1)
|
|
1344
|
+
range_obj.start = center - span
|
|
1345
|
+
range_obj.end = center + span
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Optional: Update tick density
|
|
1350
|
+
if (axis_obj && axis_obj.ticker) {
|
|
1351
|
+
const new_span = range_obj.end - range_obj.start;
|
|
1352
|
+
if (new_span < 10) {
|
|
1353
|
+
axis_obj.ticker.desired_num_ticks = 8;
|
|
1354
|
+
} else if (new_span < 100) {
|
|
1355
|
+
axis_obj.ticker.desired_num_ticks = 10;
|
|
1356
|
+
} else {
|
|
1357
|
+
axis_obj.ticker.desired_num_ticks = 6;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
function update_convergence_single( target, data ) {
|
|
1219
1363
|
const pos = target.src.cur_chan
|
|
1220
1364
|
const imdata = data.get(pos[1]).get(pos[0])
|
|
1221
1365
|
// chan----------------^^^^^^ ^^^^^^----stokes
|
|
@@ -1225,9 +1369,11 @@ class InteractiveCleanUI:
|
|
|
1225
1369
|
const modelFlux = imdata.modelFlux
|
|
1226
1370
|
const stopCode = imdata.stopCode
|
|
1227
1371
|
const stopDesc = imdata.stopCode.map( code => stopdescmap.has(code) ? stopdescmap.get(code): "" )
|
|
1228
|
-
target.residual.data = { iterations, cyclethreshold, stopDesc, values: peakRes, type: Array(iterations.length).fill('residual') }
|
|
1229
|
-
target.flux.data = { iterations, cyclethreshold, stopDesc, values: modelFlux, type: Array(iterations.length).fill('flux') }
|
|
1372
|
+
target.residual.source.data = { iterations, cyclethreshold, stopDesc, values: peakRes, type: Array(iterations.length).fill('residual') }
|
|
1373
|
+
target.flux.source.data = { iterations, cyclethreshold, stopDesc, values: modelFlux, type: Array(iterations.length).fill('flux') }
|
|
1230
1374
|
target.cyclethreshold.data = { iterations, values: cyclethreshold }
|
|
1375
|
+
updateAxisRange( target.flux.source, target.flux.range, target.flux.axis, 'Flux' )
|
|
1376
|
+
updateAxisRange( target.residual.source, target.residual.range, target.residual.axis, 'Residual' )
|
|
1231
1377
|
}
|
|
1232
1378
|
|
|
1233
1379
|
function update_convergence( recurse=false ) {
|
|
@@ -1311,6 +1457,7 @@ class InteractiveCleanUI:
|
|
|
1311
1457
|
)
|
|
1312
1458
|
}
|
|
1313
1459
|
)
|
|
1460
|
+
clean_ctrl.continue.disable_add_sub.disabled = true
|
|
1314
1461
|
clean_ctrl.continue.disabled = true
|
|
1315
1462
|
clean_ctrl.finish.disabled = true
|
|
1316
1463
|
clean_ctrl.stop.disabled = with_stop
|
|
@@ -1335,6 +1482,7 @@ class InteractiveCleanUI:
|
|
|
1335
1482
|
|
|
1336
1483
|
clean_ctrl.stop.disabled = false
|
|
1337
1484
|
if ( ! only_stop ) {
|
|
1485
|
+
clean_ctrl.continue.disable_add_sub.disabled = false
|
|
1338
1486
|
clean_ctrl.continue.disabled = false
|
|
1339
1487
|
clean_ctrl.finish.disabled = false
|
|
1340
1488
|
}
|
|
@@ -29,7 +29,7 @@ cubevis/__js__/bokeh-3.6.1.min.js,sha256=SPRs94Q-H-aj8MCsXNu4ok1ouQQLTgXxZnk0-BB
|
|
|
29
29
|
cubevis/__js__/bokeh-tables-3.6.1.min.js,sha256=wINufoBiINmP_PERwhN_1GkidJOsJQ_3vFKUDui7rl8,301216
|
|
30
30
|
cubevis/__js__/bokeh-widgets-3.6.1.min.js,sha256=NE3tFbbxoaMjnJ0XednWJxbAGl-vSR0fxE_kX8keuDQ,311821
|
|
31
31
|
cubevis/__js__/casalib.min.js,sha256=JLZ_3i5JlbNJw2nsx7pewysxzoD3sVpSiWdgJCLbhi0,91107
|
|
32
|
-
cubevis/__js__/cubevisjs.min.js,sha256=
|
|
32
|
+
cubevis/__js__/cubevisjs.min.js,sha256=60KOq5Nt2OW_eGuJ_BcI-GndTEQAL4gZNkbZE9Lve0M,28238
|
|
33
33
|
cubevis/bokeh/__init__.py,sha256=XvuKcU9-bAv1CPb_O81VJTNLlHQC-zBg_Ig9_q4RkM4,1371
|
|
34
34
|
cubevis/bokeh/annotations/__init__.py,sha256=tjDIPKbg-rh7Iu3coFWvmX-j2yNj9KuKmRp1aTo71ww,50
|
|
35
35
|
cubevis/bokeh/annotations/_ev_poly_annotation.py,sha256=0ayX21gxNnm5-4s5VRKiaJ23DCSvbvpsU6oym9q2bk0,173
|
|
@@ -37,9 +37,10 @@ cubevis/bokeh/components/__init__.py,sha256=BQOqgBtlDpu6ENrY42nYeS73n2ZSMogJgM2L
|
|
|
37
37
|
cubevis/bokeh/format/__init__.py,sha256=umNotXSRR23675c44x3h5h2ILbZX8xrDFCztvriYjEw,1424
|
|
38
38
|
cubevis/bokeh/format/_time_ticks.py,sha256=j-DcPh7RfGE8iX2bPjLQDQPIbiAbmjiEWQnKmdMWA3I,1773
|
|
39
39
|
cubevis/bokeh/format/_wcs_ticks.py,sha256=x-ObJiCxBvfqCEk8ySh0NU1ZQUPFUdHRHztjwPSPECI,1827
|
|
40
|
-
cubevis/bokeh/models/__init__.py,sha256=
|
|
40
|
+
cubevis/bokeh/models/__init__.py,sha256=rlZbGqSv0nmg5At9fZDofK3tF8PLM6sp7hpE3Bgi6Wg,167
|
|
41
41
|
cubevis/bokeh/models/_edit_span.py,sha256=7o59ZS0bF_Q_WtstvViWXP-2PiY_F7_zCecTqKcmz0E,196
|
|
42
42
|
cubevis/bokeh/models/_ev_text_input.py,sha256=SGtefXkWK6jHEk4EneZ_hEUGwoIWwVGjwqLjGsAXMpY,158
|
|
43
|
+
cubevis/bokeh/models/_shared_dict.py,sha256=AWjLMOKVAXWHSF4gcK2RbxF442QlzQ7hMR0oaODCqB0,901
|
|
43
44
|
cubevis/bokeh/models/_tip.py,sha256=bnlCOYXsNdgEYKDbsQ6hEVrKOjCXEDxtuwE3sldOeEU,1396
|
|
44
45
|
cubevis/bokeh/models/_tip_button.py,sha256=Dw4aO37o0J3n6EoaJ3ui1y8d04qNn3x2dbKiwiQpArM,1577
|
|
45
46
|
cubevis/bokeh/sources/__init__.py,sha256=4FsudFuVU4o7VG5OG3K1tiMoxIXcJWNz_K9yzMDE8ls,1581
|
|
@@ -95,9 +96,9 @@ cubevis/remote/_local.py,sha256=PcPCFcwttTFZd3O33-5pqDuGKQKK6CA0gz1MTIkTiNI,1032
|
|
|
95
96
|
cubevis/remote/_remote_kernel.py,sha256=wfu7ZzKn-oCxZxzDIkC5puBvGf8WbCLYL3CzM56_FNc,2652
|
|
96
97
|
cubevis/toolbox/__init__.py,sha256=xzqwAG9863d7UKBVBRw7FrRUQbvCdFcLBq4vTpg63DU,1487
|
|
97
98
|
cubevis/toolbox/_app_context.py,sha256=0tRY2SSbSCM6RKLFs_T707_ehWkJXPvnLlE1P9cLXJY,3024
|
|
98
|
-
cubevis/toolbox/_cube.py,sha256=
|
|
99
|
-
cubevis/toolbox/_interactive_clean_ui.mustache,sha256=
|
|
100
|
-
cubevis/toolbox/_interactive_clean_ui.py,sha256=
|
|
99
|
+
cubevis/toolbox/_cube.py,sha256=Jjf40aahUo6ZT9KP8b1RUbBtdd1CSLtE48RQF6q4EkQ,298496
|
|
100
|
+
cubevis/toolbox/_interactive_clean_ui.mustache,sha256=EyihZ-ZNe1hMxdQfkH2lPEo_Km-Kb7ZVcDF3VBzuxNE,111910
|
|
101
|
+
cubevis/toolbox/_interactive_clean_ui.py,sha256=FJdGxbdNHOVlSy0PZULQAUXwdVdAHBEpLGOTe-_0lHs,111821
|
|
101
102
|
cubevis/toolbox/_interactiveclean_wrappers.py,sha256=XqyCGz33CMDhszTxnwZ_3-64GszUK1XYnGKUOxl9sas,5071
|
|
102
103
|
cubevis/toolbox/_region_list.py,sha256=_1RvnXwqMoaAq8CPy-6IyhabLi_snXqO566onehI2y0,8957
|
|
103
104
|
cubevis/utils/_ResourceManager.py,sha256=SaaR29etabRiKxmUK-aWvAm4v_OPFJH8CX7bNFm0Lgo,3410
|
|
@@ -114,8 +115,8 @@ cubevis/utils/_pkgs.py,sha256=mu2CCzndmJZYP81UkFhxveW_CisWLUvagJVolHOEVgM,2294
|
|
|
114
115
|
cubevis/utils/_regions.py,sha256=TdAg4ZUUyhg3nFmX9_KLboqmc0LkyOdEW8M1WDR5Udk,1669
|
|
115
116
|
cubevis/utils/_static.py,sha256=rN-sqXNqQ5R2M3wmPHU1GPP5OTyyWQlUPRuimCrht-g,2347
|
|
116
117
|
cubevis/utils/_tiles.py,sha256=A9W1X61VOhBMTOKXVajzOIoiV2FBdO5N2SFB9SUpDOo,7336
|
|
117
|
-
cubevis/__version__.py,sha256=
|
|
118
|
-
cubevis-0.5.
|
|
119
|
-
cubevis-0.5.
|
|
120
|
-
cubevis-0.5.
|
|
121
|
-
cubevis-0.5.
|
|
118
|
+
cubevis/__version__.py,sha256=kSyf03ZyJGgJcFLGc0Q1b3QZ1UfFrJEhukKkhdMWiAM,22
|
|
119
|
+
cubevis-0.5.25.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
120
|
+
cubevis-0.5.25.dist-info/METADATA,sha256=_5negZulwCmL_4YPAbnW31Bod3XBEgsg3cv2xxPKmA8,2629
|
|
121
|
+
cubevis-0.5.25.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
122
|
+
cubevis-0.5.25.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|