Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite). #29130

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 21 commits into from
Jan 3, 2025

Conversation

NGWi
Copy link
Contributor

@NGWi NGWi commented Nov 12, 2024

This is to fulfill @tacaswell's recommendation (at the PyData sprint I joined last week) that for a quick fix to close issue #24404, we raise a warning when such a script is attempted.
The complaint in that issue was: that if both c and facecolors args are specified for a plot's markers (specifically a scatterplot), then the facecolors arg is ignored, while a user might expect that facecolors would be used for the fill and the 'c' color would remain at the edges.
I have the code raise a warning in the style of others I saw in _axes.py :
"You passed both c and facecolor/facecolors for the markers. "
"Matplotlib is ignoring the facecolor "
"in favor of what you specified in c. "
"This behavior may change in the future."
I am hoping that in the future we can implement c as edgecolors in that case, and we are not forced at some point to cause the plot to fail.

PR checklist

…he future we may implement c as edgecolors in that case or cause plot to fail.
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 week or so, please leave a new comment below and that should bring it to our attention. 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.

@NGWi
Copy link
Contributor Author

NGWi commented Nov 12, 2024

Would you like me to push another commit and PR that removes the offending extra line and whitespace (flake8 fail) or edit the PR?
Update: I edited the PR-staged code.

@NGWi
Copy link
Contributor Author

NGWi commented Nov 13, 2024

I see the other failures are because of two tests failing: one because my warning was triggered for test_legend_pathcollection_labelcolor_markfacecolor_cmap

        fig, ax = plt.subplots()
        facecolors = mpl.cm.viridis(np.random.rand(10))
        ax.scatter(
            np.arange(10),
            np.arange(10),
            label='#1',
            c=np.arange(10),
            facecolor=facecolors
        )

And the other because another warning was triggered.
That second one has been plaguing PRs since this morning: https://github.com/matplotlib/matplotlib/actions/workflows/tests.yml

=========================== short test summary info ============================
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_backend[toolmanager-MPLBACKEND=wxagg-BACKEND_DEPS=wx] - Failed: Subprocess failed to test intended behavior
<frozen _collections_abc>:982: UserWarning: Treat the new Tool classes introduced in v1.5 as experimental for now; the API and rcParam may change in future versions.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/runner/work/matplotlib/matplotlib/lib/matplotlib/tests/test_backends_interactive.py", line 232, in _test_interactive_impl
    assert result.getvalue() == result_after.getvalue()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

I just raised issue #29131 about that one.
But I'll have to analyze the first test to see if it's failing only because of my intentional improvement in behavior.

To pass flake8 formatting check
Comment on lines 4623 to 4625
"You passed both c and facecolor/facecolors for the markers. "
"Matplotlib is ignoring the facecolor "
"in favor of what you specified in c. "
Copy link
Member

Choose a reason for hiding this comment

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

Slightly more concise:

Suggested change
"You passed both c and facecolor/facecolors for the markers. "
"Matplotlib is ignoring the facecolor "
"in favor of what you specified in c. "
"Passing both c and facecolor/facecolors for the markers "
"is ambiguous. facecolor is ignored in in favor of c. "

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for reviewing the comment. Your change is more concise, and I understand the argument that matplotlib developers consider passing both as ambiguous.
However, a user intentionally passing both will likely not understand why it is ambiguous. They probably assumed incorrectly, as the issue's Original Poster did, that c defines both a face color and edge color and that just like adding edge color works, the face color can also be overwritten.

@timhoffm
Copy link
Member

Would you like me to push another commit and PR that removes the offending extra line and whitespace (flake8 fail) or edit the PR? Update: I edited the PR-staged code.

Yes, you've don this correctly: Please update this PR and do not create new ones on the same topic. You can choose whether to add additional commits or force-push a new version.

@NGWi
Copy link
Contributor Author

NGWi commented Nov 13, 2024

I tried out the test code that was failing
test_legend_pathcollection_labelcolor_markfacecolor_cmap

        fig, ax = plt.subplots()
        facecolors = mpl.cm.viridis(np.random.rand(10))
        ax.scatter(
            np.arange(10),
            np.arange(10),
            label='#1',
            c=np.arange(10),
            facecolor=facecolors
        )

As I suspected, facecolors doesn't do anything in that case, so my addition justifiably raises the warning. This, of course, alters the outcome from the assertion's previous expectation.
I will change the test to:

        fig, ax = plt.subplots()
        ax.scatter(
            np.arange(10),
            np.arange(10),
            label='#1',
            c=np.arange(10)
        )

which produces the indentical plot as before (I tested it with .canvas.tostring_rgb()).
However, I imagine that will not update all your online test suites. I hope you will approve my PR regardless.

@NGWi
Copy link
Contributor Author

NGWi commented Nov 13, 2024

That failing test was added in Commit 66ec3a0 .
I see the intention was to test if the label color in the legend is correctly set when using a colormap.
So I, instead, am only dropping the c argument in the test:

    fig, ax = plt.subplots()
    facecolors = mpl.cm.viridis(np.random.rand(10))
    ax.scatter(
        np.arange(10),
        np.arange(10),
        label='#1',
        facecolor=facecolors
    )

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

This will let the random color assignment shine through, but it won't raise a warning. The only problem would be if a visual compare test were done with its old output.

lib/matplotlib/tests/test_legend.py Show resolved Hide resolved
@NGWi
Copy link
Contributor Author

NGWi commented Nov 17, 2024

I want to mention that I am working on an alternative branch where I add an ec (edge colors) arg to .scatter() that parallels c's functionality and would come before the current 'edgecolors' arg (which I bump to kwargs). This would make it explicit that c should not be used for specifically setting edge colors and return intuitive, symmetrical functionality to .scatter().

