@@ -30,6 +30,7 @@ class VolumeSlicer:
30
30
scene_id (str): the scene that this slicer is part of. Slicers
31
31
that have the same scene-id show each-other's positions with
32
32
line indicators. By default this is derived from ``id(volume)``.
33
+ color (str): the color for this slicer.
33
34
34
35
This is a placeholder object, not a Dash component. The components
35
36
that make up the slicer can be accessed as attributes. These must all
@@ -73,6 +74,7 @@ def __init__(
73
74
axis = 0 ,
74
75
reverse_y = True ,
75
76
scene_id = None ,
77
+ color = None ,
76
78
):
77
79
78
80
if not isinstance (app , Dash ):
@@ -93,9 +95,6 @@ def __init__(
93
95
raise ValueError ("The given axis must be 0, 1, or 2." )
94
96
self ._axis = int (axis )
95
97
self ._reverse_y = bool (reverse_y )
96
- # Select the *other* axii
97
- self ._other_axii = [0 , 1 , 2 ]
98
- self ._other_axii .pop (self ._axis )
99
98
100
99
# Check and store scene id, and generate
101
100
if scene_id is None :
@@ -116,6 +115,7 @@ def __init__(
116
115
"size" : shape3d_to_size2d (volume .shape , axis ),
117
116
"origin" : shape3d_to_size2d (origin , axis ),
118
117
"spacing" : shape3d_to_size2d (spacing , axis ),
118
+ "color" : color or "#00ffff" ,
119
119
}
120
120
121
121
# Build the slicer
@@ -340,9 +340,7 @@ def _create_dash_components(self):
340
340
341
341
# The (float) position (in scene coords) of the current slice,
342
342
# used to publish our position to slicers with the same scene_id.
343
- self ._pos = Store (
344
- id = self ._subid ("pos" , True , axis = self ._axis ), data = initial_pos
345
- )
343
+ self ._pos = Store (id = self ._subid ("pos" , True ), data = initial_pos )
346
344
347
345
# Signal to set the position of other slicers with the same scene_id.
348
346
self ._setpos = Store (id = self ._subid ("setpos" , True ), data = None )
@@ -502,10 +500,17 @@ def _create_client_callbacks(self):
502
500
# ----------------------------------------------------------------------
503
501
# Callback to update position (in scene coordinates) from the index.
504
502
503
+ # todo: replace index store with this info, drop the pos store
504
+ # todo: include info about axis range
505
505
app .clientside_callback (
506
506
"""
507
507
function update_pos(index, info) {
508
- return info.origin[2] + index * info.spacing[2];
508
+ return {
509
+ index: index,
510
+ pos: info.origin[2] + index * info.spacing[2],
511
+ axis: info.axis,
512
+ color: info.color,
513
+ };
509
514
}
510
515
""" ,
511
516
Output (self ._pos .id , "data" ),
@@ -579,32 +584,45 @@ def _create_client_callbacks(self):
579
584
580
585
app .clientside_callback (
581
586
"""
582
- function update_indicator_traces(positions1, positions2, info, current ) {
587
+ function update_indicator_traces(states, info) {
583
588
let x0 = info.origin[0], y0 = info.origin[1];
584
589
let x1 = x0 + info.size[0] * info.spacing[0], y1 = y0 + info.size[1] * info.spacing[1];
585
590
x0 = x0 - info.spacing[0], y0 = y0 - info.spacing[1];
586
591
let d = ((x1 - x0) + (y1 - y0)) * 0.5 * 0.05;
587
- let version = (current.version || 0) + 1;
588
- let x = [], y = [];
589
- for (let pos of positions1) {
590
- // x relative to our slice, y in scene-coords
591
- x.push(...[x0 - d, x0, null, x1, x1 + d, null]);
592
- y.push(...[pos, pos, pos, pos, pos, pos]);
592
+
593
+ let axii = [0, 1, 2];
594
+ axii.splice(info.axis, 1);
595
+ let traces = [];
596
+
597
+ for (let state of states) {
598
+ let pos = state.pos;
599
+ if (state.axis == axii[0]) {
600
+ // x relative to our slice, y in scene-coords
601
+ traces.push({
602
+ //x: [x0 - d, x0, null, x1, x1 + d, null],
603
+ x: [x0, x1],
604
+ y: [pos, pos],
605
+ line: {color: state.color, width: 1}
606
+ });
607
+ } else if (state.axis == axii[1]) {
608
+ // x in scene-coords, y relative to our slice
609
+ traces.push({
610
+ x: [pos, pos],
611
+ y: [y0, y1],
612
+ //y: [y0 - d, y0, null, y1, y1 + d, null],
613
+ line: {color: state.color, width: 1}
614
+ });
615
+ }
593
616
}
594
- for (let pos of positions2) {
595
- // x in scene-coords, y relative to our slice
596
- x.push(...[pos, pos, pos, pos, pos, pos]);
597
- y.push(...[y0 - d, y0, null, y1, y1 + d, null]);
617
+
618
+ for (let trace of traces) {
619
+ trace.type = 'scatter';
620
+ trace.mode = 'lines';
621
+ trace.hoverinfo = 'skip';
622
+ trace.showlegend = false;
598
623
}
599
- return [{
600
- type: 'scatter',
601
- mode: 'lines',
602
- line: {color: '#ff00aa'},
603
- x: x,
604
- y: y,
605
- hoverinfo: 'skip',
606
- version: version
607
- }];
624
+
625
+ return traces;
608
626
}
609
627
""" ,
610
628
Output (self ._indicator_traces .id , "data" ),
@@ -614,15 +632,12 @@ def _create_client_callbacks(self):
614
632
"scene" : self ._scene_id ,
615
633
"context" : ALL ,
616
634
"name" : "pos" ,
617
- "axis" : axis ,
618
635
},
619
636
"data" ,
620
637
)
621
- for axis in self ._other_axii
622
638
],
623
639
[
624
640
State (self ._info .id , "data" ),
625
- State (self ._indicator_traces .id , "data" ),
626
641
],
627
642
)
628
643
@@ -631,26 +646,42 @@ def _create_client_callbacks(self):
631
646
632
647
app .clientside_callback (
633
648
"""
634
- function update_figure(img_traces, indicators, ori_figure) {
649
+ function update_figure(img_traces, indicators, ori_figure, info ) {
635
650
636
651
// Collect traces
637
652
let traces = [];
638
653
for (let trace of img_traces) { traces.push(trace); }
639
654
for (let trace of indicators) { traces.push(trace); }
640
655
656
+ // Show our own color as a rectangle around the image,
657
+ // But only if there are multiple slicers with the same scene id.
658
+ let shapes = [];
659
+ if (indicators.length > 1) {
660
+ shapes.push({
661
+ type: 'rect',
662
+ //xref: 'paper', yref: 'paper', x0: 0, y0: 0, x1: 1, y1: 1,
663
+ xref: 'x', yref: 'y',
664
+ x0: info.origin[0] - info.spacing[0]/2, y0: info.origin[1] - info.spacing[1]/2,
665
+ x1: info.origin[0] + (info.size[0] - 0.5) * info.spacing[0], y1: info.origin[1] + (info.size[1] - 0.5) * info.spacing[1],
666
+ line: {color: info.color, width: 3}
667
+ });
668
+ }
669
+
641
670
// Update figure
642
671
let figure = {...ori_figure};
643
672
figure.data = traces;
673
+ figure.layout.shapes = shapes;
644
674
645
675
return figure;
646
676
}
647
677
""" ,
648
- Output (self .graph .id , "figure" ),
678
+ Output (self ._graph .id , "figure" ),
649
679
[
650
680
Input (self ._img_traces .id , "data" ),
651
681
Input (self ._indicator_traces .id , "data" ),
652
682
],
653
683
[
654
- State (self .graph .id , "figure" ),
684
+ State (self ._graph .id , "figure" ),
685
+ State (self ._info .id , "data" ),
655
686
],
656
687
)
0 commit comments