mplcairo icon indicating copy to clipboard operation
mplcairo copied to clipboard

workaround for low dpi when rasterizing (pcolormesh saved as pdf)

Open pharshalp opened this issue 4 years ago • 5 comments

https://github.com/matplotlib/mplcairo/blob/master/ISSUES.rst mentions that there is an issue with "Invalid dpi manipulations in vector output". Is there an easy workaround for this?

Also, thanks for developing this backend! I don't understand all the details of how fonts are handled internally but mplcairo seems to be giving me better looking text!

pharshalp avatar Jan 15 '20 22:01 pharshalp

Are you running into this issue for a real use case? The main problem I am aware of is with using figimage() (so "per-pixel data") with pdf output (where the notion of "pixel" is not really well defined, but conventionally thought of as 72 dpi); I think there's somewhere where I may forget to switch the canvas from 100 dpi (or whatever the "nominal" resolution is) to the pdf output's 72 dpi, or where mpl does it and I do it too so it happens twice (IIRC (from very long time ago...) mpl's image.py code basically does something slightly weird to match the just as undocumented behavior of backend_pdf.py, and I gave up reverse-engineering that). To be honest it's really low on my priority list because it's quite obscure and not so easy to fix, but if you have a real use case, please describe it. The other problems mostly occur with rasterizing svgs at very low resolution, and whether that should use "nearest" interpolation or some kind of smoothing. I think there's also an issue about that on the mpl tracker.

anntzer avatar Jan 15 '20 22:01 anntzer

here is a MWE to reproduce the issue I am facing.

import numpy as np
import matplotlib.pyplot as plt

data = np.arange(25).reshape(5, 5)

for backend in ['pdf', 'module://mplcairo.base']:
    plt.switch_backend(backend)
    fig, ax = plt.subplots(figsize=(3, 2.5), constrained_layout=True)
    im = ax.pcolormesh(data)
    cbar = fig.colorbar(im)
    im.set_rasterized(True)
    cbar.solids.set_rasterized(True)
    fig.savefig(f'backend_{backend.split("//")[-1]}_dpi300.pdf', dpi=300)
    fig.savefig(f'backend_{backend.split("//")[-1]}_dpi72.pdf', dpi=72)

backend_pdf_dpi72.pdf backend_pdf_dpi300.pdf backend_mplcairo.base_dpi72.pdf backend_mplcairo.base_dpi300.pdf

Looks like mplcairo is always going for 72 dpi (and also causing issue with the rasterized image overflowing the boundaries of axes and colorbar).

I forgot to add that I am using mplcairo v0.2 installed from pypi, matplotlib v3.1.2 (conda-forge) Python 3.7.6 (conda-forge) installed on Windows 10.

pharshalp avatar Jan 15 '20 22:01 pharshalp

I think that the following line is causing the issue. I have created a PR to fix it. (My apologies in advance if I am trivializing the issue but this just feels like an inadvertent oversight).

https://github.com/matplotlib/mplcairo/blob/a54ace541fd10a07e662fa8df0efc8e1f240020c/lib/mplcairo/base.py#L245

    def _print_method(self, renderer_factory,
                      path_or_stream, *, metadata=None, dpi=72, **kwargs):
        _check_print_extra_kwargs(**kwargs)
        self.figure.set_dpi(72)   # This should be self.figure.set_dpi(dpi) 

pharshalp avatar Jan 16 '20 00:01 pharshalp

No need to apologize when you're proposing a fix :) (though it does look like the PR CI is failing -- let's continue the discussion there)

anntzer avatar Jan 16 '20 01:01 anntzer

https://github.com/matplotlib/matplotlib/issues/16268#issuecomment-576412375 may be related.

anntzer avatar Jan 20 '20 22:01 anntzer