Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c259f1a

Browse files
Wrote hline etc. tests for subplots
Still need to test adding to empty subplots and adding to single plot.
1 parent be05c07 commit c259f1a

File tree

2 files changed

+249
-14
lines changed

2 files changed

+249
-14
lines changed

packages/python/plotly/plotly/basedatatypes.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,11 +3522,19 @@ def _make_paper_spanning_shape(self, direction, shape, none_if_no_trace=True):
35223522
for t in [(d["xaxis"], d["yaxis"]) for d in self.data]
35233523
):
35243524
return None
3525+
# set the ref to paper so that it always spans to the edges of the
3526+
# subplot
35253527
shape[ref] = "paper"
35263528
return shape
35273529

35283530
def _process_multiple_paper_spanning_shapes(
3529-
self, shape_args, row, col, direction, **kwargs
3531+
self,
3532+
shape_args,
3533+
row,
3534+
col,
3535+
direction,
3536+
exclude_subplots_without_data=True,
3537+
**kwargs
35303538
):
35313539
"""
35323540
Add a shape or multiple shapes and call _make_paper_spanning_shape on
@@ -3542,14 +3550,20 @@ def _process_multiple_paper_spanning_shapes(
35423550
filter(
35433551
lambda x: x is not None,
35443552
[
3545-
self._make_paper_spanning_shape(direction, self.layout["shapes"][n])
3553+
self._make_paper_spanning_shape(
3554+
direction,
3555+
self.layout["shapes"][n],
3556+
none_if_no_trace=exclude_subplots_without_data,
3557+
)
35463558
for n in range(n_shapes_before, n_shapes_after)
35473559
],
35483560
)
35493561
)
35503562
self.layout["shapes"] = self.layout["shapes"][:n_shapes_before] + new_shapes
35513563

3552-
def add_vline(self, x, row=None, col=None, **kwargs):
3564+
def add_vline(
3565+
self, x, row=None, col=None, exclude_subplots_without_data=True, **kwargs
3566+
):
35533567
"""
35543568
Add a vertical line to a plot or subplot that extends infinitely in the
35553569
y-dimension.
@@ -3571,11 +3585,18 @@ def add_vline(self, x, row=None, col=None, **kwargs):
35713585
except for x0, x1, y0, y1 or type.
35723586
"""
35733587
self._process_multiple_paper_spanning_shapes(
3574-
dict(type="line", x0=x, x1=x, y0=0, y1=1), row, col, "vertical", **kwargs
3588+
dict(type="line", x0=x, x1=x, y0=0, y1=1),
3589+
row,
3590+
col,
3591+
"vertical",
3592+
exclude_subplots_without_data=exclude_subplots_without_data,
3593+
**kwargs
35753594
)
35763595
return self
35773596

3578-
def add_hline(self, y, row=None, col=None, **kwargs):
3597+
def add_hline(
3598+
self, y, row=None, col=None, exclude_subplots_without_data=True, **kwargs
3599+
):
35793600
"""
35803601
Add a horizontal line to a plot or subplot that extends infinitely in the
35813602
x-dimension.
@@ -3597,11 +3618,18 @@ def add_hline(self, y, row=None, col=None, **kwargs):
35973618
except for x0, x1, y0, y1 or type.
35983619
"""
35993620
self._process_multiple_paper_spanning_shapes(
3600-
dict(type="line", x0=0, x1=1, y0=y, y1=y,), row, col, "horizontal", **kwargs
3621+
dict(type="line", x0=0, x1=1, y0=y, y1=y,),
3622+
row,
3623+
col,
3624+
"horizontal",
3625+
exclude_subplots_without_data=exclude_subplots_without_data,
3626+
**kwargs
36013627
)
36023628
return self
36033629

3604-
def add_vrect(self, x0, x1, row=None, col=None, **kwargs):
3630+
def add_vrect(
3631+
self, x0, x1, row=None, col=None, exclude_subplots_without_data=True, **kwargs
3632+
):
36053633
"""
36063634
Add a rectangle to a plot or subplot that extends infinitely in the
36073635
y-dimension.
@@ -3625,11 +3653,18 @@ def add_vrect(self, x0, x1, row=None, col=None, **kwargs):
36253653
except for x0, x1, y0, y1 or type.
36263654
"""
36273655
self._process_multiple_paper_spanning_shapes(
3628-
dict(type="rect", x0=x0, x1=x1, y0=0, y1=1), row, col, "vertical", **kwargs
3656+
dict(type="rect", x0=x0, x1=x1, y0=0, y1=1),
3657+
row,
3658+
col,
3659+
"vertical",
3660+
exclude_subplots_without_data=exclude_subplots_without_data,
3661+
**kwargs
36293662
)
36303663
return self
36313664

3632-
def add_hrect(self, y0, y1, row=None, col=None, **kwargs):
3665+
def add_hrect(
3666+
self, y0, y1, row=None, col=None, exclude_subplots_without_data=True, **kwargs
3667+
):
36333668
"""
36343669
Add a rectangle to a plot or subplot that extends infinitely in the
36353670
x-dimension.
@@ -3657,6 +3692,7 @@ def add_hrect(self, y0, y1, row=None, col=None, **kwargs):
36573692
row,
36583693
col,
36593694
"horizontal",
3695+
exclude_subplots_without_data=exclude_subplots_without_data,
36603696
**kwargs
36613697
)
36623698
return self
Lines changed: 204 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
import plotly.graph_objs as go
22
from plotly.subplots import make_subplots
33
from plotly.basedatatypes import _indexing_combinations, _unzip_pairs
4+
import plotly.express as px
45
import pytest
56

