diff --git a/CHANGELOG.md b/CHANGELOG.md index 625c7cb83a7..9a705109fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fixed special cases with `px.sunburst` and `px.treemap` with `path` input ([#2524](https://github.com/plotly/plotly.py/pull/2524)) - Fixed bug in `hover_data` argument of `px` functions, when the column name is changed with labels and `hover_data` is a dictionary setting up a specific format for the hover data ([#2544](https://github.com/plotly/plotly.py/pull/2544)). - Made the Plotly Express `trendline` argument more robust and made it work with datetime `x` values ([#2554](https://github.com/plotly/plotly.py/pull/2554)) +- Fixed bug in `px.sunburst` and `px.treemap`: when the `color` and `values` + arguments correspond to the same column, a different aggregation function has + to be used for the two arguments ([#2591](https://github.com/plotly/plotly.py/pull/2591)) - Plotly Express wide mode now accepts mixed integer and float columns ([#2598](https://github.com/plotly/plotly.py/pull/2598)) - Plotly Express `range_(x|y)` should not impact the unlinked range of marginal subplots ([#2600](https://github.com/plotly/plotly.py/pull/2600)) - `px.line` now sets `line_group=` in wide mode by default ([#2599](https://github.com/plotly/plotly.py/pull/2599)) diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py index 18ea28d2ab7..82da1ea7bef 100644 --- a/packages/python/plotly/plotly/express/_core.py +++ b/packages/python/plotly/plotly/express/_core.py @@ -474,11 +474,10 @@ def make_trace_kwargs(args, trace_spec, trace_data, mapping_labels, sizeref): # We need to invert the mapping here k_args = invert_label(args, k) if k_args in args["hover_data"]: - if args["hover_data"][k_args][0]: - if isinstance(args["hover_data"][k_args][0], str): - mapping_labels_copy[k] = v.replace( - "}", "%s}" % args["hover_data"][k_args][0] - ) + formatter = args["hover_data"][k_args][0] + if formatter: + if isinstance(formatter, str): + mapping_labels_copy[k] = v.replace("}", "%s}" % formatter) else: _ = mapping_labels_copy.pop(k) hover_lines = [k + "=" + v for k, v in mapping_labels_copy.items()] @@ -1507,7 +1506,9 @@ def aggfunc_discrete(x): if args["color"]: if args["color"] == args["values"]: - aggfunc_color = "sum" + new_value_col_name = args["values"] + "_sum" + df[new_value_col_name] = df[args["values"]] + args["values"] = new_value_col_name count_colname = args["values"] else: # we need a count column for the first groupby and the weighted mean of color @@ -1526,7 +1527,7 @@ def aggfunc_discrete(x): if not _is_continuous(df, args["color"]): aggfunc_color = aggfunc_discrete discrete_color = True - elif not aggfunc_color: + else: def aggfunc_continuous(x): return np.average(x, weights=df.loc[x.index, count_colname]) @@ -1584,6 +1585,9 @@ def aggfunc_continuous(x): if args["color"]: if not args["hover_data"]: args["hover_data"] = [args["color"]] + elif isinstance(args["hover_data"], dict): + if not args["hover_data"].get(args["color"]): + args["hover_data"][args["color"]] = (True, None) else: args["hover_data"].append(args["color"]) return args 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 9c89fcd25f0..8dde6a7be4e 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 @@ -149,10 +149,6 @@ def test_sunburst_treemap_with_path(): fig = px.sunburst(df, path=path, values="values") assert fig.data[0].branchvalues == "total" assert fig.data[0].values[-1] == np.sum(values) - # Continuous colorscale - fig = px.sunburst(df, path=path, values="values", color="values") - assert "coloraxis" in fig.data[0].marker - assert np.all(np.array(fig.data[0].marker.colors) == np.array(fig.data[0].values)) # Error when values cannot be converted to numerical data type df["values"] = ["1 000", "3 000", "2", "4", "2", "2", "1 000", "4 000"] msg = "Column `values` of `df` could not be converted to a numerical data type." @@ -162,6 +158,12 @@ def test_sunburst_treemap_with_path(): path = [df.total, "regions", df.sectors, "vendors"] fig = px.sunburst(df, path=path) assert fig.data[0].branchvalues == "total" + # Continuous colorscale + df["values"] = 1 + fig = px.sunburst(df, path=path, values="values", color="values") + assert "coloraxis" in fig.data[0].marker + assert np.all(np.array(fig.data[0].marker.colors) == 1) + assert fig.data[0].values[-1] == 8 def test_sunburst_treemap_with_path_and_hover(): diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py index 07d0e201a43..6e1b57cba34 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py +++ b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py @@ -151,3 +151,15 @@ def test_fail_wrong_column(): "Ambiguous input: values for 'c' appear both in hover_data and data_frame" in str(err_msg.value) ) + + +def test_sunburst_hoverdict_color(): + df = px.data.gapminder().query("year == 2007") + fig = px.sunburst( + df, + path=["continent", "country"], + values="pop", + color="lifeExp", + hover_data={"pop": ":,"}, + ) + assert "color" in fig.data[0].hovertemplate