Altering the resolution of an embeded raster image

I’m attempting to save a plot generated using imshow, using the pgf backend. In doing so, I seem to have no control over the DPI of the rasterized part of the plot (in this case, a PNG), and the dpi keyword to savefig seems to have no effect.

I found a similar post from before:

I tried this with the svg backend too, and it has the same problem.

I cannot reproduce your issue:

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
ax.imshow(np.random.randn(600, 600), rasterized=True)

for dpi in [30, 100, 400, 600]:
    fig.savefig(f'Boo{dpi}.svg', dpi=dpi)

shows varying resolution of the svg in accordance with the dpi kwarg.

I found the problem! It is that i had not passed rasterized=True to imshow. When I do that, the dpi keyword has an effect. Thanks a lot!

But this seems like a bug. If it rasterises a part of the plot anyway, it should accept a custom DPI. Should it not?

On my machine, you don’t need the rasterized keyword, the following also appears to work…

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
ax.imshow(np.random.randn(600, 600))

for dpi in [30, 100, 400, 600]:
    fig.savefig(f'/home/bbeltr1/Downloads/Boo{dpi}.svg', dpi=dpi)

But that is the only change I made for it to work. So then I’m not sure.

@jklymak likely knows better than me why that argument is needed, but if I’m not missing anything silly, there must be something else going on.

But to test that everything is working as it should, you can set a breakpoint in backends/, then run the plt.savefig command. It should pause execution right as it’s about to write out the image to the file.

If you go up a level, that should put you in image._ImageBase.draw_image, and the variable renderer should be a “MixedModeRenderer” with the requested DPI.

EDIT: just realized that since I’m on master, giving you line numbers may not be the smartest idea. The function you want to break at to check what is actually being saved to the file is backends.backend_svg.RendererSVG.draw_image.

Of course, a minimal example of the code you’re actually running is probably the fastest way to diagnose the issue @physkets, if that’s possible.

This may not be the most minimal, but this produces exactly the effect I’m talking about:

from matplotlib import use
from matplotlib.pyplot import get_cmap, figure, gca, title, savefig
from matplotlib.colors import SymLogNorm
from numpy import random


FIG = figure()
AXES = gca()
IM = AXES.imshow(random.randn(50, 50), interpolation='none',
                 norm=SymLogNorm(base=10, linthresh=1))

title("Testing DPI of the embedded raster image",

savefig('check.svg', bbox_inches='tight',
        dpi=600, transparent=True)

Now if you add a rasterized=True to the imshow, it accepts the argument of the dpi keyword and produces a nicer picture.

No you don’t need the rasterized kwarg.

This is a bug in the svg interpolation='none' behaviour, where it does interpolation by default. It should be fixed by To work around, try settinginterpolation='hanning'.

As a workaround, setting rasterized=True works, and I’m okay with that. Also, interpolation='none' is what is most appropriate for me. I need clear, crisp boxes of colour.

This doesn’t happen just with the svg backend. It also happens with the pgf backend. Does the PR fix that too?

To be clear, the issue with svg is that the viewer was doing the up-sampling and the fix was to add flags to the SVG to control that. Presumably we would need a mirrored change in pgf if the viewers are trying to up-sample the images with interpolation='none'.

In the case of pgf, the output of imshow is a .pgf file that contains all the text as well as placement information and PNG images of any raster components. Can the upsampling of PNG images also be controlled like for SVG? (In my case the viewer is is a PDF reader because I compile the PGF into a PDF using a LaTeX program)