Skip to content

Images are clipped incorrectly with custom clip path #15952

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
QuLogic opened this issue Dec 16, 2019 · 8 comments · Fixed by #15970
Closed

Images are clipped incorrectly with custom clip path #15952

QuLogic opened this issue Dec 16, 2019 · 8 comments · Fixed by #15970
Labels
backend: agg status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action topic: images

Comments

@QuLogic
Copy link
Member

QuLogic commented Dec 16, 2019

Bug report

Bug summary

This is related to #15946, but for images. When setting a custom clip path, the image is cropped slightly incorrectly.

Code for reproduction

(Note, in lieu of subclassing Axes and Subplot, I've just overwritten the Axes.patch using the properties that it should have).

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as mpatches

data = [[1, 1], [0, 1]]

fig, ax = plt.subplots(1, 3, figsize=(6, 2), sharex=True, sharey=True)
ax[0].set_xlim(0, 2)
ax[0].set_ylim(0, 2)
ax[0].set_title('Default patch')

ax[2].patch = mpatches.PathPatch(
    Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
    facecolor=plt.rcParams['axes.facecolor'],
    edgecolor='None',
    linewidth=0,
    snap=False,
    transform=ax[2].transAxes)
ax[2].patch.set_figure(fig)
ax[2].set_title('Custom patch')

img = []
for a in ax:
    img.append(a.imshow(data, extent=(0, 2, 0, 2), vmin=-10))

img[1].set_clip_box(None)
img[1].set_clip_path(
    Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
    ax[1].transAxes)
ax[1].set_title('Custom clip path')

plt.show()

Actual outcome

Figure_1

If you check the antialiasing along the top spine, the first Axes is grey (f1f1f1), but the second and third are slightly yellow (f0e7a0). Note, this seems to be figure size and/or DPI dependent.

Expected outcome

All images should be cropped in the same way, and there should not be a difference in edges along the top of the Axes.

Matplotlib version

  • Operating system: Fedora 30
  • Matplotlib version: 9d00ca8
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg (probably just Agg though)
  • Python version: 3.6.3
@anntzer
Copy link
Contributor

anntzer commented Dec 17, 2019

At the risk of sounding like a broken record... looks like this doesn't happen with mplcairo? can you confirm?

@QuLogic
Copy link
Member Author

QuLogic commented Dec 18, 2019

I believe you are correct. Also, I think this affects all artists, not just images, but it really depends on how the artist interacts with the border.

@dopplershift
Copy link
Contributor

@anntzer coughhumblebragcough 😉

@anntzer
Copy link
Contributor

anntzer commented Dec 18, 2019

hehe...

@QuLogic
Copy link
Member Author

QuLogic commented Dec 22, 2019

As noted in #15970, it was not a full fix, but I couldn't figure out a way to reproduce in plain Matplotlib. Now, I think I have something that still shows the issue. Basically, because the figure background defaults to white, you don't see it, but by changing the background to some other colour, you can see that the image is clipped a bit differently using a clip path over a clip box:

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as mpatches
from matplotlib.testing import setup as mpl_setup


plt.rcParams['savefig.facecolor'] = 'b'

data = [[1, 1], [0, 1]]

fig, ax = plt.subplots(1, 4, figsize=(8, 2), sharex=True, sharey=True,
                       facecolor='b')
ax[0].set_xlim(0, 2)
ax[0].set_ylim(0, 2)
ax[0].set_title('Default patch')

for a in ax[2:]:
    a.patch = mpatches.PathPatch(
        Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
        facecolor=plt.rcParams['axes.facecolor'],
        edgecolor='None',
        linewidth=0,
        snap=False,
        transform=a.transAxes)
    a.patch.set_figure(fig)
    a.set_title('Custom patch')

img = []
for a in ax[:3]:
    img.append(a.imshow(data, extent=(0, 2, 0, 2), vmin=-10))
    for s in a.spines.values():
        s.set_bounds(0, 1.25)

img[1].set_clip_box(None)
img[1].set_clip_path(
    Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
    ax[1].transAxes)
ax[1].set_title('Custom clip path')

ax[3].set_title('No image, clip path')
ax[3].set_aspect('equal')
for s in ax[3].spines.values():
    s.set_bounds(0, 1.25)

plt.show()

Figure_1

The first Axes is normal and while the clip position is a bit inconsistent with the spines, they all fall within or under the spine (which being opaque black, covers that up). In the second Axes, where the clip path is set on the image directly, the top extends one pixel extra and the right is clipped a little early (maybe 0.5 pixel.) In the third Axes, the path is set as the background patch, and the image is clipped slightly differently on all four edges. I suspect this is because the patch itself is clipped differently, which is why I put just a custom patch on the fourth Axes and no image. Comparing three and four, that seems to be the case for all sides except the right.

So while the patch changing position a bit might explain a few edge differences, it doesn't explain the second Axes, and I'm going to reopen this.

@greglucas
Copy link
Contributor

I was just looking into some snapping related problems and decided to test your cases out here. It looks like the second axes (of the most recent example) is now fixed? Here is the result I get with master:
Figure_1
There are still issues with aliasing in the third and fourth axes in that image though.

If you remove the snap=False from the patch, things look pretty good to me I think. Below is the image with snapping on by default.
Figure_1_snapTrue

@QuLogic
Copy link
Member Author

QuLogic commented Jul 29, 2020

Indeed, it is snapping that seems to do this. I am mostly worried about the last case though, as it's the (likely, not tried this change on it yet) problem that manifests in Cartopy.

@github-actions
Copy link

github-actions bot commented Jul 3, 2023

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Jul 3, 2023
@github-actions github-actions bot added the status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. label Aug 4, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Aug 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend: agg status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action topic: images
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants