Repository navigation
Add legend support for PatchCollection #30756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
story645
merged 18 commits into
matplotlib:main
from
FazeelUsmani:fix-patchcollection-legend
Nov 26, 2025
Merged
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
0f13209
Add support for PatchCollection legends and update documentation
FazeelUsmani 3f013f6
Add type stub for HandlerPatchCollection
FazeelUsmani 567b478
Remove visual regression test (baseline image needed)
FazeelUsmani 8fc57eb
Trigger CI re-run
FazeelUsmani 478de45
Add explicit figure cleanup in PatchCollection legend tests
FazeelUsmani 8536bfc
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 71c9a86
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 618d426
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 122a7d6
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 83adf5c
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 477bf97
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 1a1b20a
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani bd2f926
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani 33242ca
Update lib/matplotlib/tests/test_legend.py
FazeelUsmani b669f4d
Remove redundant test_patchcollection_legend_match_original test
FazeelUsmani 92aaeca
Test behavior instead of implementation details
FazeelUsmani 555faa6
Address story645's review: simplify implementation and improve tests
FazeelUsmani 84a911e
Update documentation and tests for PatchCollection legend support
FazeelUsmani File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ``PatchCollection`` legends now supported | ||
| ------------------------------------------ | ||
| `.PatchCollection` instances now properly display in legends when given a label. | ||
| Previously, labels on `~.PatchCollection` objects were ignored by the legend | ||
| system, requiring users to create manual legend entries. | ||
|
|
||
| The legend entry displays a rectangle matching the visual properties (colors, | ||
| line styles, line widths) of the first patch in the collection. | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| import matplotlib.pyplot as plt | ||
| import matplotlib.patches as mpatches | ||
| from matplotlib.collections import PatchCollection | ||
|
|
||
| fig, ax = plt.subplots() | ||
| patches = [mpatches.Circle((0, 0), 0.1), mpatches.Rectangle((0.5, 0.5), 0.2, 0.3)] | ||
| pc = PatchCollection(patches, facecolor='blue', edgecolor='black', label='My patches') | ||
| ax.add_collection(pc) | ||
| ax.legend() # Now displays the label "My patches" | ||
| plt.show() | ||
|
|
||
| This fix resolves :ghissue:`23998`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1667,3 +1667,78 @@ def test_boxplot_legend_labels(): | |
| bp4 = axs[3].boxplot(data, label='box A') | ||
| assert bp4['medians'][0].get_label() == 'box A' | ||
| assert all(x.get_label().startswith("_") for x in bp4['medians'][1:]) | ||
|
|
||
|
|
||
| def test_patchcollection_legend(): | ||
| # Test that PatchCollection labels show up in legend (issue #23998) | ||
| fig, ax = plt.subplots() | ||
|
|
||
| pc = mcollections.PatchCollection( | ||
| [ | ||
| mpatches.Polygon([[0, 0], [100, 100], [200, 0]]), | ||
| mpatches.Polygon([[400, 0], [500, 100], [600, 0]]), | ||
| ], | ||
| label="patch collection", facecolor='blue', edgecolor='black' | ||
| ) | ||
| ax.add_collection(pc, autolim=True) | ||
| ax.autoscale_view() | ||
|
|
||
| leg = ax.legend() | ||
|
|
||
| # Check that the legend contains our label | ||
| assert len(leg.get_texts()) == 1 | ||
| assert leg.get_texts()[0].get_text() == "patch collection" | ||
|
|
||
| # Check that the legend handle exists and has correct colors | ||
| assert len(leg.legend_handles) == 1 | ||
| legend_patch = leg.legend_handles[0] | ||
| assert_allclose(legend_patch.get_facecolor(), | ||
| pc.get_facecolor()[0], rtol=1e-5) | ||
| assert_allclose(legend_patch.get_edgecolor(), | ||
| pc.get_edgecolor()[0], rtol=1e-5) | ||
|
|
||
|
story645 marked this conversation as resolved.
Resolved
|
||
|
|
||
| def test_patchcollection_legend_properties(): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can combine
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
| # Test that PatchCollection legend preserves visual properties | ||
| fig, ax = plt.subplots() | ||
|
|
||
| pc = mcollections.PatchCollection( | ||
| [mpatches.Circle((0, 0), 1), mpatches.Circle((2, 0), 1)], | ||
| label="styled patches", | ||
| facecolor='red', | ||
| edgecolor='blue', | ||
| linewidths=3, | ||
| linestyle='--', | ||
| ) | ||
| ax.add_collection(pc) | ||
| ax.autoscale_view() | ||
|
|
||
| leg = ax.legend() | ||
|
|
||
| # Verify that visual properties are preserved | ||
| legend_patch = leg.legend_handles[0] | ||
| assert_allclose(legend_patch.get_facecolor(), | ||
| pc.get_facecolor()[0], rtol=1e-5) | ||
| assert_allclose(legend_patch.get_edgecolor(), | ||
| pc.get_edgecolor()[0], rtol=1e-5) | ||
|
story645 marked this conversation as resolved.
Resolved
|
||
| assert legend_patch.get_linewidth() == pc.get_linewidths()[0] | ||
| assert legend_patch.get_linestyle() == pc.get_linestyles()[0] | ||
|
|
||
|
|
||
| def test_patchcollection_legend_empty(): | ||
| # Test that empty PatchCollection doesn't crash | ||
| fig, ax = plt.subplots() | ||
|
|
||
| # Create an empty PatchCollection | ||
| pc = mcollections.PatchCollection([], label="empty collection") | ||
| ax.add_collection(pc) | ||
|
|
||
| # This should not crash | ||
| leg = ax.legend() | ||
|
|
||
| # Check that the label still appears | ||
| assert len(leg.get_texts()) == 1 | ||
| assert leg.get_texts()[0].get_text() == "empty collection" | ||
|
|
||
| # The legend handle should exist | ||
| assert len(leg.legend_handles) == 1 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.