@@ -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
@@ -338,9 +338,7 @@ def _create_dash_components(self):
338
338
339
339
# The (float) position (in scene coords) of the current slice,
340
340
# used to publish our position to slicers with the same scene_id.
341
- self ._pos = Store (
342
- id = self ._subid ("pos" , True , axis = self ._axis ), data = initial_pos
343
- )
341
+ self ._pos = Store (id = self ._subid ("pos" , True ), data = initial_pos )
344
342
345
343
# Signal to set the position of other slicers with the same scene_id.
346
344
self ._setpos = Store (id = self ._subid ("setpos" , True ), data = None )
@@ -500,10 +498,17 @@ def _create_client_callbacks(self):
500
498
# ----------------------------------------------------------------------
501
499
# Callback to update position (in scene coordinates) from the index.
502
500
501
+ # todo: replace index store with this info, drop the pos store
502
+ # todo: include info about axis range
503
503
app .clientside_callback (
504
504
"""
505
505
function update_pos(index, info) {
506
- return info.origin[2] + index * info.spacing[2];
506
+ return {
507
+ index: index,
508
+ pos: info.origin[2] + index * info.spacing[2],
509
+ axis: info.axis,
510
+ color: info.color,
511
+ };
507
512
}
508
513
""" ,
509
514
Output (self ._pos .id , "data" ),
@@ -577,32 +582,45 @@ def _create_client_callbacks(self):
577
582
578
583
app .clientside_callback (
579
584
"""
580
- function update_indicator_traces(positions1, positions2, info, current ) {
585
+ function update_indicator_traces(states, info) {
581
586
let x0 = info.origin[0], y0 = info.origin[1];
582
587
let x1 = x0 + info.size[0] * info.spacing[0], y1 = y0 + info.size[1] * info.spacing[1];
583
588
x0 = x0 - info.spacing[0], y0 = y0 - info.spacing[1];
584
589
let d = ((x1 - x0) + (y1 - y0)) * 0.5 * 0.05;
585
- let version = (current.version || 0) + 1;
586
- let x = [], y = [];
587
- for (let pos of positions1) {
588
- // x relative to our slice, y in scene-coords
589
- x.push(...[x0 - d, x0, null, x1, x1 + d, null]);
590
- y.push(...[pos, pos, pos, pos, pos, pos]);
590
+
591
+ let axii = [0, 1, 2];
592
+ axii.splice(info.axis, 1);
593
+ let traces = [];
594
+
595
+ for (let state of states) {
596
+ let pos = state.pos;
597
+ if (state.axis == axii[0]) {
598
+ // x relative to our slice, y in scene-coords
599
+ traces.push({
600
+ //x: [x0 - d, x0, null, x1, x1 + d, null],
601
+ x: [x0, x1],
602
+ y: [pos, pos],
603
+ line: {color: state.color, width: 1}
604
+ });
605
+ } else if (state.axis == axii[1]) {
606
+ // x in scene-coords, y relative to our slice
607
+ traces.push({
608
+ x: [pos, pos],
609
+ y: [y0, y1],
610
+ //y: [y0 - d, y0, null, y1, y1 + d, null],
611
+ line: {color: state.color, width: 1}
612
+ });
613
+ }
591
614
}
592
- for (let pos of positions2) {
593
- // x in scene-coords, y relative to our slice
594
- x.push(...[pos, pos, pos, pos, pos, pos]);
595
- y.push(...[y0 - d, y0, null, y1, y1 + d, null]);
615
+
616
+ for (let trace of traces) {
617
+ trace.type = 'scatter';
618
+ trace.mode = 'lines';
619
+ trace.hoverinfo = 'skip';
620
+ trace.showlegend = false;
596
621
}
597
- return [{
598
- type: 'scatter',
599
- mode: 'lines',
600
- line: {color: '#ff00aa'},
601
- x: x,
602
- y: y,
603
- hoverinfo: 'skip',
604
- version: version
605
- }];
622
+
623
+ return traces;
606
624
}
607
625
""" ,
608
626
Output (self ._indicator_traces .id , "data" ),
@@ -612,15 +630,12 @@ def _create_client_callbacks(self):
612
630
"scene" : self ._scene_id ,
613
631
"context" : ALL ,
614
632
"name" : "pos" ,
615
- "axis" : axis ,
616
633
},
617
634
"data" ,
618
635
)
619
- for axis in self ._other_axii
620
636
],
621
637
[
622
638
State (self ._info .id , "data" ),
623
- State (self ._indicator_traces .id , "data" ),
624
639
],
625
640
)
626
641
@@ -629,26 +644,42 @@ def _create_client_callbacks(self):
629
644
630
645
app .clientside_callback (
631
646
"""
632
- function update_figure(img_traces, indicators, ori_figure) {
647
+ function update_figure(img_traces, indicators, ori_figure, info ) {
633
648
634
649
// Collect traces
635
650
let traces = [];
636
651
for (let trace of img_traces) { traces.push(trace); }
637
652
for (let trace of indicators) { traces.push(trace); }
638
653
654
+ // Show our own color as a rectangle around the image,
655
+ // But only if there are multiple slicers with the same scene id.
656
+ let shapes = [];
657
+ if (indicators.length > 1) {
658
+ shapes.push({
659
+ type: 'rect',
660
+ //xref: 'paper', yref: 'paper', x0: 0, y0: 0, x1: 1, y1: 1,
661
+ xref: 'x', yref: 'y',
662
+ x0: info.origin[0] - info.spacing[0]/2, y0: info.origin[1] - info.spacing[1]/2,
663
+ x1: info.origin[0] + (info.size[0] - 0.5) * info.spacing[0], y1: info.origin[1] + (info.size[1] - 0.5) * info.spacing[1],
664
+ line: {color: info.color, width: 3}
665
+ });
666
+ }
667
+
639
668
// Update figure
640
669
let figure = {...ori_figure};
641
670
figure.data = traces;
671
+ figure.layout.shapes = shapes;
642
672
643
673
return figure;
644
674
}
645
675
""" ,
646
- Output (self .graph .id , "figure" ),
676
+ Output (self ._graph .id , "figure" ),
647
677
[
648
678
Input (self ._img_traces .id , "data" ),
649
679
Input (self ._indicator_traces .id , "data" ),
650
680
],
651
681
[
652
- State (self .graph .id , "figure" ),
682
+ State (self ._graph .id , "figure" ),
683
+ State (self ._info .id , "data" ),
653
684
],
654
685
)
0 commit comments