Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Walk the artist tree when preparing for saving with tight bbox.#14216

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tacaswell merged 1 commit intomatplotlib:masterfromanntzer:dryrun-walk-tree
May 24, 2019

Conversation

anntzer
Copy link
Contributor

PR Summary

Closes (I think?)#14180 and#14134 (comment).
@astrofrog@pllim can you confirm?

PR Checklist

  • Has Pytest style unit tests
  • Code isFlake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@anntzeranntzer added the Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. labelMay 14, 2019
@anntzeranntzer added this to thev3.2.0 milestoneMay 14, 2019
@tacaswell
Copy link
Member

At this point my may as well just letprint_method fully run in the line above?

@anntzer
Copy link
ContributorAuthor

So what's the patch you propose?

@astrofrog
Copy link
Contributor

I'll test this out tomorrow!

Copy link
Member

@jklymakjklymak left a comment

Choose a reason for hiding this comment

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

I'm not convinced we should fix this like this. AstroPy is overridingAxes.get_tightbbox but not doing all the thingsAxes.get_tightbbox does. I think the onus is on AstroPy to inheritget_tightbbox more robustly, not for us to sledgehammer the issue with an extra draw to the detriment of the vast majority of cases that don't need this.

If there is something we can do to make it easier for AstroPy to customizeget_tightbbox to their needs, we should definitely try and do that. But I think if at all possible they should callsuper().get_tightbbox to make sure they stay current with us.

@astrofrog
Copy link
Contributor

@jklymak - I'd be fine with fixing Astropy - essentially what we need is a way to provide extra bounding boxes of plot items that need to be included in the calculation of the final bounding box. I guess one way would be to simply call Axes.get_tightbbox and then do a union of that and our extra bounding boxes?

@jklymak
Copy link
Member

@astrofrog - that'd work; but again,Axes.get_tightbbox now walks the artists in the axes (it didn't pre 3.0), and includes them all in the bbox, so maybe your artists are already included? If not, you can always callsuper.get_tightbbox(bbox_extra_artists=listofartists), though that willonly include artists you specifically include.

BTW, since we were effectively doing the draw before withdry_run, maybe this PRshould go in as we may have broken other folks as well, and doing the extra draw won't be slower than what we had before...

@astrofrog
Copy link
Contributor

astrofrog commentedMay 14, 2019
edited
Loading

Ok so I've dug a little deeper into what we do in Astropy, and there are two separate things here - yes we can definitely simplify ourget_tightbbox to just inherit the one fromAxes then modify the BBox accordingly (and I'll do that shortly), but there is still an issue, which is thatget_tightbbox only gets called before drawing (which arguably is sensible)

In WCSAxes we dynamically draw e.g. the tick labels by setting up a singleText instance and whenWCSAxes.draw gets called we effectively modify the position of the text, draw it, modify the position, draw it again, and so on. Note that we don't add the artist to the axes, we just callartist.draw ourselves. At that point we also record the bbox of the drawn text, and combine it inget_tightbbox. However, as you can see from the following example,get_tightbbox now only gets called before draw, so that the extra bbox is never taken into account:

frommatplotlib.axesimportAxesfrommatplotlib.textimportTextfrommatplotlibimportpyplotaspltclassMyAxes(Axes):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)self.text=Text(0.5,0.5,'Text outside axes',transform=self.transAxes,clip_on=False,figure=self.figure,ha='center',va='center')self._extra_bbox=Nonedefdraw(self,renderer,*args,**kwargs):print('MyAxes.draw')result=super().draw(renderer,*args,**kwargs)self.text.set_position((-0.1,0.5))self.text.draw(renderer)self._extra_bbox=self.text.get_window_extent(renderer)returnresultdefget_tightbbox(self,*args,**kwargs):print('MyAxes.get_tightbbox')result=super().get_tightbbox(*args,**kwargs)ifself._extra_bboxisNone:returnresultelse:returnresult.union(self._extra_bbox)fig=plt.figure()ax=MyAxes(fig, [0.1,0.1,0.8,0.8])fig.add_axes(ax)print(ax.figure)fig.savefig('test.png',bbox_inches='tight')

In this case, the label is truncated at the left of the window rather than having the bounding box be adjusted. The reason we dynamically draw the text like this is that we don't know in advance how many tick labels will be drawn and we don't want to keep adding/removing artists from the axes.

The only fix I can think of without changing Matplotlib would be for us to have some kind of 'dry run' on the code that draws the artists, and only collects their bboxes but doesn't draw them. This would then get called insideget_tightbbox. Is that the only reasonable fix here?

@jklymak
Copy link
Member

OK, so you can't position yourtext until draw time? But can you extract that (self._position_text) and then call that inget_tightbbox as well? Thats basically what we do in_apply_aspect, which you see is called in bothdraw andget_tightbbox.

Its possible we should re-architect this somehow.

Anyway, for now I guess I'm OK w/ this PR as a fix to get us back where we were.

@tacaswell
Copy link
Member

doing the extra draw won't be slower than what we had before

However, backends thatdid do something withdry_run you may see a performance hit (no idea how big that actually is or which backends actually implemented the short-cut).

@anntzer
Copy link
ContributorAuthor

Let's assume that print_foomust walk the artist tree twice when preparing to save with tight bbox (that's the origin of this discussion). The way print_foo is implemented is basically always

  • prepare stuff before walking the tree (e.g., write the SVG preamble) and create a renderer object
  • walk the tree (figure.draw(renderer))
  • do some stuff after walking the tree (e.g., sending the buffer to Pillow to convert to jpg, running a postscript distiller, etc.)

With#14134, when doing the "dry_run" call, we would only do the preparation to extract out the renderer object. With this PR, we do the preparation and walk the tree, but still skip the post-walking step.

What did backends do to optimize dry_run? The only optimizations right now are

  • backend_ps replaces the output buffer by a null writer object (such thatbuf.write = lambda *args, **kwargs: None)
  • backend_pgf patches out all drawing methods from the renderer object (renderer.draw_path = lambda *args, **kwargs: None; same fordraw_image, etc.), which is strictly better (I don't think writing the (short) SVG preamble to a memory buffer really matters for performance anyways).
    It looks like we could actually just move the backend_pgf optimization to backend_bases (into_get_renderer, which could be called_get_nondrawing_renderer); then all backends (matplotlib's own and third-parties) would benefit from it instead of just backend_pgf.

Copy link
Contributor

@astrofrogastrofrog left a comment
edited
Loading

Choose a reason for hiding this comment

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

This fixes Astropy's tests - I do still plan to try and make it so thatget_tightbbox returns sensible results even without requiring Matplotlib to walk the draw tree first, but it will be good to have this fix in in the mean time.

pllim reacted with hooray emoji
@pllim
Copy link

If@astrofrog is happy with this, I am happy too. I am looking forward for this being in dev sooner than later, so we can un-xfail two of our tests over atastropy. 😄

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@astrofrogastrofrogastrofrog approved these changes

@jklymakjklymakjklymak approved these changes

Assignees
No one assigned
Labels
Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.
Projects
None yet
Milestone
v3.2.0
Development

Successfully merging this pull request may close these issues.

5 participants
@anntzer@tacaswell@astrofrog@jklymak@pllim

[8]ページ先頭

©2009-2025 Movatter.jp