Skip to content

Saving as a pdf ignores set_clip_path when there is more than one of them. #18499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
FlorentinJ opened this issue Sep 16, 2020 · 3 comments · Fixed by #19375
Closed

Saving as a pdf ignores set_clip_path when there is more than one of them. #18499

FlorentinJ opened this issue Sep 16, 2020 · 3 comments · Fixed by #19375
Milestone

Comments

@FlorentinJ
Copy link

I am trying to plot some curves with variable width and opacity. To do this I first plot a background image with the correct color, which I then clip using patches.

It works perfectlty, except when I try to export the result as a PDF, where all clipping information is lost if I try to draw more than one curve. There is no problem when exporting to PNG or with the inline viewer.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch

fig, ax = plt.subplots()
X = np.linspace(0, 1, 100)

# green curve, rgba = (0, 1, 0, x)
im1 = ax.imshow([np.array((np.zeros_like(X), np.ones_like(X), np.zeros_like(X), X)).transpose()],
                 aspect=0.5, extent=[0, 1, 0, 1.5])
paths1 = ax.fill_between(X, X**2, X**2+0.5, facecolor='none', lw=2)
patch1 = PathPatch(paths1._paths[0], visible=False)
ax.add_patch(patch1)
im1.set_clip_path(patch1)

# red curve, rgba = (1, 0, 0, x)
im2 = ax.imshow([np.array((np.ones_like(X), np.zeros_like(X), np.zeros_like(X), X)).transpose()],
                 aspect=0.5, extent=[0, 1, 0, 1.5])
paths2 = ax.fill_between(X, 1.5-X**2, 1-X**2, facecolor='none', lw=2)
patch2 = PathPatch(paths2._paths[0], visible=False)
ax.add_patch(patch2)
im2.set_clip_path(patch2)

fig.savefig('test.pdf')
fig.savefig('test.png')

PNG output
image

PDF output
image

If I only try to plot a single curve, then everything works as expected.

Is this linked to a known issue?
Does anyone have a workaround?

Many thanks.

Matplotlib version

  • Operating system: Windows 10 or Cygwin (first discovered on a SageMath install, but reproduced in a pure python environment)
  • Matplotlib version: 3.3.1 and 2.2.4
  • Matplotlib backend: module://ipykernel.pylab.backend_inline
  • Python version: 3.8.5 and 3.7.3
  • Jupyter version (if applicable): jupyterlab 2.2.6 and 2.2.0
@jklymak jklymak added this to the v3.4.0 milestone Sep 16, 2020
@jklymak
Copy link
Member

jklymak commented Sep 16, 2020

I agree this is a bug, at least on Preview as well. Someone would have to dig into the pdf spec and figure out why this breaks. BTW, its worth noting that this works fine with just one curve, so Artist clipping works for PDF, but two clips are not allowed.

@anntzer
Copy link
Contributor

anntzer commented Sep 16, 2020

This actually affects all vector backends, and comes from image._draw_list_compositing_images, which completely fails to take image clipping into account (it only accounts for clipping of the parent axes/figure). My guess is that the simple solution is to just disable precompositing whenever custom clips are sets on the images, something along the lines of not_composite = ... or any(artist.get_clip_rectangle() is not None or artist.get_clip_path() is not None for artist in artists).

@Jhsmit
Copy link

Jhsmit commented Feb 3, 2021

After a few futile attempt to install matplotlib from source to try the PR I found a stackoverflow post with a solution for my issue:

plt.rcParams["image.composite_image"] = False

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants