13
13
from _plotly_utils .utils import _natural_sort_strings , _get_int_type
14
14
from .optional_imports import get_module
15
15
16
+ from . import shapeannotation
17
+
16
18
# Create Undefined sentinel value
17
19
# - Setting a property to None removes any existing value
18
20
# - Setting a property to Undefined leaves existing value unmodified
@@ -3548,7 +3550,9 @@ def _index_is(iterable, val):
3548
3550
3549
3551
return index_list [0 ]
3550
3552
3551
- def _make_axis_spanning_shape (self , direction , shape , none_if_no_trace = True ):
3553
+ def _make_axis_spanning_layout_object (
3554
+ self , direction , shape , none_if_no_trace = True
3555
+ ):
3552
3556
"""
3553
3557
Convert a shape drawn on a plot or a subplot into one whose yref or xref
3554
3558
ends with " domain" and has coordinates so that the shape will seem to
@@ -3559,6 +3563,7 @@ def _make_axis_spanning_shape(self, direction, shape, none_if_no_trace=True):
3559
3563
corresponding axis reference referring to an actual axis (e.g., 'x',
3560
3564
'y2' etc. are accepted, but not 'paper'). This will be the case if the
3561
3565
shape was added with "add_shape".
3566
+ Shape must have the x0, x1, y0, y1 fields already initialized.
3562
3567
"""
3563
3568
if direction == "vertical" :
3564
3569
# fix y points to top and bottom of subplot
@@ -3575,12 +3580,6 @@ def _make_axis_spanning_shape(self, direction, shape, none_if_no_trace=True):
3575
3580
"Bad direction: %s. Permissible values are 'vertical' and 'horizontal'."
3576
3581
% (direction ,)
3577
3582
)
3578
- # vline and hline span the whole axis
3579
- domain = [0 , 1 ]
3580
- try :
3581
- shape [axis + "0" ], shape [axis + "1" ] = domain
3582
- except KeyError as e :
3583
- raise e ("Shape does not support axis spanning." )
3584
3583
if none_if_no_trace :
3585
3584
# iterate through all the traces and check to see if one with the
3586
3585
# same xref and yref pair is there, if not, we return None (we don't
@@ -3608,42 +3607,69 @@ def _process_multiple_axis_spanning_shapes(
3608
3607
shape_args ,
3609
3608
row ,
3610
3609
col ,
3611
- direction ,
3610
+ shape_type ,
3612
3611
exclude_empty_subplots = True ,
3613
3612
annotation = None ,
3614
3613
** kwargs
3615
3614
):
3616
3615
"""
3617
- Add a shape or multiple shapes and call _make_axis_spanning_shape on
3616
+ Add a shape or multiple shapes and call _make_axis_spanning_layout_object on
3618
3617
all the new shapes.
3619
3618
"""
3619
+ if shape_type in ["vline" , "vrect" ]:
3620
+ direction = "vertical"
3621
+ elif shape_type in ["hline" , "hrect" ]:
3622
+ direction = "horizontal"
3623
+ else :
3624
+ raise ValueError (
3625
+ "Bad shape_type %s, needs to be one of 'vline', 'hline', 'vrect', 'hrect'"
3626
+ % (shape_type ,)
3627
+ )
3628
+
3629
+ n_shapes_before = len (self .layout ["shapes" ])
3630
+ n_annotations_before = len (self .layout ["annotations" ])
3620
3631
# shapes are always added at the end of the tuple of shapes, so we see
3621
3632
# how long the tuple is before the call and after the call, and adjust
3622
3633
# the new shapes that were added at the end
3623
- n_shapes_before = len (self .layout ["shapes" ])
3624
- self .add_shape (row = row , col = col , ** _combine_dicts ([shape_args , kwargs ]))
3625
- if row == None and col == None :
3626
- # this was called intending to add to a single plot (and
3627
- # self.add_shape succeeded)
3628
- # however, in the case of a single plot, xref and yref are not
3629
- # specified, so we specify them here so the following routines can work
3630
- # (they need to append " domain" to xref or yref)
3631
- self .layout ["shapes" ][- 1 ].update (xref = "x" , yref = "y" )
3632
- n_shapes_after = len (self .layout ["shapes" ])
3633
- new_shapes = tuple (
3634
- filter (
3635
- lambda x : x is not None ,
3636
- [
3637
- self ._make_axis_spanning_shape (
3638
- direction ,
3639
- self .layout ["shapes" ][n ],
3640
- none_if_no_trace = exclude_empty_subplots ,
3641
- )
3642
- for n in range (n_shapes_before , n_shapes_after )
3643
- ],
3644
- )
3634
+ # extract annotation prefixed kwargs
3635
+ # annotation with extra parameters based on the annotation_position
3636
+ # argument and other annotation_ prefixed kwargs
3637
+ shape_kwargs , annotation_kwargs = shapeannotation .split_dict_by_key_prefix (
3638
+ kwargs , "annotation_"
3645
3639
)
3646
- self .layout ["shapes" ] = self .layout ["shapes" ][:n_shapes_before ] + new_shapes
3640
+ augmented_annotation = shapeannotation .axis_spanning_shape_annotation (
3641
+ annotation , shape_type , shape_args , annotation_kwargs
3642
+ )
3643
+ self .add_shape (row = row , col = col , ** _combine_dicts ([shape_args , shape_kwargs ]))
3644
+ self .add_annotation (augmented_annotation , row = row , col = col )
3645
+ # update xref and yref for the new shapes and annotations
3646
+ for layout_obj , n_layout_objs_before in zip (
3647
+ ["shapes" , "annotations" ], [n_shapes_before , n_annotations_before ]
3648
+ ):
3649
+ if row == None and col == None :
3650
+ # this was called intending to add to a single plot (and
3651
+ # self.add_{layout_obj} succeeded)
3652
+ # however, in the case of a single plot, xref and yref are not
3653
+ # specified, so we specify them here so the following routines can work
3654
+ # (they need to append " domain" to xref or yref)
3655
+ self .layout [layout_obj ][- 1 ].update (xref = "x" , yref = "y" )
3656
+ n_layout_objs_after = len (self .layout [layout_obj ])
3657
+ new_layout_objs = tuple (
3658
+ filter (
3659
+ lambda x : x is not None ,
3660
+ [
3661
+ self ._make_axis_spanning_layout_object (
3662
+ direction ,
3663
+ self .layout [layout_obj ][n ],
3664
+ none_if_no_trace = exclude_empty_subplots ,
3665
+ )
3666
+ for n in range (n_layout_objs_before , n_layout_objs_after )
3667
+ ],
3668
+ )
3669
+ )
3670
+ self .layout [layout_obj ] = (
3671
+ self .layout [layout_obj ][:n_layout_objs_before ] + new_layout_objs
3672
+ )
3647
3673
3648
3674
def add_vline (
3649
3675
self ,
@@ -3678,7 +3704,7 @@ def add_vline(
3678
3704
dict (type = "line" , x0 = x , x1 = x , y0 = 0 , y1 = 1 ),
3679
3705
row ,
3680
3706
col ,
3681
- "vertical " ,
3707
+ "vline " ,
3682
3708
exclude_empty_subplots = exclude_empty_subplots ,
3683
3709
annotation = annotation ,
3684
3710
** kwargs
@@ -3710,7 +3736,7 @@ def add_hline(self, y, row=None, col=None, exclude_empty_subplots=True, **kwargs
3710
3736
dict (type = "line" , x0 = 0 , x1 = 1 , y0 = y , y1 = y ,),
3711
3737
row ,
3712
3738
col ,
3713
- "horizontal " ,
3739
+ "hline " ,
3714
3740
exclude_empty_subplots = exclude_empty_subplots ,
3715
3741
** kwargs
3716
3742
)
@@ -3745,7 +3771,7 @@ def add_vrect(
3745
3771
dict (type = "rect" , x0 = x0 , x1 = x1 , y0 = 0 , y1 = 1 ),
3746
3772
row ,
3747
3773
col ,
3748
- "vertical " ,
3774
+ "vrect " ,
3749
3775
exclude_empty_subplots = exclude_empty_subplots ,
3750
3776
** kwargs
3751
3777
)
@@ -3780,7 +3806,7 @@ def add_hrect(
3780
3806
dict (type = "rect" , x0 = 0 , x1 = 1 , y0 = y0 , y1 = y1 ),
3781
3807
row ,
3782
3808
col ,
3783
- "horizontal " ,
3809
+ "hrect " ,
3784
3810
exclude_empty_subplots = exclude_empty_subplots ,
3785
3811
** kwargs
3786
3812
)
0 commit comments