Skip to content

Add textcolor to legend based on labelcolor string #24122

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
merged 7 commits into from
Oct 20, 2022

Conversation

chahak13
Copy link
Contributor

@chahak13 chahak13 commented Oct 8, 2022

PR Summary

As raised by #20577, setting labelcolor to any of the string options did not work with a scatter plot as it is a PathCollection with possible multiple color values. This commit fixes that. Now, if there is a colormap or a scatter plot with multiple values, then, the legend text color is not changed, but otherwise, the text color is changed to the color of the scatter markers.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

As raised by matplotlib#20577, setting `labelcolor` to any of the string options
did not work with a scatter plot as it is a PathCollection with possible
multiple color values. This commit fixes that. Now, if there is a
Colormap or a scatter plot with multiple values, then, the legend text
color is not changed, but otherwise, the text color is changed to the
color of the scatter markers.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@chahak13
Copy link
Contributor Author

chahak13 commented Oct 8, 2022

@timhoffm as we discussed, I started working on issue #20577. I wanted some suggestions if you could help. Did not want to clutter the issue discussion with code questions so moved to this working PR.

My idea is that if we have a LinearSegmentedColormap, then we should not be changing the text color. If not, we check if we have a single color/same color in an array and proceed accordingly. These seemed to work on at least the simple cases but I ran into one issue while writing the tests for this. If I have some scatter plots on an axes, like

fig, ax = plt.subplots()
ax.scatter(np.arange(10), np.arange(10)*1, label='#1', c='r')
ax.scatter(np.arange(10), np.arange(10)*2, label='#2', c='g')
ax.scatter(np.arange(10), np.arange(10)*3, label='#3', c='b')
leg = ax.legend(labelcolor="linecolor")

This creates a ListedColormap which is what I was expecting, but when I write a function in test_legend.py as

def test_legend_pathcollection_labelcolor_linecolor():
    fig, ax = plt.subplots()
    ax.scatter(np.arange(10), np.arange(10)*1, label='#1', c='r')
    ax.scatter(np.arange(10), np.arange(10)*2, label='#2', c='g')
    ax.scatter(np.arange(10), np.arange(10)*3, label='#3', c='b')

    leg = ax.legend(labelcolor='linecolor')
    for text, color in zip(leg.get_texts(), ['r', 'g', 'b']):
        assert mpl.colors.same_color(text.get_color(), color)

the generated cmap comes out to be LinearSegmentedColormap (Found using handle.get_cmap() in both cases). Why would there be a different behavior in both cases? Or am I doing something wrong? Thanks!

@timhoffm
Copy link
Member

timhoffm commented Oct 9, 2022

I admit this is quite arcane for historic reasons. All collections have a colormap, even if they don't use it.
What you need to check is whether the data values get_array() are None. If this is not None it contains the values to be colormapped.

Due to inconsistencies in the colormap setup, it is suggested to instead
check for `get_array` to get an array of values to be color mapped. This
check is more robust irrespective of whatever the type of colormap is
set to be.
Tests are added to check various conditions for the text color for a
legend set with `linecolor`, `markeredgecolor`, `markerfacecolor` in a
scatter plot.
@chahak13
Copy link
Contributor Author

chahak13 commented Oct 9, 2022

@timhoffm Thanks for that! I've updated and added tests to the PR. I was not sure where to document this change though. Let me know what else I need to do?

@chahak13 chahak13 changed the title [WIP] Add textcolor to legend based on labelcolor string Add textcolor to legend based on labelcolor string Oct 12, 2022
Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good to go modulo some optional improvements in the tests.

@chahak13 if we consider this only a bugfix, there's no additional documentation needed.

@chahak13
Copy link
Contributor Author

@timhoffm thanks! I updated the tests. Should be good now :)

Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, sorry my suggestion code was incorrect. This should fix CI.

chahak13 and others added 2 commits October 19, 2022 21:12
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@chahak13
Copy link
Contributor Author

Right, sorry. Should have spotted that too. Thanks!

@chahak13
Copy link
Contributor Author

@timhoffm changed it to the correct get_color call. Tests should all be fine now. Let me know if there's anything else. Thanks!

@tacaswell tacaswell added this to the v3.7.0 milestone Oct 20, 2022
@tacaswell tacaswell merged commit 84dec9c into matplotlib:main Oct 20, 2022
@tacaswell
Copy link
Member

Thanks @chahak13 and congratulations on your first merged Matplotlib PR 🎉 (I know you have at least one more in flight). I hope we continue to hear from you.


Even though this is a bug fix, it is a fair bit of code and I do not feel comfortable backporting this no 3.6.x.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants