Skip to content

Fix inability to use empty markers in scatter #25593

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

maramiulescu
Copy link

@maramiulescu maramiulescu commented Mar 31, 2023

PR Summary

Fixes #24404

Modifies the scatter function to allow users to plot using empty 'o' markers without any additional code.

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (and pytest passes)
  • [N/A] Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • [N/A] New plotting related features are documented with examples.

Release Notes

  • New features are marked with a .. versionadded:: directive in the docstring and documented in doc/users/next_whats_new/
  • [N/A] API changes are marked with a .. versionchanged:: directive in the docstring and documented in doc/api/next_api_changes/
  • Release notes conform with instructions in next_whats_new/README.rst or next_api_changes/README.rst

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.

@tacaswell tacaswell added this to the v3.8.0 milestone Mar 31, 2023
Comment on lines 4687 to 4688
if (colors is None or edgecolors is None) and not mcolors.is_color_like(c)\
and not type(c) == np.ndarray:
Copy link
Member

Choose a reason for hiding this comment

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

(I'm going to get the indentation wrong in the GH UI)

Suggested change
if (colors is None or edgecolors is None) and not mcolors.is_color_like(c)\
and not type(c) == np.ndarray:
if ((colors is None or edgecolors is None) and not mcolors.is_color_like(c)
and not type(c) == np.ndarray):

we prefer using () for multi-line expressions over using line-continuation.

Copy link
Member

Choose a reason for hiding this comment

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

I say that and then see a whole bunch of it in the code right above this 🤦🏻

Copy link
Author

Choose a reason for hiding this comment

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

Updated

@@ -2760,7 +2762,10 @@ def get_next_color():
_, _, result_edgecolors = \
mpl.axes.Axes._parse_scatter_color_args(
c, edgecolors, kwargs, xsize=2, get_next_color_func=get_next_color)
assert result_edgecolors == expected_edgecolors
if type(expected_edgecolors) == np.ndarray:
Copy link
Member

Choose a reason for hiding this comment

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

isinstance here as well please.

Copy link
Author

Choose a reason for hiding this comment

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

Updated

@tacaswell
Copy link
Member

Thank you for this work @maramiulescu ! I left a few minor style comments. I feel strongly about the isinstance changes, but am more 🤷🏻 on the line continuation as it passes our style checker.

Would you be willing to write a whats new for this? I think that this feature is best explained with an image and is impactful enough we want to be sure to highlight it.

@maramiulescu
Copy link
Author

Thanks @tacaswell for reviewing! I'm working together with @ewpardijs on this, we will implement your feedback and write a what's new soon.

@tacaswell
Copy link
Member

We recently widened our linewidth to 88 (from 80) so you can be a bit more relaxed on that front for any new code you add and code immediately around it, but please do not reflow all of the code in this file.

@ksunden
Copy link
Member

ksunden commented Mar 31, 2023

@maramiulescu FYI, a slight tweak to how you word the PR description will automatically link the PR to close that issue:

https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword

(e.g. saying "Fixes #XXXXX" instead of "Fix issue #XXXXX")

I was going to just link this one manually, but the search box is not letting me select #24404 for some reason...

@oscargus
Copy link
Member

oscargus commented Apr 1, 2023

( I edited the description before seeing @ksunden's comment, so now it is linked...)

@maramiulescu
Copy link
Author

( I edited the description before seeing @ksunden's comment, so now it is linked...)

I edited it to say "Fixes ..." too, but it didn't get linked. Could it be that only a maintainer can link a PR after it's been created?

@jklymak
Copy link
Member

jklymak commented Apr 1, 2023

I don't think the linking in the message is restricted to maintainers.

I'd also suggest a better title and description. Even should I click through to the issue the number won't mean anything to me in a week, whereas knowing what it fixed will.

@erinproc
Copy link

Hi, I am a new contributor and I was working on this issue when the pull request was submitted. I would still like to contribute in some way if possible, I noticed when looking at the files changed there was a warning that "Added lines #L4623 - L4624 were not covered by tests". Is this something that I could add? If not, if there is any other way I could help contribute, please let me know as soon as possible!

@oscargus
Copy link
Member

@erinproc please have a look at https://github.com/matplotlib/matplotlib/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22 especially those that does not have a PR associated with them. That is probably a better starting point. But, yes, you are correct that ideally all lines should be covered in a PR.

@maramiulescu maramiulescu changed the title Fix issue #24404 Fix inability to use empty markers in scatter Apr 20, 2023
@maramiulescu
Copy link
Author

I don't think the linking in the message is restricted to maintainers.

I'd also suggest a better title and description. Even should I click through to the issue the number won't mean anything to me in a week, whereas knowing what it fixed will.

Updated the title and the description

@erinproc
Copy link

@oscargus thank you for your advice. I was working on this issue for an assignment in my software engineering course which is due soon, so I don't really have time to pivot to a new issue, but I'd still like to contribute to this pull request if possible. I have written some new tests and I was wondering what is the best way to submit these to be added to the current pull request?

@oscargus
Copy link
Member

@erinproc Wait until this is merged and then contribute them I'd say.

You can also add your commits on top of this, put that may still require rebasing later on so probably better to wait.

@erinproc
Copy link

@oscargus thanks for all of your help and advice, I really appreciate it. Out of curiosity, how long might it take to merge this pull request? I'm unfamiliar with the timeline of these types of things, and I'd just like to have a general idea.

@oscargus
Copy link
Member

I'd say between one hour and, well, the oldest we have is six years... I'm not really up to date with this one, but hopefully shouldn't be long.

@maramiulescu
Copy link
Author

maramiulescu commented Apr 20, 2023

Would you be willing to write a whats new for this? I think that this feature is best explained with an image and is impactful enough we want to be sure to highlight it.

@tacaswell What's new added, could you have a look?

Enable configuration of empty markers in `~matplotlib.axes.Axes.scatter`
------------------------------------------------------------------------

`~matplotlib.axes.Axes.scatter` can now be configured to plot empty markers without additional code. Setting ``facecolors`` to *'none'* and defining ``c`` now draws only the edge colors for fillable markers.
Copy link
Member

Choose a reason for hiding this comment

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

I think this should more explicitly highlight the "with colormap" part of this change, it has always been possible to have empty single color markers with facecolor='none', edgecolor='C0', e.g.

Admittedly it is a bit surprising that specifying edgecolor explicitly was required, but that is due to the default being to follow "face"

Does this PR do anything to make that behavior change (without a cmap?)

Copy link
Author

Choose a reason for hiding this comment

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

We've changed the text in 39cfd56, hopefully now it's more fitting. If I understand your question correctly, yes, this PR does change that behavior: for the value of edgecolor, c now takes precedence over face

@@ -4338,6 +4340,7 @@ def _parse_scatter_color_args(c, edgecolors, kwargs, xsize,
- kwargs['edgecolor']
- edgecolors (is an explicit kw argument in scatter())
- kwargs['color'] (==kwcolor)
- c (if not None)
Copy link
Member

Choose a reason for hiding this comment

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

I think this is only true if facecolors is "none". Otherwise I would expect the test case (dict(c='b'), None), from the edited test to instead be (dict(c='b'), np.array([[0, 0, 1, 1]])), similar to the last test case added... I think, at least?

Comment on lines +4648 to +4649
x, y, s, linewidths = \
cbook._combine_masks(x, y, s, linewidths)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
x, y, s, linewidths = \
cbook._combine_masks(x, y, s, linewidths)
x, y, s, linewidths = cbook._combine_masks(x, y, s, linewidths)

Comment on lines +4655 to +4657
c = np.ma.masked_invalid(c)
x, y, s, colors, linewidths = \
cbook._combine_masks(x, y, s, colors, linewidths)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
c = np.ma.masked_invalid(c)
x, y, s, colors, linewidths = \
cbook._combine_masks(x, y, s, colors, linewidths)
c = np.ma.masked_invalid(c)
x, y, s, colors, linewidths = cbook._combine_masks(x, y, s, colors, linewidths)

Copy link
Member

Choose a reason for hiding this comment

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

This also needs a test case that will cover this line.

if colors is None:

if ((colors is None or edgecolors is None) and not mcolors.is_color_like(c) and
(not isinstance(c, np.ndarray) or isinstance(c, np.ma.MaskedArray))):
Copy link
Member

Choose a reason for hiding this comment

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

Why are we gating on the type here? Will our normalization above ensure other iterables will be converted to numpy arrays?

@@ -2749,6 +2749,8 @@ def get_next_color():
(dict(c='b', edgecolor='r', edgecolors='g'), 'r'),
(dict(color='r'), 'r'),
(dict(color='r', edgecolor='g'), 'g'),
(dict(facecolors='none'), None),
(dict(c='b', facecolors='none'), np.array([[0, 0, 1, 1]]))
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to cover the case of colormapping + empty here as well.

@tacaswell
Copy link
Member

@maramiulescu Sorry this fell off our radar.

@QuLogic QuLogic modified the milestones: v3.9.0, v3.10.0 Mar 27, 2024
@ksunden ksunden modified the milestones: v3.10.0, future releases Oct 9, 2024
@claytharrison
Copy link

I'd be interested in taking this over if @maramiulescu has no objections. It's been bugging me for ages and it would be nice to just have it finally work.

@maramiulescu
Copy link
Author

It would be great if you could take over @claytharrison

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Waiting for author
Development

Successfully merging this pull request may close these issues.

[Bug]: Cannot use empty markers in scatter
9 participants