Reputation: 9388
I have plots that I annotate using images:
def add_image(axe, filename, position, zoom):
img = plt.imread(filename)
off_img = matplotlib.offsetbox.OffsetImage(img, zoom = zoom, resample = False)
art = matplotlib.offsetbox.AnnotationBbox(off_img, position, xybox = (0, 0),
xycoords = axe.transAxes, boxcoords = "offset points", frameon = False)
axe.add_artist(art)
Then I save the figure to some pdf file, say fig.pdf
. I expect the exact original image to be embedded in the resulting pdf, without resampling. However, the image is resampled according to the dpi
parameter of savefig()
.
How can I force matplotlib to NOT resample the image (there is no point in doing that for a vector output anyway) ?
For more details, here is a simple example, using this image as image.png
:
import numpy as np
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt
def add_image(axe, filename, position, zoom):
img = plt.imread(filename)
off_img = matplotlib.offsetbox.OffsetImage(img, zoom = zoom, resample = False)
art = matplotlib.offsetbox.AnnotationBbox(off_img, position, xybox = (0, 0),
xycoords = axe.transAxes, boxcoords = "offset points", frameon = False)
axe.add_artist(art)
# ==========
fig = plt.figure()
axe = plt.axes()
fig.set_size_inches(3, 1.5)
axe.plot(np.arange(10), np.arange(10))
add_image(axe, "image.png", position = (0.2, 0.7), zoom = 0.07)
fig.savefig("temp.pdf", bbox_inches = "tight", pad_inches = 0)
EDIT: There is a bug/feature issue for this question
Upvotes: 1
Views: 292
Reputation: 339610
Just a quick summary of the discussion in https://github.com/matplotlib/matplotlib/issues/16268:
Passing the image through without resampling is indeed a desireable feature, mostly because for vector output, it should really be up to the renderer (e.g. pdf viewer, printer etc.) to determine the resolution.
The fact that matplotlib currently does not allow for this is mostly an oversight.
A workaround solution (a quick hack) is to add the following code before producing the figure:
from matplotlib.backends.backend_mixed import MixedModeRenderer
def _check_unsampled_image(self, renderer):
if isinstance(renderer, MixedModeRenderer):
return True
else:
return False
matplotlib.image.BboxImage._check_unsampled_image = _check_unsampled_image
This is not meant to be used in production code though, and a more robust solution needs to be implemented in a future matplotlib version. Contributions are welcome.
Upvotes: 2