6-
NROWS = 4
7-
NCOLS = 5
8-
97

108
@pytest.fixture
119
def subplot_fig_fixture():
12-
fig = make_subplots(NROWS, NCOLS)
10+
fig = px.scatter(
11+
px.data.tips(), x="total_bill", y="tip", facet_row="smoker", facet_col="sex"
12+
)
13+
# explicitly set domains so that we know what they will be
14+
for ax in ["x", "y"]:
15+
for n in range(1, 5):
16+
axname = ax + "axis" + str(n) if n != 1 else ax + "axis"
17+
start = ((n - 1) // 2) * 0.5
18+
stop = start + 0.4
19+
fig["layout"][axname]["domain"] = [start, stop]
1320
return fig
1421

1522

23+
@pytest.fixture
24+
def subplot_empty_traces_fig_fixture():
25+
fig = px.scatter(
26+
px.data.tips(), x="total_bill", y="tip", facet_row="day", facet_col="time"
27+
)
28+
29+
1630
@pytest.fixture
1731
def non_subplot_fig_fixture():
1832
fig = go.Figure(go.Scatter(x=[1, 2, 3], y=[4, 3, 2]))
@@ -22,6 +36,191 @@ def non_subplot_fig_fixture():
2236
# stuff to test:
2337
# add_vline, hline etc. add the intended shape
2438
# - then WLOG maybe we can just test 1 of them, e.g., add_vline?
25-
# test that the addressing works correctly? this is already tested for add_shape...
39+
# test that the addressing works correctly? this is already tested for in add_shape...
2640
# make sure all the methods work for subplots and single plot
2741
# test edge-cases of _make_paper_spanning_shape: bad direction, bad shape (e.g., a path)
42+
43+
44+
def _cmp_partial_dict(a, b):
45+
ret = True
46+
for k in b.keys():
47+
try:
48+
v = a[k]
49+
ret &= v == b[k]
50+
except KeyError:
51+
return False
52+
return ret
53+
54+
55+
@pytest.mark.parametrize(
56+
"test_input,expected",
57+
# test_input: (function,kwargs)
58+
# expected: list of dictionaries with key:value pairs we expect in the added shapes
59+
[
60+
(
61+
(go.Figure.add_vline, dict(x=20, row=1, col=1)),
62+
[
63+
{
64+
"type": "line",
65+
"x0": 20,
66+
"x1": 20,
67+
"xref": "x",
68+
"y0": 0,
69+
"y1": 0.4,
70+
"yref": "paper",
71+
}
72+
],
73+
),
74+
(
75+
(go.Figure.add_vline, dict(x=20, row=2, col=2)),
76+
[
77+
{
78+
"type": "line",
79+
"x0": 20,
80+
"x1": 20,
81+
"xref": "x4",
82+
"y0": 0.5,
83+
"y1": 0.9,
84+
"yref": "paper",
85+
}
86+
],
87+
),
88+
(
89+
(go.Figure.add_hline, dict(y=6, row=1, col=1)),
90+
[
91+
{
92+
"type": "line",
93+
"x0": 0,
94+
"x1": 0.4,
95+
"xref": "paper",
96+
"y0": 6,
97+
"y1": 6,
98+
"yref": "y",
99+
}
100+
],
101+
),
102+
(
103+
(go.Figure.add_hline, dict(y=6, row=2, col=2)),
104+
[
105+
{
106+
"type": "line",
107+
"x0": 0.5,
108+
"x1": 0.9,
109+
"xref": "paper",
110+
"y0": 6,
111+
"y1": 6,
112+
"yref": "y4",
113+
}
114+
],
115+
),
116+
(
117+
(go.Figure.add_vrect, dict(x0=20, x1=30, row=1, col=1)),
118+
[
119+
{
120+
"type": "rect",
121+
"x0": 20,
122+
"x1": 30,
123+
"xref": "x",
124+
"y0": 0,
125+
"y1": 0.4,
126+
"yref": "paper",
127+
}
128+
],
129+
),
130+
(
131+
(go.Figure.add_vrect, dict(x0=20, x1=30, row=2, col=2)),
132+
[
133+
{
134+
"type": "rect",
135+
"x0": 20,
136+
"x1": 30,
137+
"xref": "x4",
138+
"y0": 0.5,
139+
"y1": 0.9,
140+
"yref": "paper",
141+
}
142+
],
143+
),
144+
(
145+
(go.Figure.add_hrect, dict(y0=6, y1=8, row=1, col=1)),
146+
[
147+
{
148+
"type": "rect",
149+
"x0": 0,
150+
"x1": 0.4,
151+
"xref": "paper",
152+
"y0": 6,
153+
"y1": 8,
154+
"yref": "y",
155+
}
156+
],
157+
),
158+
(
159+
(go.Figure.add_hrect, dict(y0=6, y1=8, row=2, col=2)),
160+
[
161+
{
162+
"type": "rect",
163+
"x0": 0.5,
164+
"x1": 0.9,
165+
"xref": "paper",
166+
"y0": 6,
167+
"y1": 8,
168+
"yref": "y4",
169+
}
170+
],
171+
),
172+
(
173+
(go.Figure.add_vline, dict(x=20, row=2, col="all")),
174+
[
175+
{
176+
"type": "line",
177+
"x0": 20,
178+
"x1": 20,
179+
"xref": "x3",
180+
"y0": 0.5,
181+
"y1": 0.9,
182+
"yref": "paper",
183+
},
184+
{
185+
"type": "line",
186+
"x0": 20,
187+
"x1": 20,
188+
"xref": "x4",
189+
"y0": 0.5,
190+
"y1": 0.9,
191+
"yref": "paper",
192+
},
193+
],
194+
),
195+
(
196+
(go.Figure.add_vline, dict(x=20, row="all", col=2)),
197+
[
198+
{
199+
"type": "line",
200+
"x0": 20,
201+
"x1": 20,
202+
"xref": "x2",
203+
"y0": 0,
204+
"y1": 0.4,
205+
"yref": "paper",
206+
},
207+
{
208+
"type": "line",
209+
"x0": 20,
210+
"x1": 20,
211+
"xref": "x4",
212+
"y0": 0.5,
213+
"y1": 0.9,
214+
"yref": "paper",
215+
},
216+
],
217+
),
218+
],
219+
)
220+
def test_add_span_shape(test_input, expected, subplot_fig_fixture):
221+
f, kwargs = test_input
222+
f(subplot_fig_fixture, **kwargs)
223+
ret = True
224+
for s, d in zip(subplot_fig_fixture.layout.shapes, expected):
225+
ret &= _cmp_partial_dict(s, d)
226+
assert ret

0 commit comments

Comments
 (0)