Skip to content

Commit 415686b

Browse files
lock down some behaviour with tests
1 parent 234ec0d commit 415686b

File tree

4 files changed

+98
-19
lines changed

4 files changed

+98
-19
lines changed

packages/python/plotly/plotly/express/_core.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,20 @@ def get_decorated_label(args, column, role):
153153
or (role == "x" and "orientation" in args and args["orientation"] == "h")
154154
or (role == "y" and "orientation" in args and args["orientation"] == "v")
155155
):
156-
if label:
157-
label = "%s of %s" % (args["histfunc"] or "count", label)
156+
histfunc = args["histfunc"] or "count"
157+
if histfunc != "count":
158+
label = "%s of %s" % (histfunc, label)
158159
else:
159160
label = "count"
160161

161162
if "histnorm" in args and args["histnorm"] is not None:
162-
label = "%s of %s" % (args["histnorm"], label)
163+
if label == "count":
164+
label = args["histnorm"]
165+
else:
166+
histnorm = args["histnorm"]
167+
# avoid "probability of sum of thing"
168+
histnorm = "fraction" if histnorm == "probability" else histnorm
169+
label = "%s of %s" % (histnorm, label)
163170

164171
if "barnorm" in args and args["barnorm"] is not None:
165172
label = "%s (normalized as %s)" % (label, args["barnorm"])
@@ -924,13 +931,6 @@ def apply_default_cascade(args):
924931
"longdashdot",
925932
]
926933

927-
# If both marginals and faceting are specified, faceting wins
928-
if args.get("facet_col", None) is not None and args.get("marginal_y", None):
929-
args["marginal_y"] = None
930-
931-
if args.get("facet_row", None) is not None and args.get("marginal_x", None):
932-
args["marginal_x"] = None
933-
934934

935935
def _check_name_not_reserved(field_name, reserved_names):
936936
if field_name not in reserved_names:
@@ -1765,6 +1765,14 @@ def infer_config(args, constructor, trace_patch, layout_patch):
17651765
args[position] = args["marginal"]
17661766
args[other_position] = None
17671767

