cubevis 0.5.22__py3-none-any.whl → 0.5.24__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/__version__.py +1 -1
- cubevis/toolbox/_cube.py +2 -2
- cubevis/toolbox/_interactive_clean_ui.mustache +213 -72
- cubevis/toolbox/_interactive_clean_ui.py +213 -72
- {cubevis-0.5.22.dist-info → cubevis-0.5.24.dist-info}/METADATA +1 -1
- {cubevis-0.5.22.dist-info → cubevis-0.5.24.dist-info}/RECORD +8 -8
- {cubevis-0.5.22.dist-info → cubevis-0.5.24.dist-info}/WHEEL +0 -0
- {cubevis-0.5.22.dist-info → cubevis-0.5.24.dist-info}/licenses/LICENSE +0 -0
cubevis/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '0.5.
|
|
1
|
+
__version__ = '0.5.24'
|
cubevis/toolbox/_cube.py
CHANGED
|
@@ -880,7 +880,7 @@ class CubeMask:
|
|
|
880
880
|
### square: 𝑦=𝑥^2
|
|
881
881
|
### gamma: 𝑦=𝑥^𝛾
|
|
882
882
|
### power: 𝑦=(𝛼^𝑥−1)/(𝛼−1)
|
|
883
|
-
self._cm_adjust['alpha-value'] = TextInput( value="
|
|
883
|
+
self._cm_adjust['alpha-value'] = TextInput( value="10", prefix="alpha", max_width=170, visible=False )
|
|
884
884
|
self._cm_adjust['gamma-value'] = TextInput( value="1", prefix="gamma", max_width=170, visible=False )
|
|
885
885
|
self._cm_adjust['equation'] = Div(text='''<math><mrow><mi>y</mi><mo>=</mo><mi>x</mi></mrow></math>''', margin=(12, 0, 0, 0)) # linear
|
|
886
886
|
self._cm_adjust['scaling'] = Dropdown( label='linear',
|
|
@@ -2969,8 +2969,8 @@ class CubeMask:
|
|
|
2969
2969
|
( spec ) => {
|
|
2970
2970
|
if ( isource.masking_on( ) )
|
|
2971
2971
|
refresh_pixel_display( spec.index,
|
|
2972
|
+
spec.spectrum.pixel[spec.chan[1]],
|
|
2972
2973
|
'mask' in spec ? spec.mask[spec.chan[1]] : undefined,
|
|
2973
|
-
'mask' in spec && spec.mask[spec.chan[1]],
|
|
2974
2974
|
pix_wrld && pix_wrld.label == 'pixel' ? false : true )
|
|
2975
2975
|
} )
|
|
2976
2976
|
if ( go_to && ! go_to._has_focus ) {
|
|
@@ -45,12 +45,13 @@ import asyncio
|
|
|
45
45
|
import shutil
|
|
46
46
|
import websockets
|
|
47
47
|
from os.path import basename, abspath, exists, join
|
|
48
|
+
import numpy as np
|
|
48
49
|
from uuid import uuid4
|
|
49
50
|
from html import escape as html_escape
|
|
50
51
|
from contextlib import asynccontextmanager
|
|
51
52
|
from bokeh.models import Button, TextInput, Checkbox, Div, LinearAxis, CustomJS, Spacer, Span, HoverTool, DataRange1d, Step, InlineStyleSheet
|
|
52
53
|
from bokeh.events import ModelEvent, MouseEnter
|
|
53
|
-
from bokeh.models import TabPanel, Tabs
|
|
54
|
+
from bokeh.models import TabPanel, Tabs, Range1d
|
|
54
55
|
from bokeh.plotting import ColumnDataSource, figure, show
|
|
55
56
|
from bokeh.layouts import column, row, layout
|
|
56
57
|
from bokeh.io import reset_output as reset_bokeh_output, output_notebook
|
|
@@ -343,57 +344,159 @@ class InteractiveCleanUI:
|
|
|
343
344
|
</div>'''
|
|
344
345
|
|
|
345
346
|
hover = HoverTool( tooltips=TOOLTIPS )
|
|
346
|
-
imdetails['gui']['convergence'] = figure( sizing_mode=sizing_mode, y_axis_location="right",
|
|
347
|
-
tools=[ hover ], toolbar_location=None, **kw )
|
|
348
347
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
348
|
+
###
|
|
349
|
+
### Data source that will be used for updating the convergence plot
|
|
350
|
+
###
|
|
351
|
+
stokes = 0
|
|
352
|
+
convergence = imdetails['converge']['chan'][0][stokes]
|
|
353
|
+
imdetails['converge-data'] = { }
|
|
354
|
+
imdetails['converge-data']['flux'] = ColumnDataSource( data=dict( values=convergence['modelFlux'], iterations=convergence['iterations'],
|
|
355
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
356
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
357
|
+
type=['flux'] * len(convergence['iterations']) ) )
|
|
358
|
+
imdetails['converge-data']['residual'] = ColumnDataSource( data=dict( values=convergence['peakRes'], iterations=convergence['iterations'],
|
|
359
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
360
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
361
|
+
type=['residual'] * len(convergence['iterations'])) )
|
|
362
|
+
imdetails['converge-data']['cyclethreshold'] = ColumnDataSource( data=dict( values=convergence['cycleThresh'], iterations=convergence['iterations'] ) )
|
|
363
|
+
|
|
364
|
+
# Calculate explicit ranges for each dataset
|
|
365
|
+
flux_values = convergence['modelFlux']
|
|
366
|
+
residual_values = convergence['peakRes']
|
|
367
|
+
iterations = convergence['iterations']
|
|
368
|
+
cyclethresh_values = convergence['cycleThresh']
|
|
369
|
+
|
|
370
|
+
# Calculate ranges with padding
|
|
371
|
+
if len(flux_values) > 0:
|
|
372
|
+
flux_min, flux_max = np.min(flux_values), np.max(flux_values)
|
|
373
|
+
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)
|
|
374
|
+
else:
|
|
375
|
+
flux_min, flux_max, flux_padding = 0, 1, 0.1
|
|
372
376
|
|
|
377
|
+
if len(residual_values) > 0:
|
|
378
|
+
residual_min, residual_max = np.min(residual_values), np.max(residual_values)
|
|
379
|
+
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)
|
|
373
380
|
else:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
381
|
+
residual_min, residual_max, residual_padding = 0, 1, 0.1
|
|
382
|
+
|
|
383
|
+
# Create Range1d objects
|
|
384
|
+
flux_range = Range1d(start=flux_min - flux_padding, end=flux_max + flux_padding)
|
|
385
|
+
residual_range = Range1d(start=residual_min - residual_padding, end=residual_max + residual_padding)
|
|
386
|
+
|
|
387
|
+
# Ensure ranges are valid (non-zero span)
|
|
388
|
+
if flux_range.end - flux_range.start < 1e-10:
|
|
389
|
+
center = flux_range.start
|
|
390
|
+
if abs(center) < 1e-10: # If center is essentially 0
|
|
391
|
+
flux_range.start = -0.1
|
|
392
|
+
flux_range.end = 1.0
|
|
393
|
+
else:
|
|
394
|
+
span = max(abs(center * 0.2), 0.1)
|
|
395
|
+
flux_range.start = center - span
|
|
396
|
+
flux_range.end = center + span
|
|
397
|
+
|
|
398
|
+
if residual_range.end - residual_range.start < 1e-10:
|
|
399
|
+
center = residual_range.start
|
|
400
|
+
span = max(abs(center * 0.2), 0.1)
|
|
401
|
+
residual_range.start = center - span
|
|
402
|
+
residual_range.end = center + span
|
|
403
|
+
|
|
404
|
+
# ORIENTATION CONFIGURATION - this eliminates the conditional branches
|
|
405
|
+
config = {
|
|
406
|
+
'vertical': {
|
|
407
|
+
'iteration_axis': 'y',
|
|
408
|
+
'data_axis': 'x',
|
|
409
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
410
|
+
'residual_axis_label': 'Peak Residual',
|
|
411
|
+
'flux_axis_label': 'Total Flux',
|
|
412
|
+
'residual_axis_pos': 'above',
|
|
413
|
+
'flux_axis_pos': 'above',
|
|
414
|
+
'extra_ranges_key': 'extra_x_ranges',
|
|
415
|
+
'glyph_coords': ('values', 'iterations'), # (x, y)
|
|
416
|
+
'range_name_param': 'x_range_name'
|
|
417
|
+
},
|
|
418
|
+
'horizontal': {
|
|
419
|
+
'iteration_axis': 'x',
|
|
420
|
+
'data_axis': 'y',
|
|
421
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
422
|
+
'residual_axis_label': 'Peak Residual',
|
|
423
|
+
'flux_axis_label': 'Total Flux',
|
|
424
|
+
'residual_axis_pos': 'right',
|
|
425
|
+
'flux_axis_pos': 'right',
|
|
426
|
+
'extra_ranges_key': 'extra_y_ranges',
|
|
427
|
+
'glyph_coords': ('iterations', 'values'), # (x, y)
|
|
428
|
+
'range_name_param': 'y_range_name'
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
cfg = config[orient]
|
|
433
|
+
|
|
434
|
+
# Create figure with no default axes; to control the axes they must
|
|
435
|
+
# be explicitly set to None
|
|
436
|
+
imdetails['gui']['convergence'] = figure( sizing_mode=sizing_mode,
|
|
437
|
+
x_axis_location=None, y_axis_location=None,
|
|
438
|
+
tools=[ hover ], toolbar_location=None, **kw )
|
|
439
|
+
|
|
440
|
+
# Set up extra ranges
|
|
441
|
+
setattr(imdetails['gui']['convergence'], cfg['extra_ranges_key'], {
|
|
442
|
+
'residual_range': residual_range,
|
|
443
|
+
'flux_range': flux_range
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
# Store references for JavaScript updates
|
|
447
|
+
imdetails['converge-ranges'] = {
|
|
448
|
+
'residual_range': residual_range,
|
|
449
|
+
'flux_range': flux_range
|
|
450
|
+
}
|
|
396
451
|
|
|
452
|
+
# Create main iteration axis
|
|
453
|
+
main_axis = LinearAxis(axis_label=cfg['main_axis_label'])
|
|
454
|
+
main_axis_pos = 'below' if cfg['iteration_axis'] == 'x' else 'left'
|
|
455
|
+
imdetails['gui']['convergence'].add_layout(main_axis, main_axis_pos)
|
|
456
|
+
|
|
457
|
+
# Create glyphs using configuration
|
|
458
|
+
x_coord, y_coord = cfg['glyph_coords']
|
|
459
|
+
range_param = {cfg['range_name_param']: 'residual_range'}
|
|
460
|
+
|
|
461
|
+
imdetails['gui']['convergence'].step( x_coord, y_coord, source=imdetails['converge-data']['cyclethreshold'],
|
|
462
|
+
line_color='red', line_dash='dotted', line_width=2, **range_param )
|
|
463
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
464
|
+
line_color=self._converge_color['residual'], **range_param )
|
|
465
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
466
|
+
color=self._converge_color['residual'], size=10, **range_param )
|
|
467
|
+
|
|
468
|
+
# Flux glyphs
|
|
469
|
+
range_param = {cfg['range_name_param']: 'flux_range'}
|
|
470
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
471
|
+
line_color=self._converge_color['flux'], **range_param )
|
|
472
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
473
|
+
color=self._converge_color['flux'], size=10, **range_param )
|
|
474
|
+
|
|
475
|
+
# Create and style residual axis
|
|
476
|
+
residual_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'residual_range'}
|
|
477
|
+
residual_axis = LinearAxis(axis_label=cfg['residual_axis_label'], **residual_axis_param)
|
|
478
|
+
residual_axis.axis_line_color = self._converge_color['residual']
|
|
479
|
+
residual_axis.major_label_text_color = self._converge_color['residual']
|
|
480
|
+
residual_axis.axis_label_text_color = self._converge_color['residual']
|
|
481
|
+
residual_axis.major_tick_line_color = self._converge_color['residual']
|
|
482
|
+
residual_axis.minor_tick_line_color = self._converge_color['residual']
|
|
483
|
+
imdetails['gui']['convergence'].add_layout(residual_axis, cfg['residual_axis_pos'])
|
|
484
|
+
|
|
485
|
+
# Create and style flux axis
|
|
486
|
+
flux_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'flux_range'}
|
|
487
|
+
flux_axis = LinearAxis(axis_label=cfg['flux_axis_label'], **flux_axis_param)
|
|
488
|
+
flux_axis.axis_line_color = self._converge_color['flux']
|
|
489
|
+
flux_axis.major_label_text_color = self._converge_color['flux']
|
|
490
|
+
flux_axis.axis_label_text_color = self._converge_color['flux']
|
|
491
|
+
flux_axis.major_tick_line_color = self._converge_color['flux']
|
|
492
|
+
flux_axis.minor_tick_line_color = self._converge_color['flux']
|
|
493
|
+
imdetails['gui']['convergence'].add_layout(flux_axis, cfg['flux_axis_pos'])
|
|
494
|
+
|
|
495
|
+
# Store axis references for JavaScript access
|
|
496
|
+
imdetails['converge-axes'] = {
|
|
497
|
+
'residual_axis': residual_axis,
|
|
498
|
+
'flux_axis': flux_axis
|
|
499
|
+
}
|
|
397
500
|
|
|
398
501
|
def _launch_gui( self ):
|
|
399
502
|
'''create and show GUI
|
|
@@ -534,23 +637,6 @@ class InteractiveCleanUI:
|
|
|
534
637
|
|
|
535
638
|
self._clean['converge']['pipe'].register( self._clean['converge']['id'], convergence_handler )
|
|
536
639
|
|
|
537
|
-
###
|
|
538
|
-
### Data source that will be used for updating the convergence plot
|
|
539
|
-
###
|
|
540
|
-
stokes = 0
|
|
541
|
-
convergence = imdetails['converge']['chan'][0][stokes]
|
|
542
|
-
imdetails['converge-data'] = { }
|
|
543
|
-
imdetails['converge-data']['flux'] = ColumnDataSource( data=dict( values=convergence['modelFlux'], iterations=convergence['iterations'],
|
|
544
|
-
cyclethreshold=convergence['cycleThresh'],
|
|
545
|
-
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
546
|
-
type=['flux'] * len(convergence['iterations']) ) )
|
|
547
|
-
imdetails['converge-data']['residual'] = ColumnDataSource( data=dict( values=convergence['peakRes'], iterations=convergence['iterations'],
|
|
548
|
-
cyclethreshold=convergence['cycleThresh'],
|
|
549
|
-
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
550
|
-
type=['residual'] * len(convergence['iterations'])) )
|
|
551
|
-
imdetails['converge-data']['cyclethreshold'] = ColumnDataSource( data=dict( values=convergence['cycleThresh'], iterations=convergence['iterations'] ) )
|
|
552
|
-
|
|
553
|
-
|
|
554
640
|
###
|
|
555
641
|
### help page for cube interactions
|
|
556
642
|
###
|
|
@@ -585,8 +671,12 @@ class InteractiveCleanUI:
|
|
|
585
671
|
imdetails['gui']['image']['src'] = imdetails['gui']['cube'].js_obj( )
|
|
586
672
|
imdetails['gui']['image']['fig'] = imdetails['gui']['cube'].image( grid=False, height_policy='max', width_policy='max',
|
|
587
673
|
channelcb=CustomJS( args=dict( img_state={ 'src': imdetails['gui']['image']['src'],
|
|
588
|
-
'flux': imdetails['converge-data']['flux'],
|
|
589
|
-
|
|
674
|
+
'flux': { 'source': imdetails['converge-data']['flux'],
|
|
675
|
+
'axis': imdetails['converge-axes']['flux_axis'],
|
|
676
|
+
'range': imdetails['converge-ranges']['flux_range'] },
|
|
677
|
+
'residual': { 'source': imdetails['converge-data']['residual'],
|
|
678
|
+
'axis': imdetails['converge-axes']['residual_axis'],
|
|
679
|
+
'range': imdetails['converge-ranges']['residual_range'] },
|
|
590
680
|
'cyclethreshold': imdetails['converge-data']['cyclethreshold'] },
|
|
591
681
|
imid=imid,
|
|
592
682
|
ctrl={ 'converge': self._clean['converge'] },
|
|
@@ -702,9 +792,13 @@ class InteractiveCleanUI:
|
|
|
702
792
|
'src': v['gui']['cube'].js_obj( ),
|
|
703
793
|
'spectrum': v['gui']['spectrum'],
|
|
704
794
|
'src': v['gui']['image']['src'],
|
|
705
|
-
'flux': v['converge-data']['flux'],
|
|
795
|
+
'flux': { 'source': v['converge-data']['flux'],
|
|
796
|
+
'axis': v['converge-axes']['flux_axis'],
|
|
797
|
+
'range': v['converge-ranges']['flux_range'] },
|
|
706
798
|
'cyclethreshold': v['converge-data']['cyclethreshold'],
|
|
707
|
-
'residual': v['converge-data']['residual'],
|
|
799
|
+
'residual': { 'source': v['converge-data']['residual'],
|
|
800
|
+
'axis': v['converge-axes']['residual_axis'],
|
|
801
|
+
'range': v['converge-ranges']['residual_range'] },
|
|
708
802
|
'navi': { 'slider': v['gui']['slider'],
|
|
709
803
|
'goto': v['gui']['goto'],
|
|
710
804
|
## it doesn't seem like pixel tracking must be disabled
|
|
@@ -1216,7 +1310,52 @@ class InteractiveCleanUI:
|
|
|
1216
1310
|
### -- The "Insert here ..." code seems to be called when when the stokes plane is changed --
|
|
1217
1311
|
### -- but there have been no tclean iterations yet... --
|
|
1218
1312
|
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1219
|
-
'update-converge': '''function
|
|
1313
|
+
'update-converge': '''function updateAxisRange(source, range_obj, axis_obj, axis_name) {
|
|
1314
|
+
const data = source.data;
|
|
1315
|
+
const values = data['values'];
|
|
1316
|
+
|
|
1317
|
+
if (values.length === 0) return;
|
|
1318
|
+
|
|
1319
|
+
// Calculate data bounds
|
|
1320
|
+
const min_val = Math.min(...values);
|
|
1321
|
+
const max_val = Math.max(...values);
|
|
1322
|
+
|
|
1323
|
+
// Add padding (10% of range, with minimum padding)
|
|
1324
|
+
const span = max_val - min_val;
|
|
1325
|
+
const padding = max_val != min_val ? Math.max(span * 0.1, Math.abs(max_val * 0.02)) : Math.abs(max_val * 0.1);
|
|
1326
|
+
|
|
1327
|
+
// Update range
|
|
1328
|
+
range_obj.start = min_val - padding;
|
|
1329
|
+
range_obj.end = max_val + padding;
|
|
1330
|
+
|
|
1331
|
+
// Ensure ranges are valid (non-zero span)
|
|
1332
|
+
if ( range_obj.end - range_obj.start < 1e-10 ) {
|
|
1333
|
+
const center = range_obj.start
|
|
1334
|
+
if ( Math.abs(center) < 1e-10 ) {
|
|
1335
|
+
// If center is essentially 0
|
|
1336
|
+
range_obj.start = -0.1
|
|
1337
|
+
range_obj.end = 1.0
|
|
1338
|
+
} else {
|
|
1339
|
+
const span = Math.max(Math.abs(center * 0.2), 0.1)
|
|
1340
|
+
range_obj.start = center - span
|
|
1341
|
+
range_obj.end = center + span
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// Optional: Update tick density
|
|
1346
|
+
if (axis_obj && axis_obj.ticker) {
|
|
1347
|
+
const new_span = range_obj.end - range_obj.start;
|
|
1348
|
+
if (new_span < 10) {
|
|
1349
|
+
axis_obj.ticker.desired_num_ticks = 8;
|
|
1350
|
+
} else if (new_span < 100) {
|
|
1351
|
+
axis_obj.ticker.desired_num_ticks = 10;
|
|
1352
|
+
} else {
|
|
1353
|
+
axis_obj.ticker.desired_num_ticks = 6;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function update_convergence_single( target, data ) {
|
|
1220
1359
|
const pos = target.src.cur_chan
|
|
1221
1360
|
const imdata = data.get(pos[1]).get(pos[0])
|
|
1222
1361
|
// chan----------------^^^^^^ ^^^^^^----stokes
|
|
@@ -1226,9 +1365,11 @@ class InteractiveCleanUI:
|
|
|
1226
1365
|
const modelFlux = imdata.modelFlux
|
|
1227
1366
|
const stopCode = imdata.stopCode
|
|
1228
1367
|
const stopDesc = imdata.stopCode.map( code => stopdescmap.has(code) ? stopdescmap.get(code): "" )
|
|
1229
|
-
target.residual.data = { iterations, cyclethreshold, stopDesc, values: peakRes, type: Array(iterations.length).fill('residual') }
|
|
1230
|
-
target.flux.data = { iterations, cyclethreshold, stopDesc, values: modelFlux, type: Array(iterations.length).fill('flux') }
|
|
1368
|
+
target.residual.source.data = { iterations, cyclethreshold, stopDesc, values: peakRes, type: Array(iterations.length).fill('residual') }
|
|
1369
|
+
target.flux.source.data = { iterations, cyclethreshold, stopDesc, values: modelFlux, type: Array(iterations.length).fill('flux') }
|
|
1231
1370
|
target.cyclethreshold.data = { iterations, values: cyclethreshold }
|
|
1371
|
+
updateAxisRange( target.flux.source, target.flux.range, target.flux.axis, 'Flux' )
|
|
1372
|
+
updateAxisRange( target.residual.source, target.residual.range, target.residual.axis, 'Residual' )
|
|
1232
1373
|
}
|
|
1233
1374
|
|
|
1234
1375
|
function update_convergence( recurse=false ) {
|
|
@@ -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
|
|
@@ -342,57 +343,159 @@ class InteractiveCleanUI:
|
|
|
342
343
|
</div>'''
|
|
343
344
|
|
|
344
345
|
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
346
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
347
|
+
###
|
|
348
|
+
### Data source that will be used for updating the convergence plot
|
|
349
|
+
###
|
|
350
|
+
stokes = 0
|
|
351
|
+
convergence = imdetails['converge']['chan'][0][stokes]
|
|
352
|
+
imdetails['converge-data'] = { }
|
|
353
|
+
imdetails['converge-data']['flux'] = ColumnDataSource( data=dict( values=convergence['modelFlux'], iterations=convergence['iterations'],
|
|
354
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
355
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
356
|
+
type=['flux'] * len(convergence['iterations']) ) )
|
|
357
|
+
imdetails['converge-data']['residual'] = ColumnDataSource( data=dict( values=convergence['peakRes'], iterations=convergence['iterations'],
|
|
358
|
+
cyclethreshold=convergence['cycleThresh'],
|
|
359
|
+
stopDesc=list( map( ImagingDict.get_summaryminor_stopdesc, convergence['stopCode'] ) ),
|
|
360
|
+
type=['residual'] * len(convergence['iterations'])) )
|
|
361
|
+
imdetails['converge-data']['cyclethreshold'] = ColumnDataSource( data=dict( values=convergence['cycleThresh'], iterations=convergence['iterations'] ) )
|
|
362
|
+
|
|
363
|
+
# Calculate explicit ranges for each dataset
|
|
364
|
+
flux_values = convergence['modelFlux']
|
|
365
|
+
residual_values = convergence['peakRes']
|
|
366
|
+
iterations = convergence['iterations']
|
|
367
|
+
cyclethresh_values = convergence['cycleThresh']
|
|
368
|
+
|
|
369
|
+
# Calculate ranges with padding
|
|
370
|
+
if len(flux_values) > 0:
|
|
371
|
+
flux_min, flux_max = np.min(flux_values), np.max(flux_values)
|
|
372
|
+
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)
|
|
373
|
+
else:
|
|
374
|
+
flux_min, flux_max, flux_padding = 0, 1, 0.1
|
|
371
375
|
|
|
376
|
+
if len(residual_values) > 0:
|
|
377
|
+
residual_min, residual_max = np.min(residual_values), np.max(residual_values)
|
|
378
|
+
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
379
|
else:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
380
|
+
residual_min, residual_max, residual_padding = 0, 1, 0.1
|
|
381
|
+
|
|
382
|
+
# Create Range1d objects
|
|
383
|
+
flux_range = Range1d(start=flux_min - flux_padding, end=flux_max + flux_padding)
|
|
384
|
+
residual_range = Range1d(start=residual_min - residual_padding, end=residual_max + residual_padding)
|
|
385
|
+
|
|
386
|
+
# Ensure ranges are valid (non-zero span)
|
|
387
|
+
if flux_range.end - flux_range.start < 1e-10:
|
|
388
|
+
center = flux_range.start
|
|
389
|
+
if abs(center) < 1e-10: # If center is essentially 0
|
|
390
|
+
flux_range.start = -0.1
|
|
391
|
+
flux_range.end = 1.0
|
|
392
|
+
else:
|
|
393
|
+
span = max(abs(center * 0.2), 0.1)
|
|
394
|
+
flux_range.start = center - span
|
|
395
|
+
flux_range.end = center + span
|
|
396
|
+
|
|
397
|
+
if residual_range.end - residual_range.start < 1e-10:
|
|
398
|
+
center = residual_range.start
|
|
399
|
+
span = max(abs(center * 0.2), 0.1)
|
|
400
|
+
residual_range.start = center - span
|
|
401
|
+
residual_range.end = center + span
|
|
402
|
+
|
|
403
|
+
# ORIENTATION CONFIGURATION - this eliminates the conditional branches
|
|
404
|
+
config = {
|
|
405
|
+
'vertical': {
|
|
406
|
+
'iteration_axis': 'y',
|
|
407
|
+
'data_axis': 'x',
|
|
408
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
409
|
+
'residual_axis_label': 'Peak Residual',
|
|
410
|
+
'flux_axis_label': 'Total Flux',
|
|
411
|
+
'residual_axis_pos': 'above',
|
|
412
|
+
'flux_axis_pos': 'above',
|
|
413
|
+
'extra_ranges_key': 'extra_x_ranges',
|
|
414
|
+
'glyph_coords': ('values', 'iterations'), # (x, y)
|
|
415
|
+
'range_name_param': 'x_range_name'
|
|
416
|
+
},
|
|
417
|
+
'horizontal': {
|
|
418
|
+
'iteration_axis': 'x',
|
|
419
|
+
'data_axis': 'y',
|
|
420
|
+
'main_axis_label': 'Iteration (cycle threshold dotted red)',
|
|
421
|
+
'residual_axis_label': 'Peak Residual',
|
|
422
|
+
'flux_axis_label': 'Total Flux',
|
|
423
|
+
'residual_axis_pos': 'right',
|
|
424
|
+
'flux_axis_pos': 'right',
|
|
425
|
+
'extra_ranges_key': 'extra_y_ranges',
|
|
426
|
+
'glyph_coords': ('iterations', 'values'), # (x, y)
|
|
427
|
+
'range_name_param': 'y_range_name'
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
cfg = config[orient]
|
|
432
|
+
|
|
433
|
+
# Create figure with no default axes; to control the axes they must
|
|
434
|
+
# be explicitly set to None
|
|
435
|
+
imdetails['gui']['convergence'] = figure( sizing_mode=sizing_mode,
|
|
436
|
+
x_axis_location=None, y_axis_location=None,
|
|
437
|
+
tools=[ hover ], toolbar_location=None, **kw )
|
|
438
|
+
|
|
439
|
+
# Set up extra ranges
|
|
440
|
+
setattr(imdetails['gui']['convergence'], cfg['extra_ranges_key'], {
|
|
441
|
+
'residual_range': residual_range,
|
|
442
|
+
'flux_range': flux_range
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
# Store references for JavaScript updates
|
|
446
|
+
imdetails['converge-ranges'] = {
|
|
447
|
+
'residual_range': residual_range,
|
|
448
|
+
'flux_range': flux_range
|
|
449
|
+
}
|
|
395
450
|
|
|
451
|
+
# Create main iteration axis
|
|
452
|
+
main_axis = LinearAxis(axis_label=cfg['main_axis_label'])
|
|
453
|
+
main_axis_pos = 'below' if cfg['iteration_axis'] == 'x' else 'left'
|
|
454
|
+
imdetails['gui']['convergence'].add_layout(main_axis, main_axis_pos)
|
|
455
|
+
|
|
456
|
+
# Create glyphs using configuration
|
|
457
|
+
x_coord, y_coord = cfg['glyph_coords']
|
|
458
|
+
range_param = {cfg['range_name_param']: 'residual_range'}
|
|
459
|
+
|
|
460
|
+
imdetails['gui']['convergence'].step( x_coord, y_coord, source=imdetails['converge-data']['cyclethreshold'],
|
|
461
|
+
line_color='red', line_dash='dotted', line_width=2, **range_param )
|
|
462
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
463
|
+
line_color=self._converge_color['residual'], **range_param )
|
|
464
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['residual'],
|
|
465
|
+
color=self._converge_color['residual'], size=10, **range_param )
|
|
466
|
+
|
|
467
|
+
# Flux glyphs
|
|
468
|
+
range_param = {cfg['range_name_param']: 'flux_range'}
|
|
469
|
+
imdetails['gui']['convergence'].line( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
470
|
+
line_color=self._converge_color['flux'], **range_param )
|
|
471
|
+
imdetails['gui']['convergence'].scatter( x_coord, y_coord, source=imdetails['converge-data']['flux'],
|
|
472
|
+
color=self._converge_color['flux'], size=10, **range_param )
|
|
473
|
+
|
|
474
|
+
# Create and style residual axis
|
|
475
|
+
residual_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'residual_range'}
|
|
476
|
+
residual_axis = LinearAxis(axis_label=cfg['residual_axis_label'], **residual_axis_param)
|
|
477
|
+
residual_axis.axis_line_color = self._converge_color['residual']
|
|
478
|
+
residual_axis.major_label_text_color = self._converge_color['residual']
|
|
479
|
+
residual_axis.axis_label_text_color = self._converge_color['residual']
|
|
480
|
+
residual_axis.major_tick_line_color = self._converge_color['residual']
|
|
481
|
+
residual_axis.minor_tick_line_color = self._converge_color['residual']
|
|
482
|
+
imdetails['gui']['convergence'].add_layout(residual_axis, cfg['residual_axis_pos'])
|
|
483
|
+
|
|
484
|
+
# Create and style flux axis
|
|
485
|
+
flux_axis_param = {cfg['range_name_param'].replace('_name', '_name'): 'flux_range'}
|
|
486
|
+
flux_axis = LinearAxis(axis_label=cfg['flux_axis_label'], **flux_axis_param)
|
|
487
|
+
flux_axis.axis_line_color = self._converge_color['flux']
|
|
488
|
+
flux_axis.major_label_text_color = self._converge_color['flux']
|
|
489
|
+
flux_axis.axis_label_text_color = self._converge_color['flux']
|
|
490
|
+
flux_axis.major_tick_line_color = self._converge_color['flux']
|
|
491
|
+
flux_axis.minor_tick_line_color = self._converge_color['flux']
|
|
492
|
+
imdetails['gui']['convergence'].add_layout(flux_axis, cfg['flux_axis_pos'])
|
|
493
|
+
|
|
494
|
+
# Store axis references for JavaScript access
|
|
495
|
+
imdetails['converge-axes'] = {
|
|
496
|
+
'residual_axis': residual_axis,
|
|
497
|
+
'flux_axis': flux_axis
|
|
498
|
+
}
|
|
396
499
|
|
|
397
500
|
def _launch_gui( self ):
|
|
398
501
|
'''create and show GUI
|
|
@@ -533,23 +636,6 @@ class InteractiveCleanUI:
|
|
|
533
636
|
|
|
534
637
|
self._clean['converge']['pipe'].register( self._clean['converge']['id'], convergence_handler )
|
|
535
638
|
|
|
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
639
|
###
|
|
554
640
|
### help page for cube interactions
|
|
555
641
|
###
|
|
@@ -584,8 +670,12 @@ class InteractiveCleanUI:
|
|
|
584
670
|
imdetails['gui']['image']['src'] = imdetails['gui']['cube'].js_obj( )
|
|
585
671
|
imdetails['gui']['image']['fig'] = imdetails['gui']['cube'].image( grid=False, height_policy='max', width_policy='max',
|
|
586
672
|
channelcb=CustomJS( args=dict( img_state={ 'src': imdetails['gui']['image']['src'],
|
|
587
|
-
'flux': imdetails['converge-data']['flux'],
|
|
588
|
-
|
|
673
|
+
'flux': { 'source': imdetails['converge-data']['flux'],
|
|
674
|
+
'axis': imdetails['converge-axes']['flux_axis'],
|
|
675
|
+
'range': imdetails['converge-ranges']['flux_range'] },
|
|
676
|
+
'residual': { 'source': imdetails['converge-data']['residual'],
|
|
677
|
+
'axis': imdetails['converge-axes']['residual_axis'],
|
|
678
|
+
'range': imdetails['converge-ranges']['residual_range'] },
|
|
589
679
|
'cyclethreshold': imdetails['converge-data']['cyclethreshold'] },
|
|
590
680
|
imid=imid,
|
|
591
681
|
ctrl={ 'converge': self._clean['converge'] },
|
|
@@ -701,9 +791,13 @@ class InteractiveCleanUI:
|
|
|
701
791
|
'src': v['gui']['cube'].js_obj( ),
|
|
702
792
|
'spectrum': v['gui']['spectrum'],
|
|
703
793
|
'src': v['gui']['image']['src'],
|
|
704
|
-
'flux': v['converge-data']['flux'],
|
|
794
|
+
'flux': { 'source': v['converge-data']['flux'],
|
|
795
|
+
'axis': v['converge-axes']['flux_axis'],
|
|
796
|
+
'range': v['converge-ranges']['flux_range'] },
|
|
705
797
|
'cyclethreshold': v['converge-data']['cyclethreshold'],
|
|
706
|
-
'residual': v['converge-data']['residual'],
|
|
798
|
+
'residual': { 'source': v['converge-data']['residual'],
|
|
799
|
+
'axis': v['converge-axes']['residual_axis'],
|
|
800
|
+
'range': v['converge-ranges']['residual_range'] },
|
|
707
801
|
'navi': { 'slider': v['gui']['slider'],
|
|
708
802
|
'goto': v['gui']['goto'],
|
|
709
803
|
## it doesn't seem like pixel tracking must be disabled
|
|
@@ -1215,7 +1309,52 @@ class InteractiveCleanUI:
|
|
|
1215
1309
|
### -- The "Insert here ..." code seems to be called when when the stokes plane is changed --
|
|
1216
1310
|
### -- but there have been no tclean iterations yet... --
|
|
1217
1311
|
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
1218
|
-
'update-converge': '''function
|
|
1312
|
+
'update-converge': '''function updateAxisRange(source, range_obj, axis_obj, axis_name) {
|
|
1313
|
+
const data = source.data;
|
|
1314
|
+
const values = data['values'];
|
|
1315
|
+
|
|
1316
|
+
if (values.length === 0) return;
|
|
1317
|
+
|
|
1318
|
+
// Calculate data bounds
|
|
1319
|
+
const min_val = Math.min(...values);
|
|
1320
|
+
const max_val = Math.max(...values);
|
|
1321
|
+
|
|
1322
|
+
// Add padding (10% of range, with minimum padding)
|
|
1323
|
+
const span = max_val - min_val;
|
|
1324
|
+
const padding = max_val != min_val ? Math.max(span * 0.1, Math.abs(max_val * 0.02)) : Math.abs(max_val * 0.1);
|
|
1325
|
+
|
|
1326
|
+
// Update range
|
|
1327
|
+
range_obj.start = min_val - padding;
|
|
1328
|
+
range_obj.end = max_val + padding;
|
|
1329
|
+
|
|
1330
|
+
// Ensure ranges are valid (non-zero span)
|
|
1331
|
+
if ( range_obj.end - range_obj.start < 1e-10 ) {
|
|
1332
|
+
const center = range_obj.start
|
|
1333
|
+
if ( Math.abs(center) < 1e-10 ) {
|
|
1334
|
+
// If center is essentially 0
|
|
1335
|
+
range_obj.start = -0.1
|
|
1336
|
+
range_obj.end = 1.0
|
|
1337
|
+
} else {
|
|
1338
|
+
const span = Math.max(Math.abs(center * 0.2), 0.1)
|
|
1339
|
+
range_obj.start = center - span
|
|
1340
|
+
range_obj.end = center + span
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// Optional: Update tick density
|
|
1345
|
+
if (axis_obj && axis_obj.ticker) {
|
|
1346
|
+
const new_span = range_obj.end - range_obj.start;
|
|
1347
|
+
if (new_span < 10) {
|
|
1348
|
+
axis_obj.ticker.desired_num_ticks = 8;
|
|
1349
|
+
} else if (new_span < 100) {
|
|
1350
|
+
axis_obj.ticker.desired_num_ticks = 10;
|
|
1351
|
+
} else {
|
|
1352
|
+
axis_obj.ticker.desired_num_ticks = 6;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
function update_convergence_single( target, data ) {
|
|
1219
1358
|
const pos = target.src.cur_chan
|
|
1220
1359
|
const imdata = data.get(pos[1]).get(pos[0])
|
|
1221
1360
|
// chan----------------^^^^^^ ^^^^^^----stokes
|
|
@@ -1225,9 +1364,11 @@ class InteractiveCleanUI:
|
|
|
1225
1364
|
const modelFlux = imdata.modelFlux
|
|
1226
1365
|
const stopCode = imdata.stopCode
|
|
1227
1366
|
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') }
|
|
1367
|
+
target.residual.source.data = { iterations, cyclethreshold, stopDesc, values: peakRes, type: Array(iterations.length).fill('residual') }
|
|
1368
|
+
target.flux.source.data = { iterations, cyclethreshold, stopDesc, values: modelFlux, type: Array(iterations.length).fill('flux') }
|
|
1230
1369
|
target.cyclethreshold.data = { iterations, values: cyclethreshold }
|
|
1370
|
+
updateAxisRange( target.flux.source, target.flux.range, target.flux.axis, 'Flux' )
|
|
1371
|
+
updateAxisRange( target.residual.source, target.residual.range, target.residual.axis, 'Residual' )
|
|
1231
1372
|
}
|
|
1232
1373
|
|
|
1233
1374
|
function update_convergence( recurse=false ) {
|
|
@@ -95,9 +95,9 @@ cubevis/remote/_local.py,sha256=PcPCFcwttTFZd3O33-5pqDuGKQKK6CA0gz1MTIkTiNI,1032
|
|
|
95
95
|
cubevis/remote/_remote_kernel.py,sha256=wfu7ZzKn-oCxZxzDIkC5puBvGf8WbCLYL3CzM56_FNc,2652
|
|
96
96
|
cubevis/toolbox/__init__.py,sha256=xzqwAG9863d7UKBVBRw7FrRUQbvCdFcLBq4vTpg63DU,1487
|
|
97
97
|
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=
|
|
98
|
+
cubevis/toolbox/_cube.py,sha256=Qj6aY_0x9nZkdIymGSwEFhBYg_tXv7H5zrjERAFLwXQ,294690
|
|
99
|
+
cubevis/toolbox/_interactive_clean_ui.mustache,sha256=KtcTGDa-vBB2_hIug7kNimICcJk1KavS0vMyf_qGRIE,111003
|
|
100
|
+
cubevis/toolbox/_interactive_clean_ui.py,sha256=iaBpVin0iRBvcW1mXpSjEj6rTyQn3f3Zhd-AHS1fqOw,110914
|
|
101
101
|
cubevis/toolbox/_interactiveclean_wrappers.py,sha256=XqyCGz33CMDhszTxnwZ_3-64GszUK1XYnGKUOxl9sas,5071
|
|
102
102
|
cubevis/toolbox/_region_list.py,sha256=_1RvnXwqMoaAq8CPy-6IyhabLi_snXqO566onehI2y0,8957
|
|
103
103
|
cubevis/utils/_ResourceManager.py,sha256=SaaR29etabRiKxmUK-aWvAm4v_OPFJH8CX7bNFm0Lgo,3410
|
|
@@ -114,8 +114,8 @@ cubevis/utils/_pkgs.py,sha256=mu2CCzndmJZYP81UkFhxveW_CisWLUvagJVolHOEVgM,2294
|
|
|
114
114
|
cubevis/utils/_regions.py,sha256=TdAg4ZUUyhg3nFmX9_KLboqmc0LkyOdEW8M1WDR5Udk,1669
|
|
115
115
|
cubevis/utils/_static.py,sha256=rN-sqXNqQ5R2M3wmPHU1GPP5OTyyWQlUPRuimCrht-g,2347
|
|
116
116
|
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.
|
|
117
|
+
cubevis/__version__.py,sha256=aydFbhyyvNka8P6vHcHfdWlGmQCUwCmq7WC1N73zpFA,22
|
|
118
|
+
cubevis-0.5.24.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
119
|
+
cubevis-0.5.24.dist-info/METADATA,sha256=ISXKMsHZaJ2gDD1q-D_Jedxy0cmAP7iyccFmnsjllEk,2629
|
|
120
|
+
cubevis-0.5.24.dist-info/licenses/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
|
|
121
|
+
cubevis-0.5.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|