Skip to content

Commit 0501de6

Browse files
finish edge-case labelling for histnorm/histfunc
1 parent 415686b commit 0501de6

File tree

2 files changed

+86
-7
lines changed

2 files changed

+86
-7
lines changed

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def _is_continuous(df, col_name):
147147

148148

149149
def get_decorated_label(args, column, role):
150-
label = get_label(args, column)
150+
original_label = label = get_label(args, column)
151151
if "histfunc" in args and (
152152
(role == "z")
153153
or (role == "x" and "orientation" in args and args["orientation"] == "h")
@@ -164,9 +164,19 @@ def get_decorated_label(args, column, role):
164164
label = args["histnorm"]
165165
else:
166166
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)
167+
if histfunc == "sum":
168+
if histnorm == "probability":
169+
label = "%s of %s" % ("fraction", label)
170+
elif histnorm == "percent":
171+
label = "%s of %s" % (histnorm, label)
172+
else:
173+
label = "%s weighted by %s" % (histnorm, original_label)
174+
elif histnorm == "probability":
175+
label = "%s of sum of %s" % ("fraction", label)
176+
elif histnorm == "percent":
177+
label = "%s of sum of %s" % ("percent", label)
178+
else:
179+
label = "%s of %s" % (histnorm, label)
170180

171181
if "barnorm" in args and args["barnorm"] is not None:
172182
label = "%s (normalized as %s)" % (label, args["barnorm"])

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

+72-3
Original file line numberDiff line numberDiff line change
@@ -379,18 +379,73 @@ def test_parcats_dimensions_max():
379379
assert [d.label for d in fig.data[0].dimensions] == ["sex", "smoker", "day", "size"]
380380

381381

382-
def test_histfunc_hoverlabels():
382+
@pytest.mark.parametrize("histfunc,y", [(None, None), ("count", "tip")])
383+
def test_histfunc_hoverlabels_univariate(histfunc, y):
383384
def check_label(label, fig):
384385
assert fig.layout.yaxis.title.text == label
385386
assert label + "=" in fig.data[0].hovertemplate
386387

387388
df = px.data.tips()
388-
fig = px.histogram(df, x="total_bill")
389+
390+
# base case, just "count" (note count(tip) is same as count())
391+
fig = px.histogram(df, x="total_bill", y=y, histfunc=histfunc)
389392
check_label("count", fig)
390393

394+
# without y, label is just histnorm
395+
for histnorm in ["probability", "percent", "density", "probability density"]:
396+
fig = px.histogram(
397+
df, x="total_bill", y=y, histfunc=histfunc, histnorm=histnorm
398+
)
399+
check_label(histnorm, fig)
400+
401+
for histnorm in ["probability", "percent", "density", "probability density"]:
402+
for barnorm in ["percent", "fraction"]:
403+
fig = px.histogram(
404+
df,
405+
x="total_bill",
406+
y=y,
407+
histfunc=histfunc,
408+
histnorm=histnorm,
409+
barnorm=barnorm,
410+
)
411+
check_label("%s (normalized as %s)" % (histnorm, barnorm), fig)
412+
413+
414+
def test_histfunc_hoverlabels_bivariate():
415+
def check_label(label, fig):
416+
assert fig.layout.yaxis.title.text == label
417+
assert label + "=" in fig.data[0].hovertemplate
418+
419+
df = px.data.tips()
420+
421+
# with y, should be same as forcing histfunc to sum
391422
fig = px.histogram(df, x="total_bill", y="tip")
392423
check_label("sum of tip", fig)
393424

425+
# change probability to fraction when histfunc is sum
426+
fig = px.histogram(df, x="total_bill", y="tip", histnorm="probability")
427+
check_label("fraction of sum of tip", fig)
428+
429+
# percent is percent
430+
fig = px.histogram(df, x="total_bill", y="tip", histnorm="percent")
431+
check_label("percent of sum of tip", fig)
432+
433+
# the other two are "weighted by"
434+
for histnorm in ["density", "probability density"]:
435+
fig = px.histogram(df, x="total_bill", y="tip", histnorm=histnorm)
436+
check_label("%s weighted by tip" % histnorm, fig)
437+
438+
# check a few "normalized by"
439+
for histnorm in ["density", "probability density"]:
440+
for barnorm in ["fraction", "percent"]:
441+
fig = px.histogram(
442+
df, x="total_bill", y="tip", histnorm=histnorm, barnorm=barnorm
443+
)
444+
check_label(
445+
"%s weighted by tip (normalized as %s)" % (histnorm, barnorm), fig
446+
)
447+
448+
# these next two are weird but OK...
394449
fig = px.histogram(
395450
df,
396451
x="total_bill",
@@ -399,7 +454,21 @@ def check_label(label, fig):
399454
histnorm="probability",
400455
barnorm="percent",
401456
)
402-
check_label("fraction of min of tip (normalized as percent)", fig)
457+
check_label("fraction of sum of min of tip (normalized as percent)", fig)
458+
459+
fig = px.histogram(
460+
df,
461+
x="total_bill",
462+
y="tip",
463+
histfunc="avg",
464+
histnorm="percent",
465+
barnorm="fraction",
466+
)
467+
check_label("percent of sum of avg of tip (normalized as fraction)", fig)
468+
469+
# this next one is basically "never do this" but needs a defined behaviour
470+
fig = px.histogram(df, x="total_bill", y="tip", histfunc="max", histnorm="density")
471+
check_label("density of max of tip", fig)
403472

404473

405474
def test_timeline():

0 commit comments

Comments
 (0)