1768+
# If both marginals and faceting are specified, faceting wins
1769+
if args.get("facet_col", None) is not None and args.get("marginal_y", None):
1770+
args["marginal_y"] = None
1771+
1772+
if args.get("facet_row", None) is not None and args.get("marginal_x", None):
1773+
args["marginal_x"] = None
1774+
1775+
# facet_col_wrap only works if no marginals or row faceting is used
17681776
if (
17691777
args.get("marginal_x", None) is not None
17701778
or args.get("marginal_y", None) is not None

packages/python/plotly/plotly/tests/test_core/test_px/test_facets.py

+47
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,53 @@ def test_facets():
4747
assert fig.layout.yaxis4.domain[0] - fig.layout.yaxis.domain[1] == approx(0.08)
4848

4949

50+
def test_facets_with_marginals():
51+
df = px.data.tips()
52+
53+
fig = px.histogram(df, x="total_bill", facet_col="sex", marginal="rug")
54+
assert len(fig.data) == 4
55+
fig = px.histogram(df, x="total_bill", facet_row="sex", marginal="rug")
56+
assert len(fig.data) == 2
57+
58+
fig = px.histogram(df, y="total_bill", facet_col="sex", marginal="rug")
59+
assert len(fig.data) == 2
60+
fig = px.histogram(df, y="total_bill", facet_row="sex", marginal="rug")
61+
assert len(fig.data) == 4
62+
63+
fig = px.scatter(df, x="total_bill", y="tip", facet_col="sex", marginal_x="rug")
64+
assert len(fig.data) == 4
65+
fig = px.scatter(
66+
df, x="total_bill", y="tip", facet_col="day", facet_col_wrap=2, marginal_x="rug"
67+
)
68+
assert len(fig.data) == 8 # ignore the wrap when marginal is used
69+
fig = px.scatter(df, x="total_bill", y="tip", facet_col="sex", marginal_y="rug")
70+
assert len(fig.data) == 2 # ignore the marginal in the facet direction
71+
72+
fig = px.scatter(df, x="total_bill", y="tip", facet_row="sex", marginal_x="rug")
73+
assert len(fig.data) == 2 # ignore the marginal in the facet direction
74+
fig = px.scatter(df, x="total_bill", y="tip", facet_row="sex", marginal_y="rug")
75+
assert len(fig.data) == 4
76+
77+
fig = px.scatter(
78+
df, x="total_bill", y="tip", facet_row="sex", marginal_y="rug", marginal_x="rug"
79+
)
80+
assert len(fig.data) == 4 # ignore the marginal in the facet direction
81+
fig = px.scatter(
82+
df, x="total_bill", y="tip", facet_col="sex", marginal_y="rug", marginal_x="rug"
83+
)
84+
assert len(fig.data) == 4 # ignore the marginal in the facet direction
85+
fig = px.scatter(
86+
df,
87+
x="total_bill",
88+
y="tip",
89+
facet_row="sex",
90+
facet_col="sex",
91+
marginal_y="rug",
92+
marginal_x="rug",
93+
)
94+
assert len(fig.data) == 2 # ignore all marginals
95+
96+
5097
@pytest.fixture
5198
def bad_facet_spacing_df():
5299
NROWS = 101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import plotly.express as px
2+
import pytest
3+
4+
5+
@pytest.mark.parametrize("px_fn", [px.scatter, px.density_heatmap, px.density_contour])
6+
@pytest.mark.parametrize("marginal_x", [None, "histogram", "box", "violin"])
7+
@pytest.mark.parametrize("marginal_y", [None, "rug"])
8+
def test_xy_marginals(px_fn, marginal_x, marginal_y):
9+
df = px.data.tips()
10+
11+
fig = px_fn(
12+
df, x="total_bill", y="tip", marginal_x=marginal_x, marginal_y=marginal_y
13+
)
14+
assert len(fig.data) == 1 + (marginal_x is not None) + (marginal_y is not None)
15+
16+
17+
@pytest.mark.parametrize("px_fn", [px.histogram])
18+
@pytest.mark.parametrize("marginal", [None, "rug", "histogram", "box", "violin"])
19+
@pytest.mark.parametrize("orientation", ["h", "v"])
20+
def test_single_marginals(px_fn, marginal, orientation):
21+
df = px.data.tips()
22+
23+
fig = px_fn(
24+
df, x="total_bill", y="total_bill", marginal=marginal, orientation=orientation
25+
)
26+
assert len(fig.data) == 1 + (marginal is not None)

packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,16 @@ def test_parcats_dimensions_max():
380380

381381

382382
def test_histfunc_hoverlabels():
383+
def check_label(label, fig):
384+
assert fig.layout.yaxis.title.text == label
385+
assert label + "=" in fig.data[0].hovertemplate
386+
383387
df = px.data.tips()
384388
fig = px.histogram(df, x="total_bill")
385-
label = "count"
386-
assert fig.layout.yaxis.title.text == label
387-
assert label + "=" in fig.data[0].hovertemplate
389+
check_label("count", fig)
388390

389391
fig = px.histogram(df, x="total_bill", y="tip")
390-
label = "sum of tip"
391-
assert fig.layout.yaxis.title.text == label
392-
assert label + "=" in fig.data[0].hovertemplate
392+
check_label("sum of tip", fig)
393393

394394
fig = px.histogram(
395395
df,
@@ -399,9 +399,7 @@ def test_histfunc_hoverlabels():
399399
histnorm="probability",
400400
barnorm="percent",
401401
)
402-
label = "probability of min of tip (normalized as percent)"
403-
assert fig.layout.yaxis.title.text == label
404-
assert label + "=" in fig.data[0].hovertemplate
402+
check_label("fraction of min of tip (normalized as percent)", fig)
405403

406404

407405
def test_timeline():

0 commit comments

Comments
 (0)