You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Hide contour linestroke on pyplot.contourf to get only fills #9574
if you save a contourf in pdf format, you see the thin white line contours.
This is well described in this question and I think the fix makes sense too. https://stackoverflow.com/a/32911283
is it possible to implement it with an extra argument in contourf?
thanks!
The problem is that it is not a real solution--it fails if alpha is not 1--and it actually distorts the plot because the finite-width edges extend the color beyond the true boundaries of each patch. The problems can be minimized by carefully fiddling with the patch collection line width, but it is impossible to pick a single value for line width that will always be optimal. It depends on the renderer that is ultimately used, and the dpi used at the time by that renderer.
This is an interesting one. I think as @efiring has alluded to in the past, this is an issue with PDF renderers. And 100 appologies if this has been covered before...
works. and I hope we can agree that a linewidth of 0.0000000001 isn't distorting anything. And I guess I don't know what the issue is w/ alpha, but....
In the eps we have
0.000 setlinewidth
1 setlinejoin
0 setlinecap
[] 0 setdash
0.000 0.306 0.129 setrgbcolor
gsave
357.1 266.1 57.6 38.02 clipbox
59.394573 38.016 m
61.189146 38.016 l
62.983719 38.016 l
64.778291 38.016 l
...ETC
cl
gsave
fill
grestore
stroke
grestore
And the ghost lines disappear (at least in my pdf viewers).
If we don't put the fake linewidth in, then the
stroke
grestore
lines in test.eps disappear...
Note that 0.000 setlinewidth has been called for the paths. Unfortunately, with matplotlib if we set c.set_linewidth(0.0) the stroke never gets called (I guess someone was optimizing).
Sooooo, not an expert on eps/pdf at all, but I think most pdf viewers want the stroke in there, even if linewidth=0.
Yes, we decided long ago that we wanted zero-linewidth to mean "don't stroke", instead of the postscript meaning of "stroke with the minimum linewidth (presumably one dot)".
This whole problem keeps coming up, every year or two, and more than once I have conducted tests to see if I could find a general solution. I think the most recent conversation was in connection with hexbin; someone who is good at github searching might want to find this, and possibly other issues where it has been discussed. On those previous occasions I have found using a tiny linewidth to not work uniformly. In a quick test just now, it appears to work for pdf and eps using evince or firefox as the viewer, but not for svg on firefox. More testing is in order. If it turns out to commonly work for pdf, and to do no major damage in the cases where it doesn't help, then I would be happy to make it standard. I'm not sure what would be the proper way to implement it, though--by changing the behavior of stroke with zero linewidth inside the backend, or by setting the default linewidth.
The problem with alpha <1 occurs when stroking the outline causes overlaps; they then show up as dark boundaries.
#5151 certainly is caused by the same issue. #7500, #7185 wrt hexbin and edgecolor='face'.
I think a good solution is to let contourf have edgecolors and linewidths kwargs just like contour and default edgecolors to face and allow linewidths=0 to happen, and suggest making small line widths if the exact contour position is crucial? That leaves it largely in the users hands to get something good.
hexbin: edgecolor='face' is default, but "None" can be specified.
pcolormesh: edgecolor=None where None means default to rcParams. 'face' and 'None' are possible. However, I don't see what rcParams is being referred to in the docs! So, the pcolormesh issue is fixable, though not by default as I can see...
contourf doesn't allow edgecolor or linewidths. I think it should at least allow edgecolors like pcolormesh does, and I think it should default to 'face', but allow 'None'. I don't see how pcolormesh sets the linewidth, but looking at an eps, it appears to be set to 0.1
It's not, strictly speaking, because the edges of the polygons are not matching. It's because the renderer only sees one patch at a time. When it antialiases the pixels on the edges of the polygon, the only thing it can do is assign partial occupancy by using partial transparency. When the renderer sees the second polygon, it will do the same. So an edge pixel which was supposed to have, say, left 50% red and right 50% green gets rendered as (white background) (50% transparency red) (50% transparency green), and thus the white "leaks through". This is known as a conflation artefact (I think due to the "conflation" between coverage and alpha).
AFAIK the only way to solve this is to emit your polygons as mesh objects, so that the renderer actually "knows" that the two edges are supposed to be the same (and even then you need a renderer that actually knows how to use that information). See also #7841.
@efiring I guess that setting the default linewidth to a tiny positive value (np.nexafter(0, 1) is probably the easiest). If I understand correctly, any nonzero value will tell postscript to draw an as-thin-as-possible line. On raster backends, such tiny lines will just not appear at all due, well, to rasterization (it may cause a bit of performance drop, or perhaps not -- perhaps worth checking).
Activity
efiring commentedon Oct 25, 2017
The problem is that it is not a real solution--it fails if alpha is not 1--and it actually distorts the plot because the finite-width edges extend the color beyond the true boundaries of each patch. The problems can be minimized by carefully fiddling with the patch collection line width, but it is impossible to pick a single value for line width that will always be optimal. It depends on the renderer that is ultimately used, and the dpi used at the time by that renderer.
bderembl commentedon Oct 25, 2017
I see. in my experience, the distortion is very minimal though.
I know matlab handles this with the
shading flatoptionjklymak commentedon Oct 25, 2017
This is an interesting one. I think as @efiring has alluded to in the past, this is an issue with PDF renderers. And 100 appologies if this has been covered before...
But....
works. and I hope we can agree that a linewidth of 0.0000000001 isn't distorting anything. And I guess I don't know what the issue is w/ alpha, but....
In the eps we have
And the ghost lines disappear (at least in my pdf viewers).
If we don't put the fake linewidth in, then the
lines in
test.epsdisappear...Note that
0.000 setlinewidthhas been called for the paths. Unfortunately, with matplotlib if we setc.set_linewidth(0.0)thestrokenever gets called (I guess someone was optimizing).Sooooo, not an expert on eps/pdf at all, but I think most pdf viewers want the stroke in there, even if linewidth=0.
efiring commentedon Oct 25, 2017
Yes, we decided long ago that we wanted zero-linewidth to mean "don't stroke", instead of the postscript meaning of "stroke with the minimum linewidth (presumably one dot)".
This whole problem keeps coming up, every year or two, and more than once I have conducted tests to see if I could find a general solution. I think the most recent conversation was in connection with hexbin; someone who is good at github searching might want to find this, and possibly other issues where it has been discussed. On those previous occasions I have found using a tiny linewidth to not work uniformly. In a quick test just now, it appears to work for pdf and eps using evince or firefox as the viewer, but not for svg on firefox. More testing is in order. If it turns out to commonly work for pdf, and to do no major damage in the cases where it doesn't help, then I would be happy to make it standard. I'm not sure what would be the proper way to implement it, though--by changing the behavior of stroke with zero linewidth inside the backend, or by setting the default linewidth.
The problem with alpha <1 occurs when stroking the outline causes overlaps; they then show up as dark boundaries.
jklymak commentedon Oct 26, 2017
#5151 certainly is caused by the same issue.
#7500, #7185 wrt hexbin and
edgecolor='face'.I think a good solution is to let
contourfhaveedgecolorsandlinewidthskwargs just likecontourand defaultedgecolorstofaceand allowlinewidths=0to happen, and suggest making small line widths if the exact contour position is crucial? That leaves it largely in the users hands to get something good.jklymak commentedon Oct 26, 2017
OK, a few notes which I'm sure other folks already know:
pcolormeshhas this problem (of course)jklymak commentedon Oct 26, 2017
Right now:
hexbin:edgecolor='face'is default, but"None"can be specified.pcolormesh:edgecolor=NonewhereNonemeans default to rcParams.'face'and'None'are possible. However, I don't see what rcParams is being referred to in the docs! So, thepcolormeshissue is fixable, though not by default as I can see...contourfdoesn't allowedgecolororlinewidths. I think it should at least allowedgecolorslikepcolormeshdoes, and I think it should default to'face', but allow'None'. I don't see howpcolormeshsets the linewidth, but looking at an eps, it appears to be set to0.1anntzer commentedon Oct 26, 2017
This is a fairly difficult to solve problem in general. See e.g. https://computergraphics.stackexchange.com/questions/1824/what-is-illustrators-vector-rasterization-process.
It's not, strictly speaking, because the edges of the polygons are not matching. It's because the renderer only sees one patch at a time. When it antialiases the pixels on the edges of the polygon, the only thing it can do is assign partial occupancy by using partial transparency. When the renderer sees the second polygon, it will do the same. So an edge pixel which was supposed to have, say, left 50% red and right 50% green gets rendered as (white background) (50% transparency red) (50% transparency green), and thus the white "leaks through". This is known as a conflation artefact (I think due to the "conflation" between coverage and alpha).
AFAIK the only way to solve this is to emit your polygons as mesh objects, so that the renderer actually "knows" that the two edges are supposed to be the same (and even then you need a renderer that actually knows how to use that information). See also #7841.
jklymak commentedon Oct 26, 2017
Cool! Given that, I still think we should allow a line to be added!
anntzer commentedon Oct 26, 2017
@efiring I guess that setting the default linewidth to a tiny positive value (np.nexafter(0, 1) is probably the easiest). If I understand correctly, any nonzero value will tell postscript to draw an as-thin-as-possible line. On raster backends, such tiny lines will just not appear at all due, well, to rasterization (it may cause a bit of performance drop, or perhaps not -- perhaps worth checking).
jklymak commentedon Oct 26, 2017
You can also see https://github.com/jklymak/contourfIssues/blob/master/Readme.rst where I try to work through this.
Note it is totally a viewer issue. If you turn anti-aliasing if images off you don’t see these lines in the PDF.
QuLogic commentedon Mar 4, 2023
Closing as a duplicate of #1188.