-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
bugfix #18600 by using the MarkerStyle copy constructor #18603
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
bugfix #18600 by using the MarkerStyle copy constructor #18603
Conversation
Markers already support a copy construction: `MarkerStyle.set_marker` accepts other instances of `MarkerStyle`. However, some Artists, when copying markers, instead construct the copy from the other instance's `get_marker` and `get_fillstyle` methods. This destroys (unsupported) manipulations the user might make to the marker, as discovered in issue #18600. By switching constructors, we can get a more faithful copy without explicitly relying on any of `MarkerStyle`'s private methods in places they do not belong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change seems good. Would you be able to update the docstrings for MarkerStyle.__init__
and MarkerStyle.set_marker()
? I had to go spelunking in the code to know that this was even correct.
Believe you me I understand THAT feeling! I will update the doc strings (maybe tomorrow, maybe Thursday) and re-ping you here. |
- Mention errorbar in the module docs. - Add details of the copy constructor.
- Move errorbar mention to new line. - Remove whitespace from blank lines.
@dopplershift I updated the docs of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still have some flake8 issues as well.
Could you also add a (smoke) test that this does not blow up? 👍 modulo fixing the style issues and adding a test. |
@tacaswell Can you explain what a smoke test means? You are talking to a programming scientist, not a programmer :) What should I be testing? That Line2D, when given an unusual marker, actually copies the marker? The previous implementation would have worked for all the "standard" markers. |
Sorry for the jargon, it is from "turn it on and see if it smokes!". As your original bug generated a stack trace when it should not have so the minimal test is if you can run that code and not raise (e.g. does not start smoking because it blew up). A better and more complete test is verifying that it also actually set the marker to what it should be. |
@tacaswell If I add the test, aren't we saying that the weird thing I did is in a nebulous not-supported-but-not-NOT-supported thing? |
Creating markers from MarkerStyle and passing them to axes could cause both `plot` and `errorbar` to raise ``` TypeError: float() argument must be a string or a number, not 'MarkerStyle' ``` in 3.2.2, as found in #18600 and discussed in the comments of #18603. `test_marker_as_MarkerStyle` ensures that a MarkerStyle instance can be used as the marker argument to plot, scatter, and errorbar.
OK. I actually was able to reduce my problem even further:
which has nothing to do with my transform. In 3.2.2 this throws a The good news is that 3.3.2 already passes / can run this mwe. |
Rather than new paragraphs, each option is a new rst - style list item.
- Add extra blank lines around test_marker_as_MarkerStyle - Add spaces in arrays.
(compare with similar test in test_lines)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still have flake8 issues. You can find them on the Files changed tab.
Modulo the What you did is definitely in the "supported" category of things. |
OK, Here's another very strange thing, but it may warrant its own, separate issue. I suspected that my problem with my explicit legend example was with Line2D. So I wrote this little example #!/usr/bin/env python3
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
from matplotlib.markers import MarkerStyle
print(f"{matplotlib.__version__=}")
print(f"{matplotlib.get_backend()=}")
# But when I use it in errorbar
fig_ref = plt.figure()
fig_ref.add_artist(mlines.Line2D([0.25,0.75],[0.25,0.75], marker='d'))
fig_test = plt.figure()
fig_test.add_artist(mlines.Line2D([0.25,0.75],[0.25,0.75], marker=MarkerStyle('d')))
plt.show() Which outputs
And then I wrote a little test that would check for that difference in @check_figures_equal()
def test_marker_as_markerstyle_comparison(fig_test, fig_ref):
fig_ref.add_artist(mlines.Line2D([0.25,0.75],[0.25,0.75], marker='d'))
fig_test.add_artist(mlines.Line2D([0.25,0.75],[0.25,0.75], marker=MarkerStyle('d'))) and the test passes!
What?! I tried adding to the above test fig_ref.savefig('ref')
fig_test.savefig('test') to the test to see if they're REALLY the same or not and sure enough, the both look like this: What gives? Note that I observe a difference in 3.2.2 but not the latest that my PR is written against. |
That was fixed in #16692, I think. |
OK, that seems correct. I will not add my test then. |
@QuLogic---as I mentioned in my comment towards the top of this PR, if you actually look at the code for the flake8 complaints and add a newline, the docstrings become harder to read. If you tell me that you understand that, then I will change them. Otherwise, I advocate ignoring those complaints. |
We do not ignore flake8 arbitrarily. We have plenty of these lists wrapped, so I don't see how it is less legible. |
Widows and orphans are known to typesetters to cause ugly looking or hard-to-read text. In this case the enormous amount of whitespace introduced by the orphans created by wrapping these only-slightly-over-length lines cause visual interruption. A linter usually doesn't take that sort of "global appearance" into account. But I'll change it against my better judgement. |
Um... now eslint simply failed to set up? I don't think this one was my fault. |
eslint reran and succeeded, so all tests have now passed. |
On projects that only have a handful (or just one) person working on them it is plausible to have use your judgement on the formatting, but on a project the scale of Matplotlib (we have over 1k people who have touched the code in some way at this point!) we have to rely on automated tools to maintain any consistency in the codebase. It also means we can have the robot tell you the style is wrong than have a person tell you ;) |
Thanks for finding and fixing this @evanberkowitz. Congratulations on your first Matplotlib PR 🎉 hopefully we will hear from you again! |
Glad to contribute. Hopefully there will never be further bugs for me to encounter ;) ! |
#Deeper marker copies in Line2D update_from
Markers already support a copy construction:
MarkerStyle.set_marker
accepts other instances of
MarkerStyle
. However, Line2D, whencopying markers, instead construct the copy from the other instance's
get_marker
andget_fillstyle
methods. This destroys (unsupported)manipulations the user might make to the marker, as discovered in
issue #18600.
By switching constructors, we can get a more faithful copy without
explicitly relying on any of
MarkerStyle
's private methods in placesthey do not belong.
PR Summary
This change is also more in line with the
self = other
style of the rest of the method's body.PR Checklist
Has pytest style unit tests (and
pytest
passes).master
:Is Flake 8 compliant (run
flake8
on changed files to check).[N/A] New features are documented, with examples if plot related.
[N/A] Documentation is sphinx and numpydoc compliant (the docs should build without error).
Conforms to Matplotlib style conventions (install
flake8-docstrings
andpydocstyle<4
and runflake8 --docstring-convention=all
).[N/A] New features have an entry in
doc/users/next_whats_new/
(follow instructions in README.rst there).[N/A] API changes documented in
doc/api/next_api_changes/
(follow instructions in README.rst there).