-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
fix tightbbox to account for markeredgewidth #16607
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
fix tightbbox to account for markeredgewidth #16607
Conversation
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.
Just code that makes a plot that's composed of one marker with known size and edge width and then check that get_tightbbox returns the right values?
Sounds good.
I don‘t know if it‘s necessary/worth to distinguish different markers.
lib/matplotlib/lines.py
Outdated
@@ -617,7 +617,8 @@ def get_window_extent(self, renderer): | |||
ignore=True) | |||
# correct for marker size, if any | |||
if self._marker: | |||
ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 | |||
extra_pts = self._markersize + self._markeredgewidth |
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.
extra_pts = self._markersize + self._markeredgewidth | |
extra_pts = self._markersize + self._markeredgewidth / 2 |
I think. The edge line is drawn centered on the marker outline. So only half of the width adds to the extent.
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're right, but this is already accounted for in the * 0.5
for both marker size and edge width in the next line. In the more general case, this multiplication is no longer needed, see newest commits.
Some design decisions that I didn't know how to make:
I'm happy to do that simple refactor here, since I'm adding the information, but wanted to make sure there was a shared feeling that it is necessary in the first place, and that I wouldn't be wasting too much time doing it in a style that would immediately be rejected. |
Now that it's more obvious that this gets messy on a per-glyph basis, should we include one test per glyph or just test a couple of the nasty ones? (say, 'p', '*', 'o', 'x', to get examples of glyphs with miter joins, round joins, filled and not)? |
@timhoffm Ready for re-review and need help.
|
I think this is a dpi issue. Some calculation does not Takt them into account. The jupyter backend (%matplotlib inline) sets 72dpi by default, everything else uses 100dpi. What happens if you do Sorry for the formatting, I‘m on mobile. I‘m quite busy right now. Please be patient with a full review. That may take a couple of days. |
Thanks for the quick reply Tim! Looks like it is a DPI thing, I'll follow that lead. Of course I assume you're very busy, and I definitely wasn't meaning to rush you. I just wanted to ping so you knew it was safe to start looking without wasting even more of your time. Thanks in advance for your help! |
You removed the line |
Haha, didn't see the "member" when I replied to you earlier @ImportanceOfBeingErnest. Hopefully I didn't come off as presumptuous! Mostly, thanks for the good eye! I had forgotten that the markers stuff is in points. Fixed the code to make that consistent. Tests should pass now. Had to push up new "baseline_images", since they were generated at different DPI than before for whatever reason, but now look as expected. |
To have image comparisson look like the default style one can use
...just in case that is still relevant. One could also try to use only a single image (image comparison is rather expensive, so if it can be reduced to a minimum, that would sure be nice) In general I haven't quite understood how wrong adding half the edge width would be and if that really warrants adding this huge code block. In particular, I would have though adding half the edgewidth would rather overestimate the bbox - which would be totally acceptable in my eyes. |
I agree with @ImportanceOfBeingErnest. This is for the rare case that a marker over-spills its axes, and most folks don't have markeredgewsidths that are much larger than a point or two. This is really cool that you sorted through all the geometry, but is it overkill compared to the actual problem? |
But I don't think we need to cover the general case here, just polygons and circles. I guess polygons would be relatively simpler; for circles, somehow luckily, falling back to 0.5*mew would work :-)
Well that's the problem as always: any code that goes in needs to be maintained and is extremely annoying to get rid of, and maintainer time is finite. That's why we're not necessarily so keen on adding a few hundreds of line of code just to handle a relatively edge case :-) (even though it's quite impressive work, as mentioned just above :-))
Not a huge fan of playing the coverage numbers game :-) |
@anntzer , I got a little swamped with paper deadlines, but started working on code for general solution today (written, just needs testing). However, I ran into a bit of a design issue. Right now bezier.py imports path.py (but only in a couple of functions that feel to me like they should be in path.py anyway...). Obviously a general routine that calculates bbox for a stroked path belongs as a method of Path. But I need helper routines from bezier.py so.... Should I
in order to minimize resistance to this already pretty contentious PR? |
I would be fine with moving stuff from bezier.py to path.py if that's necessary. |
Before there‘s going more work into this: Are we positive, that we want to take on the exact solution with the added amount of code vs. an approximate solution? It would be a shame to detail it all out and later decide that the maintenance burden would be too high. I haven‘t looked into this in detail, but the amount of code needed to special-case the exact solution scares me a little. Ping @jklymak @anntzer @tacaswell @ImportanceOfBeingErnest I think we should have a champion for this. If nobody is stepping up for it, I fear the PR will have a hard time of getting merged. |
I think this will depend on the amount of code involved... (I can't guarantee a quick review, but will try to keep a look on this.) |
Yeah something like @anntzer's proposal was actually my plan after you guys asked about performance, just didn't want to dump a bunch of work into this if it wasn't going to get accepted, as the current implementation works just fine for my purposes. The current recommendation is:
|
Superceded by #17119, a cleaner implementation using some of my recent additions to |
PR Summary
This initial PR is a naive fix for issue #16606; it will be updated as I document what the expected behavior should be for each marker type.
In short, increases the padding added to
Line2D.get_window_extent
in order to account for markers with non-trivial edge widths.I also do not know what kind of test would be appropriate to add here? Just code that makes a plot that's composed of one marker with known size and edge width and then check that
get_tightbbox
returns the right values? Is the goal one test per marker type?PR Checklist