FIX: keep sub-pixel segments visible when snapping (#20243) by Zish19 · Pull Request #31981 · matplotlib/matplotlib · GitHub
Skip to content

FIX: keep sub-pixel segments visible when snapping (#20243)#31981

Open
Zish19 wants to merge 2 commits into
matplotlib:mainfrom
Zish19:fix/eventplot-subpixel-snapping-20243
Open

FIX: keep sub-pixel segments visible when snapping (#20243)#31981
Zish19 wants to merge 2 commits into
matplotlib:mainfrom
Zish19:fix/eventplot-subpixel-snapping-20243

Conversation

@Zish19

@Zish19 Zish19 commented Jul 2, 2026

Copy link
Copy Markdown

PR summary

Closes #20243

PathSnapper rounds every vertex to the nearest pixel. When a line segment is shorter than a pixel, both endpoints
round to the same pixel, so the segment collapses to zero length and the Agg renderer draws nothing. With eventplots
of many events, this silently dropped most of the data, see #20243.

This change tracks the previous raw/snapped vertex in PathSnapper. When a LINETO snaps onto the previous point even
though the raw segment had non-zero length, the snapped endpoint is nudged by one pixel along the segment's dominant
direction. The result is at least one full-color pixel rather than blurring the mark by disabling snapping (per the
discussion in #20243, this matches the preference for a full-color pixel over anti-aliased fuzz). Segments that
already span a pixel are untouched, so normal rendering (lines, bars, grids) is byte-for-byte unchanged.

Minimum self-contained example

import matplotlib.pyplot as plt
import numpy as np

data = [np.random.random(np.random.randint(10)) for _ in range(500)]
fig, ax = plt.subplots()
ax.eventplot(data, linelength=1)
plt.show()

Before: most rows are missing.
After: every event renders as at least one full pixel.

Verification: A regression test (test_eventplot_sub_pixel_events_not_dropped) renders 200 isolated sub-pixel event
marks and asserts they are all drawn. On the unpatched renderer 0/200 marks appear; with this change all of them do.
A separate check confirms the pixel buffers of ordinary line plots, bar charts, grids, and normal-scale eventplots
are identical before and after the change, so there is no visual regression on content that already covers a pixel.

PR checklist

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

@Zish19 Zish19 force-pushed the fix/eventplot-subpixel-snapping-20243 branch from 343a057 to 0911d67 Compare July 2, 2026 06:37
PathSnapper rounds each vertex to the nearest pixel. A line mark shorter
than one pixel then has both endpoints rounded onto the same pixel, so it
collapses to zero length and is not drawn at all. eventplot builds every
event as its own two-point segment, so plotting many closely spaced events
silently dropped most of them.

When the opening LINETO of a subpath snaps onto its MOVETO even though the
raw segment was non-degenerate, extend the endpoint by one pixel along the
segment's dominant axis so a single pixel is still drawn. Limiting this to
the first segment of a subpath leaves polygon outlines (bars, markers,
grids) snapping exactly as before.
@Zish19 Zish19 force-pushed the fix/eventplot-subpixel-snapping-20243 branch from 0911d67 to eec0fee Compare July 2, 2026 07:29
Update PathSnapper to look ahead one vertex. This ensures that only isolated zero-length segments (like those generated by eventplot) are extended to 1 pixel. This fixes unintended rendering distortion in polygons from streamplot, hist_step_filled, etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

matplotlib eventplot not shows all the binary data for big number of events

1 participant