Snap markers to subpixels instead of whole ones - #32108
Conversation
There was a problem hiding this comment.
mplcairo special-cases the pixel marker; I have not checked how that turns out or whether that is necessary.
There was a problem hiding this comment.
IIRC the idea is that not snapping the pixel marker results in it being smeared across two pixels, whereas it would otherwise look sharp (exactly one pixel filled) on a raster output.
| auto marker_path_snapped = PathSnapper{ | ||
| marker_path_nan_removed, | ||
| gc.snap_mode, marker_path.total_vertices(), | ||
| points_to_pixels(gc.linewidth)}; |
There was a problem hiding this comment.
I'm not 100% certain we should be snapping here for each of the cached subpixel markers. It affects a lot more test images if we drop this though.
There was a problem hiding this comment.
From a quick look mplcairo disables snapping when generating subpixel markers, which still makes sense to me? (Actually, if you snap, I don't see how you can benefit from subpixel positioning.)
Maybe the issue with test images is with ticks, which are effectively markers and should indeed be drawn snapped? Can that be fixed by explicitly forcing snapping on them? (I didn't re-check snap control semantics, but maybe(?) it makes sense that if snapping is requested on the edges of a Line2D, then it is also enabled on the markers at its vertices?)
|
What is between us and marking this ready for review? |
|
This certainly works well for circles, which do not have special directional edges. We should check how this looks for squares: Do subpixel interpolated edges give the impression of “in between position” or just “blurry”? |
The main issue is this one. It looks like if we disable snapping on the cached markers, we end up with ~450 test failures, though they are mostly due to ticks being 1 pixel shorter. |
|
Can we special-case TICKDOWN / TICKUP markers so that they keep their old behavior? IMHO mid-term, the implementation of ticks via Line2D with specific markers should become an implementation detail. But |
|
In mplcairo ticks are not drawn with stamping at all but by drawing them one at a time, which IIRC is indeed needed to make them sharp and not blurry. Actually this is not an explicit switch but just the consequence of other choices: the size of the pattern cache (which is pre-populated prior to sampling) is normally between |
We cache the marker for performance, but this causes it to look very pixel-grid aligned, especially if there are multiple in a regular pattern, or they are animated. Apply the same algorithm as mplcairo noted by @anntzer in matplotlib#7233, specifically, render and cache the marker in *n_subdiv* levels in each direction, and pick the closest one for each marker. Fixes matplotlib#7233
|
I've rebased and added the image changes for people to look at. I don't quite think we should keep them all, but I haven't looked into any additional special-casing besides the pixel marker (which needs to be optimized, probably.) There also seems to be some
Ah, I don't think I noticed that and didn't implement it. The downside of doing that is it then depends on how we draw ticks, and there is of course some hope that we can refactor enough to draw them as a collection in the future.
I thought of this one originally, but I'm not sure how easy it is, since the Agg rasterizer is re-used for both marker cache and the actual drawing, so we'd have to do some careful tracking of state if we switch between them. |
|
Looking at the test failure in |
|
The antialiasing looks really bad with squares in the animation, how does mplcairo do with it? |
|
Ah, indeed the moire goes away when the video is blown up. But it's still a bit weird, the moire doesn't show up even downscaled with mplcairo? |








PR summary
We cache the marker for performance, but this causes it to look very pixel-grid aligned, especially if there are multiple in a regular pattern, or they are animated.
Apply the same algorithm as mplcairo noted by @anntzer in #7233, specifically, render and cache the marker in n_subdiv levels in each direction, and pick the closest one for each marker.
Fixes #7233
AI Disclosure
None
PR checklist