GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — PatchCollection edges incorrect when clip path is set · Issue #15946 · matplotlib/matplotlib

PatchCollection edges incorrect when clip path is set #15946

New issue
Copy link
New issue
Copy link
Open
Open
PatchCollection edges incorrect when clip path is set#15946
Copy link
Labels
backend: aggtopic: path handling

Description

@QuLogic
QuLogic
opened on Dec 16, 2019
Issue body actions

Bug report

Bug summary

Cartopy has a mostly-superfluous GeoAxes.background_patch which I'm trying to convert to the standard Axes.patch. By default, the Axes.patch is a Rectangle, which triggers a fast-path to set a clip box instead of a clip path. However, since most map boundaries are non-square, the full clip path code is used instead. When doing so, this causes some strange artifacts.

(Un)Fortunately, it can be reproduced with plain Matplotlib below.

Code for reproduction

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


pth = Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]],
           [1, 2, 2, 2, 79])

fig, ax = plt.subplots(2, 2, sharex=True, sharey=True)
ax[0, 0].set_xlim(-1, 2)
ax[0, 0].set_ylim(-1, 2)

for a in ax[0]:
    collection = a.add_collection(
        PatchCollection([mpatches.PathPatch(pth)],
                        facecolor='C0', edgecolor='k'))

collection.set_clip_path(
    Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
    a.transAxes)

for a in ax[1]:
    patch = a.add_patch(mpatches.PathPatch(pth, facecolor='C0', edgecolor='k'))

patch.set_clip_path(
    Path([[0, 0], [1, 0], [1, 1], [0, 1], [0, 1]]),
    a.transAxes)

ax[0, 0].set_ylabel('PatchCollection')
ax[1, 0].set_ylabel('PathPatch')
ax[1, 0].set_xlabel('Default clip box')
ax[1, 1].set_xlabel('Custom clip path')

plt.savefig('test.png')

Actual outcome

In the bottom row is a plain PathPatch, and the top row is a PatchCollection containing the same PathPatch. The left column shows the default clipping (to the clip box of the Axes). The right column uses a clip path of a manually-specified 0-1 rectangle in Axes space, so it should be equivalent.

But the horizontal edges are either doubled over or the wrong width in the top-right case.

test

Expected outcome

All path edges should look the same.

Matplotlib version

  • Operating system: Fedora 30
  • Matplotlib version: 3.1.3 and master, 9d00ca8
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg (probably only the Agg bit is relevant)
  • Python version: 3.6.9 / 3.6.3

Activity

  1. QuLogic
    added
    topic: path handling
    on Dec 16, 2019
  2. QuLogic commented on Dec 16, 2019

    @QuLogic
    QuLogic
    on Dec 16, 2019
    MemberAuthor
    More actions

    Can be reproduced as far back as 1.5.3, and though mplcairo has different antialiasing, it does produce the correct result.

    It seems to have something to do with the single path optimization for Collection, which calls Renderer.draw_markers (instead of a draw_path*) and does path drawing completely differently.

  3. anntzer
    added
    backend: agg
    on Dec 16, 2019
  4. anntzer commented on Dec 16, 2019

    @anntzer
    anntzer
    on Dec 16, 2019
    Contributor
    More actions

    the builtin vector backends also seem immune, so it's agg only.

  5. QuLogic commented on Jan 7, 2020

    @QuLogic
    QuLogic
    on Jan 7, 2020
    MemberAuthor
    More actions

    So obviously, if I force set do_single_path_optimization = False, then this works correctly. But doing so would break about 48 test images. This is because there's a 0.5px shift for markers that's also translated to these paths. I'm not sure it makes sense for this to happen just because you passed one vs. two colours.

    There's an explanation of what the markers optimization is by @mdboom at #3626 (comment), though I don't really understand the benefit for things that are single paths anyway (as opposed to scatter, ticks, etc.)

  6. anntzer commented on Jan 7, 2020

    @anntzer
    anntzer
    on Jan 7, 2020
    Contributor
    More actions

    Seems reasonable to disable stamping for single paths, except that IIRC (it's been a while, though) I tried this and ticks (which are single paths for now -- they are drawn independently from one another, which as a side point is terrible performance-wise) look much better when snapped to integer pixels (basically "short" lines (i.e. ticks) look particularly bad when antialiased between two pixel rows). I guess it was pretty accidental that marker stamping helped with tick antialiasing, but heh.
    What do the broken test image diffs look like?

  7. tacaswell
    added this to the v3.3.0 milestone on Mar 14, 2020
  8. QuLogic commented on May 23, 2020

    @QuLogic
    QuLogic
    on May 23, 2020
    MemberAuthor
    More actions

    Looking at the test results for forcing do_single_path_optimization = False, the failures are most likely from single scatters that would of course also be a single path. I think to cover this case, the single path optimization should not be done if not drawing markers.

  9. QuLogic commented on May 28, 2020

    @QuLogic
    QuLogic
    on May 28, 2020
    MemberAuthor
    More actions

    I tried that out, and while it does work, it also breaks a few tests. I think those tests may be wrong, but we have to see which way we want to go there. This may take a bit more time to decide.

  10. QuLogic
    modified the milestones: v3.3.0, v3.4.0 on May 28, 2020
  11. QuLogic
    modified the milestones: v3.4.0, v3.5.0 on Jan 27, 2021
  12. QuLogic
    modified the milestones: v3.5.0, v3.6.0 on Sep 25, 2021
  13. QuLogic
    modified the milestones: v3.6.0, v3.7.0 on Aug 24, 2022
  14. ksunden
    modified the milestones: v3.7.0, v3.7.1 on Feb 14, 2023
  15. QuLogic
    modified the milestones: v3.7.1, v3.7.2 on Mar 4, 2023
  16. QuLogic
    modified the milestones: v3.7.2, v3.7.3 on Jul 5, 2023
  17. QuLogic
    modified the milestones: v3.7.3, v3.8.0 on Sep 9, 2023
  18. ksunden
    removed this from the v3.8.0 milestone on Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    backend: aggtopic: path handling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.