Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add support for converting matplotlib reference lines (`axhline`, `axvline`, and horizontal/vertical `axline`) as well as axes-coordinate lines into Plotly layout shapes in `mpl_to_plotly`, including support for date axes [[#5719](https://github.com/plotly/plotly.py/pull/5719)], with thanks to @robertoffmoura for the contribution!

### Fixed
- Preserve distinct Plotly Express legend entries and groups when grouping columns have the same display label ([#2562](https://github.com/plotly/plotly.py/issues/2562)).
- Fix `mpl_to_plotly` tick marker mirroring, axis positioning, and trace visibility for twinned and overlaid subplots (such as `twinx` and `twiny`) [[#5310](https://github.com/plotly/plotly.py/pull/5310)], with thanks to @robertoffmoura for the contribution!
- Fix `mpl_to_plotly` losing matplotlib axis line colors by exporting the color of each axis's displayed spine to the plotly x and y axis `linecolor` [[#5311](https://github.com/plotly/plotly.py/pull/5311)], with thanks to @robertoffmoura for the contribution!
- Fix concurrent first access to lazily initialized graph object properties, which could raise `ValueError("Invalid value")` [[#5691](https://github.com/plotly/plotly.py/pull/5691)], with thanks to @hb1915 for the contribution!
Expand Down
6 changes: 4 additions & 2 deletions plotly/express/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2594,7 +2594,7 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
if not isinstance(m.val_map, IdentityMap):
mapping_labels[key] = str(val)
if m.show_in_trace_name:
trace_name_labels[key] = str(val)
trace_name_labels[col] = str(val)
if m.variable == "animation_frame":
frame_name = val
trace_name = ", ".join(trace_name_labels.values())
Expand Down Expand Up @@ -2768,7 +2768,9 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
layout_patch[v] = args[v]
layout_patch["legend"] = dict(tracegroupgap=0)
if trace_name_labels:
layout_patch["legend"]["title_text"] = ", ".join(trace_name_labels)
layout_patch["legend"]["title_text"] = ", ".join(
get_label(args, column) for column in trace_name_labels
)
if args["title"]:
layout_patch["title_text"] = args["title"]
elif args["template"].layout.margin.t is None:
Expand Down
35 changes: 35 additions & 0 deletions tests/test_optional/test_px/test_px.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,41 @@ def test_labels(backend):
assert fig.layout.annotations[4].text.startswith("TIME")


@pytest.mark.parametrize(
"labels", [{"color": "Group", "symbol": "Group"}, {"color": "symbol"}]
)
def test_legend_with_duplicate_labels(constructor, labels):
df = constructor(
{
"x": [1, 2, 3, 4],
"y": [4, 3, 2, 1],
"color": ["A", "A", "B", "B"],
"symbol": ["one", "two", "one", "two"],
}
)
fig = px.scatter(df, x="x", y="y", color="color", symbol="symbol", labels=labels)

expected_names = ["A, one", "A, two", "B, one", "B, two"]
assert [trace.name for trace in fig.data] == expected_names
assert [trace.legendgroup for trace in fig.data] == expected_names
assert all(trace.showlegend for trace in fig.data)
assert fig.layout.legend.title.text == ", ".join(
labels.get(column, column) for column in ["color", "symbol"]
)


def test_legend_with_same_column_for_color_and_symbol(constructor):
df = constructor({"x": [1, 2], "y": [3, 4], "group": ["A", "B"]})
fig = px.scatter(
df, x="x", y="y", color="group", symbol="group", labels={"group": "Group"}
)

assert [trace.name for trace in fig.data] == ["A", "B"]
assert [trace.legendgroup for trace in fig.data] == ["A", "B"]
assert all(trace.showlegend for trace in fig.data)
assert fig.layout.legend.title.text == "Group"


@pytest.mark.parametrize(
["extra_kwargs", "expected_mode"],
[
Expand Down