diff --git a/CHANGELOG.md b/CHANGELOG.md index cae0a8a502..80125b56ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix `mpl_to_plotly` showing unwanted legends with placeholder or internal label entries (`_nolegend_`, `_childN`) by defaulting `layout.showlegend=False` unless the matplotlib figure explicitly defines a legend [[#5699](https://github.com/plotly/plotly.py/pull/5699)], with thanks to @robertoffmoura for the contribution! - Fix `mpl_to_plotly` crashing on figures with fully transparent or alpha-carrying colors, such as boxplot outlier markers (`facecolor="none"`), rgba line colors, and `color="none"` text and axis labels; all matplotlib colors are now exported through a single helper that maps `"none"` to transparent rgba and keeps or overrides alpha as matplotlib does [[#5700](https://github.com/plotly/plotly.py/pull/5700)], with thanks to @robertoffmoura for the contribution! - Export tick label colors to the plotly tickfont in `mpl_to_plotly` [[#5716](https://github.com/plotly/plotly.py/pull/5716)], with thanks to @robertoffmoura for the contribution! +- Fix Plotly Express mutating lists passed to the `x` or `y` arguments in wide mode [[#5727](https://github.com/plotly/plotly.py/pull/5727)], with thanks to @cpruijsen for the contribution! - Fix `px.sunburst`, `px.treemap` and `px.icicle` listing sectors in a different order on every run when `path` is used with a Polars DataFrame; sectors now follow their order of first appearance for all dataframe backends [[#5766](https://github.com/plotly/plotly.py/pull/5766)], with thanks to @Irahan2 for the contribution! - Fix `mpl_to_plotly` conversion of matplotlib contour lines and line collections: close contour rings ending with `Z` codes, support dash styles, convert date x-axes, separate disjoint subpaths with `None` separators, hide line collection traces from the legend by default, and group consecutive same-style lines into single traces [[#5770](https://github.com/plotly/plotly.py/pull/5770)], with thanks to @robertoffmoura for the contribution! diff --git a/plotly/express/_core.py b/plotly/express/_core.py index e99bf40b87..fa1e327bc6 100644 --- a/plotly/express/_core.py +++ b/plotly/express/_core.py @@ -1687,8 +1687,9 @@ def build_dataframe(args, constructor): args["wide_variable"] = args["y"] if wide_y else args["x"] if df_provided and is_pd_like and args["wide_variable"] is columns: var_name = columns.name - if is_pd_like and isinstance(args["wide_variable"], native_namespace.Index): - args["wide_variable"] = list(args["wide_variable"]) + # copy into a new list so that the list provided by the user for + # x or y is not mutated when wide_variable's entries are replaced + args["wide_variable"] = list(args["wide_variable"]) if var_name in [None, "value", "index"] or ( df_provided and var_name in columns ): diff --git a/tests/test_optional/test_px/test_px_wide.py b/tests/test_optional/test_px/test_px_wide.py index 88e1fd0278..2f8a5edcac 100644 --- a/tests/test_optional/test_px/test_px_wide.py +++ b/tests/test_optional/test_px/test_px_wide.py @@ -890,3 +890,16 @@ def test_no_pd_perf_warning(): if issubclass(warn.category, pd.errors.PerformanceWarning) ] assert len(performance_warnings) == 0, "PerformanceWarning(s) raised!" + + +def test_wide_mode_does_not_mutate_x_or_y(): + # https://github.com/plotly/plotly.py/issues/4117 + df = pd.DataFrame(dict(a=[1, 2, 3], b=[4, 5, 6], c=[7, 8, 9])) + for arg in ["x", "y"]: + cols = ["a", "b"] + px.bar(df, **{arg: cols}) + assert cols == ["a", "b"] + cols = [0, 1] + df_int = pd.DataFrame([[1, 2], [3, 4]]) + px.histogram(df_int, x=cols) + assert cols == [0, 1]