0

I don't understand why the following saving as PDF is different from PNG. The minimal example is:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.patches as mpatches

def gradient_fill_rect(xy, dx,dy, fill_color=None, ax=None, speed=10 ,**kwargs):
    if ax is None:
        ax = plt.gca()
    x,y=xy
    line, = ax.plot(x, y,color='#00000000')
    if fill_color is None:
        fill_color = line.get_color()

    zorder = line.get_zorder()
    alpha = line.get_alpha()
    alpha = 1.0 if alpha is None else alpha

    z = np.empty((50, 50, 4), dtype=float)
    rgb = mcolors.colorConverter.to_rgb(fill_color)
    z[:,:,:3] = rgb
    xc=x+dx/2
    yc=y+dy/2
    XX,YY=np.meshgrid(np.linspace(x,x+dx),np.linspace(y,y+dy))
    
    z[:,:,-1]=np.exp(-(((XX-xc)/dx)**2+((YY-yc)/dy)**2)*speed)
    xmin, xmax, ymin, ymax = x,x+dx,y,y+dy
    im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
                   origin='lower', zorder=zorder)

    clip_path = mpatches.FancyBboxPatch([x,y],dx,dy,facecolor='none', edgecolor='none',**kwargs)
    ax.add_patch(clip_path)
    im.set_clip_path(clip_path)
    return line, im

fig,ax=plt.subplots()
gradient_fill_rect([0., 0.2], 0.4,.5, 'y', ax=None, speed=2,boxstyle=mpatches.BoxStyle("Round", pad=0,rounding_size=0.2))
gradient_fill_rect([0.5, 0.2], 0.4,.5, 'y', ax=None, speed=2,boxstyle=mpatches.BoxStyle("Round", pad=0,rounding_size=0.2))
ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax.text(.4,.4,'text')
fig.savefig('t.pdf',dpi=1000)

First, if I export it to PNG fig.savefig('t.png',dpi=1000), which is correct, it looks like PNG

But if I export it to PDF fig.savefig('t.pdf',dpi=1000), im.set_clip_path seems to take no effect. The snapshot is like this: enter image description here

Someone mentioned ax.set_rasterized(True) to rasterized. It forces PDF to rasterize, however, it also rasterizes the text, which I want it to keep vectorized.

Jake Pan
  • 262
  • 1
  • 8
  • have you tried `dpi=fig.dpi` as in `fig.savefig('t.pdf',dpi=fig.dpi)` Please see: https://stackoverflow.com/questions/7906365/matplotlib-savefig-plots-different-from-show – David Erickson Dec 20 '20 at 04:00
  • Yes I did, and it doesn't work. I don't think there is a difference between `dpi=1000` and `dpi=fig.dpi` – Jake Pan Dec 20 '20 at 05:29

1 Answers1

1

Per default, all images are combined into a single composite image before saving a figure as a vector graphics file like pdf (see matplotlib PR 4061). With multiple images you may want to switch this off:

with plt.rc_context({'image.composite_image': False}):
    fig.savefig('t.pdf',dpi=1000)

(If you have just one gradient filled rect, it'll work correctly with the standard setting of True. I'm afraid I don't know the exact reason for this, it's obviously linked to multiple clipping paths in the plot.)

Stef
  • 28,728
  • 2
  • 24
  • 52