From 91830855ecf56ffe04d1af3a16ea03aa3332772f Mon Sep 17 00:00:00 2001 From: Nicolas Kruchten Date: Tue, 22 Dec 2020 12:39:25 -0500 Subject: [PATCH 1/2] tiny refactoring --- .../python/plotly/plotly/express/_core.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py index af416b7f6e1..380b3d71de0 100644 --- a/packages/python/plotly/plotly/express/_core.py +++ b/packages/python/plotly/plotly/express/_core.py @@ -264,14 +264,7 @@ def make_trace_kwargs(args, trace_spec, trace_data, mapping_labels, sizeref): mapping_labels["%{xaxis.title.text}"] = "%{x}" mapping_labels["%{yaxis.title.text}"] = "%{y}" - elif ( - attr_value is not None - or (trace_spec.constructor == go.Histogram and attr_name in ["x", "y"]) - or ( - trace_spec.constructor in [go.Histogram2d, go.Histogram2dContour] - and attr_name == "z" - ) - ): + elif attr_value is not None: if attr_name == "size": if "marker" not in trace_patch: trace_patch["marker"] = dict() @@ -464,13 +457,15 @@ def make_trace_kwargs(args, trace_spec, trace_data, mapping_labels, sizeref): else: trace_patch[attr_name] = trace_data[attr_value] else: - if attr_value: - trace_patch[attr_name] = trace_data[attr_value] + trace_patch[attr_name] = trace_data[attr_value] mapping_labels[attr_label] = "%%{%s}" % attr_name - if trace_spec.constructor not in [ - go.Parcoords, - go.Parcats, - ]: + elif (trace_spec.constructor == go.Histogram and attr_name in ["x", "y"]) or ( + trace_spec.constructor in [go.Histogram2d, go.Histogram2dContour] + and attr_name == "z" + ): + # ensure that stuff like "count" gets into the hoverlabel + mapping_labels[attr_label] = "%%{%s}" % attr_name + if trace_spec.constructor not in [go.Parcoords, go.Parcats]: # Modify mapping_labels according to hover_data keys # if hover_data is a dict mapping_labels_copy = OrderedDict(mapping_labels) From 80f71f2a1c443631c022b354b52b5d3d44c2c50b Mon Sep 17 00:00:00 2001 From: Nicolas Kruchten Date: Wed, 23 Dec 2020 14:03:29 -0500 Subject: [PATCH 2/2] norms in decorated labels --- .../python/plotly/plotly/express/_core.py | 18 ++++++++----- .../test_core/test_px/test_px_functions.py | 27 ++++++++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py index 380b3d71de0..d441a6f715e 100644 --- a/packages/python/plotly/plotly/express/_core.py +++ b/packages/python/plotly/plotly/express/_core.py @@ -149,16 +149,22 @@ def _is_continuous(df, col_name): def get_decorated_label(args, column, role): label = get_label(args, column) if "histfunc" in args and ( - (role == "x" and "orientation" in args and args["orientation"] == "h") + (role == "z") + or (role == "x" and "orientation" in args and args["orientation"] == "h") or (role == "y" and "orientation" in args and args["orientation"] == "v") - or (role == "z") ): if label: - return "%s of %s" % (args["histfunc"] or "count", label) + label = "%s of %s" % (args["histfunc"] or "count", label) else: - return "count" - else: - return label + label = "count" + + if "histnorm" in args and args["histnorm"] is not None: + label = "%s of %s" % (args["histnorm"], label) + + if "barnorm" in args and args["barnorm"] is not None: + label = "%s (normalized as %s)" % (label, args["barnorm"]) + + return label def make_mapping(args, variable): diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py index e8c95860ce2..6f269b4ae0d 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py +++ b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py @@ -267,7 +267,7 @@ def test_sunburst_treemap_column_parent(): df = pd.DataFrame(dict(id=vendors, sectors=sectors, parent=regions, values=values,)) path = ["parent", "sectors", "id"] # One column of the path is a reserved name - this is ok and should not raise - fig = px.sunburst(df, path=path, values="values") + px.sunburst(df, path=path, values="values") def test_sunburst_treemap_with_path_non_rectangular(): @@ -379,6 +379,31 @@ def test_parcats_dimensions_max(): assert [d.label for d in fig.data[0].dimensions] == ["sex", "smoker", "day", "size"] +def test_histfunc_hoverlabels(): + df = px.data.tips() + fig = px.histogram(df, x="total_bill") + label = "count" + assert fig.layout.yaxis.title.text == label + assert label + "=" in fig.data[0].hovertemplate + + fig = px.histogram(df, x="total_bill", y="tip") + label = "sum of tip" + assert fig.layout.yaxis.title.text == label + assert label + "=" in fig.data[0].hovertemplate + + fig = px.histogram( + df, + x="total_bill", + y="tip", + histfunc="min", + histnorm="probability", + barnorm="percent", + ) + label = "probability of min of tip (normalized as percent)" + assert fig.layout.yaxis.title.text == label + assert label + "=" in fig.data[0].hovertemplate + + def test_timeline(): df = pd.DataFrame( [