You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
WCSAxes containing rasterized polygons displays axes frame in wrong position on figure unless grid is shown #12568
I am trying to create a WCSAxes plot that has a huge number of polygon artists on it. I want to set the polygons to be rasterized so that the image loads quickly in PDF viewers. Much to my surprise, I find that adding even a single rasterized polygon to a WCSAxes plot causes the axes frame to be drawn in the wrong place on the figure.
Even more puzzling, adding a grid to the axes causes the frame to be drawn in the correct position!
I notice that as I change the rcparam figure.dpi, the position and size of the incorrectly-drawn frame changes.
Expected behavior
This is what the output looks like when there is a grid present. Observe that the frame is drawn correctly.
Actual behavior
This is what the output looks like when there is no grid present. Observe that the frame is drawn with the wrong position and size on the figure, well offset from the axes themselves.
Do you have a high-DPI screen (including a retina screen Mac)? This looks suspiciously like HiDPI issues we've been seeing recently (matplotlib/matplotlib#21931). If you use matplotlib < 3.5 is it still an issue?
I think it's a Matplotlib bug? The issue seems to be a mismatch between the DPI used to layout PDF files (72) and the DPI of a figure (100 by default) that is used to produce rasterized elements. For now a workaround is to do fig.savefig(f'grid-{grid}.pdf', dpi=72), and I'll do some more digging in Matplotlib.
Some more digging: I think the issue is that various WCSAxes have their 'pixel' attributes set before draw time, but this is a Bad Idea because the pixel coordinates of a given artist depend on the figure DPI, which is only set in stone at draw time. Unfortunately that means it's an astropy issue 😞 . Will update when I've got something more.
It looks like there might actually be both astropy and Matplotlib bugs 🙈 . The astropy fix is in #12621, and I'll report back if/once I find a Matplotlib fix.
With #12621 both spines, all ticks, and the y-axis labels in this example are drawn correctly, but not the x-axis labels because for some reason they're still being drawn with the wrong DPI...
I really got hooked by the rabbit hole here! There is not a Matplotlib bug (phew), but there is another WCSAxes bug that needs fixing. The solution is that all the custom draw() methods in WCSAxes need a @matplotlib.artist.allow_rasterization decorator to allow the correct DPI to be set when each individual component is drawn.
This is however going to need some technically breaking API changes to draw() methods in WCSAxes, as the MPL decorator only works with the signature draw(self, renderer), whereas some WCSAxes methods have more arguments which will need to be removed. So I think that the way forward here is:
Setting the figure DPI to 72 hides this issue. This forces the DPI of rasterized elements to be 72 DPI.
Hopefully this will get fixed in the next major release of astropy, allowing the DPI of the rasterized elements to be something other than 72
Sorry for not being clear - setting to 72 DPI is the only case where this isn't currently an issue. I'm working towards solving the bugs that will allow you to use much higher resolutions than 72 DPI.
Well here's the full fix: main...dstansby:wcsaxes-rasterize - it was certainly a fun rabbit hole! I created another issue to track all of these changes, which is #12672. My plan is to tackle several PRs and associated reviews one at a time instead of trying to get a large PR merged.
Activity
dstansby commentedon Dec 19, 2021
Do you have a high-DPI screen (including a retina screen Mac)? This looks suspiciously like HiDPI issues we've been seeing recently (matplotlib/matplotlib#21931). If you use
matplotlib < 3.5is it still an issue?lpsinger commentedon Dec 20, 2021
I am using a Mac with a Retina display. However this is still broken on matplotlib 3.4.3.
dstansby commentedon Dec 20, 2021
I can reproduce this, and it's not present using matplotlib 3.3.4. Just bisecting this to a Matplotlib change now...
dstansby commentedon Dec 20, 2021
Bisects to matplotlib/matplotlib@b6a2739 from matplotlib/matplotlib#17159, so it's not a HiDPI issue, but (as said in the original report) related to Matplotlib raster output.
pllim commentedon Dec 21, 2021
So... Is this a matplotlib bug, or something we have to fix here?
dstansby commentedon Dec 21, 2021
I think it's a Matplotlib bug? The issue seems to be a mismatch between the DPI used to layout PDF files (72) and the DPI of a figure (100 by default) that is used to produce rasterized elements. For now a workaround is to do
fig.savefig(f'grid-{grid}.pdf', dpi=72), and I'll do some more digging in Matplotlib.dstansby commentedon Dec 21, 2021
Some more digging: I think the issue is that various WCSAxes have their 'pixel' attributes set before draw time, but this is a Bad Idea because the pixel coordinates of a given artist depend on the figure DPI, which is only set in stone at draw time. Unfortunately that means it's an astropy issue 😞 . Will update when I've got something more.
dstansby commentedon Dec 22, 2021
It looks like there might actually be both astropy and Matplotlib bugs 🙈 . The astropy fix is in #12621, and I'll report back if/once I find a Matplotlib fix.
With #12621 both spines, all ticks, and the y-axis labels in this example are drawn correctly, but not the x-axis labels because for some reason they're still being drawn with the wrong DPI...
dstansby commentedon Dec 22, 2021
I really got hooked by the rabbit hole here! There is not a Matplotlib bug (phew), but there is another WCSAxes bug that needs fixing. The solution is that all the custom
draw()methods inWCSAxesneed a@matplotlib.artist.allow_rasterizationdecorator to allow the correct DPI to be set when each individual component is drawn.This is however going to need some technically breaking API changes to
draw()methods in WCSAxes, as the MPL decorator only works with the signaturedraw(self, renderer), whereas some WCSAxes methods have more arguments which will need to be removed. So I think that the way forward here is:pllim commentedon Dec 22, 2021
I think your proposal is very reasonable. Thanks for investigating!
What do you think, @astrofrog , @Cadair , or @larrybradley ?
lpsinger commentedon Dec 23, 2021
I, for one, require rasterized elements at much higher resolutions than 72 DPI. We're not talking of hard-coding that in wcsaxes, are we?
dstansby commentedon Dec 23, 2021
Sorry for not being clear - setting to 72 DPI is the only case where this isn't currently an issue. I'm working towards solving the bugs that will allow you to use much higher resolutions than 72 DPI.
dstansby commentedon Dec 30, 2021
Well here's the full fix: main...dstansby:wcsaxes-rasterize - it was certainly a fun rabbit hole! I created another issue to track all of these changes, which is #12672. My plan is to tackle several PRs and associated reviews one at a time instead of trying to get a large PR merged.
dstansby commentedon Jan 10, 2024
This is fixed in the latest version of astropy, so can be closed 🥳