@@ -25,7 +25,7 @@ def findAsyncPlotlyJs(scripts):
25
25
26
26
27
27
@pytest .mark .parametrize ("is_eager" , [True , False ])
28
- def test_candlestick (dash_dcc , is_eager ):
28
+ def test_grva001_candlestick (dash_dcc , is_eager ):
29
29
app = dash .Dash (__name__ , eager_loading = is_eager )
30
30
app .layout = html .Div (
31
31
[
@@ -75,7 +75,7 @@ def update_graph(n_clicks):
75
75
76
76
77
77
@pytest .mark .parametrize ("is_eager" , [True , False ])
78
- def test_graphs_with_different_figures (dash_dcc , is_eager ):
78
+ def test_grva002_graphs_with_different_figures (dash_dcc , is_eager ):
79
79
app = dash .Dash (__name__ , eager_loading = is_eager )
80
80
app .layout = html .Div (
81
81
[
@@ -160,7 +160,7 @@ def show_relayout_data(data):
160
160
161
161
162
162
@pytest .mark .parametrize ("is_eager" , [True , False ])
163
- def test_empty_graph (dash_dcc , is_eager ):
163
+ def test_grva003_empty_graph (dash_dcc , is_eager ):
164
164
app = dash .Dash (__name__ , eager_loading = is_eager )
165
165
166
166
app .layout = html .Div (
@@ -193,7 +193,7 @@ def render_content(click, prev_graph):
193
193
194
194
195
195
@pytest .mark .parametrize ("is_eager" , [True , False ])
196
- def test_graph_prepend_trace (dash_dcc , is_eager ):
196
+ def test_grva004_graph_prepend_trace (dash_dcc , is_eager ):
197
197
app = dash .Dash (__name__ , eager_loading = is_eager )
198
198
199
199
def generate_with_id (id , data = None ):
@@ -358,7 +358,7 @@ def display_data(trigger, fig):
358
358
359
359
360
360
@pytest .mark .parametrize ("is_eager" , [True , False ])
361
- def test_graph_extend_trace (dash_dcc , is_eager ):
361
+ def test_grva005_graph_extend_trace (dash_dcc , is_eager ):
362
362
app = dash .Dash (__name__ , eager_loading = is_eager )
363
363
364
364
def generate_with_id (id , data = None ):
@@ -521,7 +521,7 @@ def display_data(trigger, fig):
521
521
522
522
523
523
@pytest .mark .parametrize ("is_eager" , [True , False ])
524
- def test_unmounted_graph_resize (dash_dcc , is_eager ):
524
+ def test_grva006_unmounted_graph_resize (dash_dcc , is_eager ):
525
525
app = dash .Dash (__name__ , eager_loading = is_eager )
526
526
527
527
app .layout = html .Div (
@@ -619,7 +619,7 @@ def test_unmounted_graph_resize(dash_dcc, is_eager):
619
619
dash_dcc .driver .set_window_size (window_size ["width" ], window_size ["height" ])
620
620
621
621
622
- def test_external_plotlyjs_prevents_lazy (dash_dcc ):
622
+ def test_grva007_external_plotlyjs_prevents_lazy (dash_dcc ):
623
623
app = dash .Dash (
624
624
__name__ ,
625
625
eager_loading = False ,
@@ -658,3 +658,168 @@ def load_chart(n_clicks):
658
658
scripts = dash_dcc .driver .find_elements (By .CSS_SELECTOR , "script" )
659
659
assert findSyncPlotlyJs (scripts ) is None
660
660
assert findAsyncPlotlyJs (scripts ) is None
661
+
662
+
663
+ def test_grva008_shapes_not_lost (dash_dcc ):
664
+ # See issue #879 and pr #905
665
+ app = dash .Dash (__name__ )
666
+
667
+ fig = {"data" : [], "layout" : {"dragmode" : "drawrect" }}
668
+ graph = dcc .Graph (id = "graph" , figure = fig , style = {"height" : "400px" })
669
+
670
+ app .layout = html .Div (
671
+ [
672
+ graph ,
673
+ html .Br (),
674
+ html .Button (id = "button" , children = "Clone figure" ),
675
+ html .Div (id = "output" , children = "" ),
676
+ ]
677
+ )
678
+
679
+ app .clientside_callback (
680
+ """
681
+ function clone_figure(_, figure) {
682
+ const new_figure = {...figure};
683
+ const shapes = new_figure.layout.shapes || [];
684
+ return [new_figure, shapes.length];
685
+ }
686
+ """ ,
687
+ Output ("graph" , "figure" ),
688
+ Output ("output" , "children" ),
689
+ Input ("button" , "n_clicks" ),
690
+ State ("graph" , "figure" ),
691
+ )
692
+
693
+ dash_dcc .start_server (app )
694
+ button = dash_dcc .wait_for_element ("#button" )
695
+ dash_dcc .wait_for_text_to_equal ("#output" , "0" )
696
+
697
+ # Draw a shape
698
+ dash_dcc .click_and_hold_at_coord_fractions ("#graph" , 0.25 , 0.25 )
699
+ dash_dcc .move_to_coord_fractions ("#graph" , 0.35 , 0.75 )
700
+ dash_dcc .release ()
701
+
702
+ # Click to trigger an update of the output, the shape should survive
703
+ dash_dcc .wait_for_text_to_equal ("#output" , "0" )
704
+ button .click ()
705
+ dash_dcc .wait_for_text_to_equal ("#output" , "1" )
706
+
707
+ # Draw another shape
708
+ dash_dcc .click_and_hold_at_coord_fractions ("#graph" , 0.75 , 0.25 )
709
+ dash_dcc .move_to_coord_fractions ("#graph" , 0.85 , 0.75 )
710
+ dash_dcc .release ()
711
+
712
+ # Click to trigger an update of the output, the shape should survive
713
+ dash_dcc .wait_for_text_to_equal ("#output" , "1" )
714
+ button .click ()
715
+ dash_dcc .wait_for_text_to_equal ("#output" , "2" )
716
+
717
+
718
+ @pytest .mark .parametrize ("mutate_fig" , [True , False ])
719
+ def test_grva009_originals_maintained_for_responsive_override (mutate_fig , dash_dcc ):
720
+ # In #905 we made changes to prevent shapes from being lost.
721
+ # This test makes sure that the overrides applied by the `responsive`
722
+ # prop are "undone" when the `responsive` prop changes.
723
+
724
+ app = dash .Dash (__name__ )
725
+
726
+ graph = dcc .Graph (
727
+ id = "graph" ,
728
+ figure = {"data" : [{"y" : [1 , 2 ]}], "layout" : {"width" : 300 , "height" : 250 }},
729
+ style = {"height" : "400px" , "width" : "500px" },
730
+ )
731
+ responsive_size = [500 , 400 ]
732
+ fixed_size = [300 , 250 ]
733
+
734
+ app .layout = html .Div (
735
+ [
736
+ graph ,
737
+ html .Br (),
738
+ html .Button (id = "edit_figure" , children = "Edit figure" ),
739
+ html .Button (id = "edit_responsive" , children = "Edit responsive" ),
740
+ html .Div (id = "output" , children = "" ),
741
+ ]
742
+ )
743
+
744
+ if mutate_fig :
745
+ # Modify the layout in place (which still has changes made by responsive)
746
+ change_fig = """
747
+ figure.layout.title = {text: String(n_fig || 0)};
748
+ const new_figure = {...figure};
749
+ """
750
+ else :
751
+ # Or create a new one each time
752
+ change_fig = """
753
+ const new_figure = {
754
+ data: [{y: [1, 2]}],
755
+ layout: {width: 300, height: 250, title: {text: String(n_fig || 0)}}
756
+ };
757
+ """
758
+
759
+ callback = (
760
+ """
761
+ function clone_figure(n_fig, n_resp, figure) {
762
+ """
763
+ + change_fig
764
+ + """
765
+ let responsive = [true, false, 'auto'][(n_resp || 0) % 3];
766
+ return [new_figure, responsive, (n_fig || 0) + ' ' + responsive];
767
+ }
768
+ """
769
+ )
770
+
771
+ app .clientside_callback (
772
+ callback ,
773
+ Output ("graph" , "figure" ),
774
+ Output ("graph" , "responsive" ),
775
+ Output ("output" , "children" ),
776
+ Input ("edit_figure" , "n_clicks" ),
777
+ Input ("edit_responsive" , "n_clicks" ),
778
+ State ("graph" , "figure" ),
779
+ )
780
+
781
+ dash_dcc .start_server (app )
782
+ edit_figure = dash_dcc .wait_for_element ("#edit_figure" )
783
+ edit_responsive = dash_dcc .wait_for_element ("#edit_responsive" )
784
+
785
+ def graph_dims ():
786
+ return dash_dcc .driver .execute_script (
787
+ """
788
+ const layout = document.querySelector('.js-plotly-plot')._fullLayout;
789
+ return [layout.width, layout.height];
790
+ """
791
+ )
792
+
793
+ dash_dcc .wait_for_text_to_equal ("#output" , "0 true" )
794
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "0" )
795
+ assert graph_dims () == responsive_size
796
+
797
+ edit_figure .click ()
798
+ dash_dcc .wait_for_text_to_equal ("#output" , "1 true" )
799
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "1" )
800
+ assert graph_dims () == responsive_size
801
+
802
+ edit_responsive .click ()
803
+ dash_dcc .wait_for_text_to_equal ("#output" , "1 false" )
804
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "1" )
805
+ assert graph_dims () == fixed_size
806
+
807
+ edit_figure .click ()
808
+ dash_dcc .wait_for_text_to_equal ("#output" , "2 false" )
809
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "2" )
810
+ assert graph_dims () == fixed_size
811
+
812
+ edit_responsive .click ()
813
+ dash_dcc .wait_for_text_to_equal ("#output" , "2 auto" )
814
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "2" )
815
+ assert graph_dims () == fixed_size
816
+
817
+ edit_figure .click ()
818
+ dash_dcc .wait_for_text_to_equal ("#output" , "3 auto" )
819
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "3" )
820
+ assert graph_dims () == fixed_size
821
+
822
+ edit_responsive .click ()
823
+ dash_dcc .wait_for_text_to_equal ("#output" , "3 true" )
824
+ dash_dcc .wait_for_text_to_equal (".gtitle" , "3" )
825
+ assert graph_dims () == responsive_size
0 commit comments