(timhoffm: accidental edit reverted)

@NGWi
Copy link
Contributor Author

NGWi commented Nov 18, 2024

@timhoffm, your edit to my comment above is full of good points.
I would still want to explore if I can add the functionality of having two independent colormap objects running in parallel, one for face and one for edge. Don't worry, I am treading extra carefully as I am aware that I am new here, plus I am proposing a much bigger shift than what @tacaswell already proposed.

@timhoffm
Copy link
Member

@timhoffm, your edit to my comment above is full of good points.

Sorry for editing your comment. I intended to click "quote reply" but accidentally hit the wrong button 🐑. I've reverted the edit.

For reference, here is my comment:

I'm sceptical on this. c is primarily used for color mapping. With the current implementation of ScalarMappable you cannot have two independent color mappings (one for face and one for edge). Therefore, I don't see how ec could be parallel to c. Note also that ec already exists as an alias for edgecolors.

@timhoffm
Copy link
Member

I would still want to explore if I can add the functionality of having two independent colormap objects running in parallel.

You should look into #28658 and #28428, which generalize the colormapping concept. The case of separate edgecolor mapping is not explicitly contained, but fits into that context.

@NGWi
Copy link
Contributor Author

NGWi commented Nov 19, 2024

Codecov doesn't like that in my test I wrote:

+     def get_next_color():
+         return 'blue'

I think it considers the output of that function as untested. But I was just following the lead of three tests above it, which it is also complaining about. Should I change my test, or ignore it?

The other failing check is build time taking over an hour (including the test suite, I think). I'm not sure that is because of something I did, though.

Comment on lines 2908 to 2924
def get_next_color():
return 'blue' # currently unused

Copy link
Member

@timhoffm timhoffm Nov 20, 2024

Choose a reason for hiding this comment

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

Let's not move the get_next_color() functions out of the tests. This produces an indirection (harder to read) and implicit coupling of the tests. There's also value in the "currently unused" comment in here.

Compared to this, the repetition of two lines is clearly the lesser evil.

Even better would be a local function

def get_next_color():
    raise AssertionError("Color cycle should not be accessed")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have no problem rolling back those commits.
But what do you want to do about the fact that CodeCov raises an "Uncovered" flag by every incidence of return 'blue'? It even failed my code because I had added another incidence of that: (https://github.com/matplotlib/matplotlib/pull/29130/checks?check_run_id=33222717934)

Copy link
Member

Choose a reason for hiding this comment

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

CodeCov does not strictly need to pass, but we have it for information only.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rolled back.

@NGWi NGWi force-pushed the issue24404_addwarning branch from 611a9dc to 38c092a Compare November 20, 2024 21:17
@@ -3027,7 +3027,7 @@ def get_next_color():
])
def test_parse_scatter_color_args_edgecolors(kwargs, expected_edgecolors):
def get_next_color():
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
def get_next_color():
def get_next_color(): # pragma no cover

Pretty sure it has to go next to the function declaration because you're telling coverage to ignore this whole block

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. That was my instinct as well, but I saw @jefromyers did it next to the return statement

return 'blue' # pragma: no cover
(line 9076 in the current iteration).
I just corrected it.

@NGWi
Copy link
Contributor Author

NGWi commented Dec 4, 2024

The AppVeyor check failed, but after reading the error logs, and doing the same workflow on my Mac, I believe it's a Windows problem unrelated to my change.

@NGWi NGWi force-pushed the issue24404_addwarning branch from e6e49aa to a18364c Compare December 4, 2024 02:45
@NGWi
Copy link
Contributor Author

NGWi commented Dec 4, 2024

I rebased my branch but incidentally created duplicate commits on top. I should have used interactive rebase, sorry.

@NGWi
Copy link
Contributor Author

NGWi commented Dec 4, 2024

Is there anything else I can do to improve my Pull Request?

lib/matplotlib/tests/test_legend.py Outdated Show resolved Hide resolved
NGWi and others added 2 commits December 4, 2024 10:11
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@NGWi
Copy link
Contributor Author

NGWi commented Dec 4, 2024

Anything else?

@NGWi NGWi changed the title Raise warning if both c and facecolors are used in scatter plot. Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite). Dec 4, 2024
@NGWi
Copy link
Contributor Author

NGWi commented Dec 5, 2024

Thank you, @timhoffm

@story645 story645 merged commit df49afc into matplotlib:main Jan 3, 2025
39 checks passed
@story645 story645 added this to the v3.10.1 milestone Jan 3, 2025
@story645
Copy link
Member

story645 commented Jan 3, 2025

Thanks @NGWi, sorry it took so long to follow up, hope to see more contributions from you! 🥳

@NGWi
Copy link
Contributor Author

NGWi commented Jan 3, 2025 via email

@QuLogic
Copy link
Member

QuLogic commented Jan 7, 2025

@story645 story645 added this to the v3.10.1 milestone Jan 3, 2025

You didn't trigger a backport, if this milestone was intentional.

@story645
Copy link
Member

story645 commented Jan 7, 2025

Uch what's the command again? I think this should get back ported since it's just an error check, right?

@timhoffm
Copy link
Member

timhoffm commented Jan 7, 2025

@meeseeksdev backport to v3.10.x

meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Jan 7, 2025
…are used in scatter plot (... and related improvements in the test suite).
greglucas added a commit that referenced this pull request Jan 7, 2025
…130-on-v3.10.x

Backport PR #29130 on branch v3.10.x (Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite).)
@ksunden ksunden mentioned this pull request Mar 3, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

[Bug]: Cannot use empty markers in scatter
5 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.