29

In some pdf viewers such as Preview on OSX, plots made with matplotlib's pcolor have white lines (see image below). How can I get rid of them?

The source code is very simple (choose any data for x,y,z):

import matplotlib
matplotlib.use("pdf")
import matplotlib.pyplot as pl
pl.figure()
pl.pcolormesh(x,y,z,cmap="Blues",linewidth=0) 
pl.savefig("heatmap.pdf")

enter image description here

Taku
  • 31,927
  • 11
  • 74
  • 85
hanno
  • 6,401
  • 8
  • 48
  • 80
  • 3
    This is because `pcolormesh` actually draws individual rectangles, and some pdf viewers render them differently than others. Both as a workaround and because it's more efficient, it's better to use `imshow` in this case. For example, in your case: `plt.imshow(z, interpolation='nearest', cmap='Blues', extent=[x.min(), x.max(), y.min(), y.max()])`. – Joe Kington Nov 23 '14 at 19:45
  • Thank you! That was exactly what I was locking for. – hanno Nov 23 '14 at 23:24
  • A similar issue exists for the color bar. Do you have an idea for a workaround for that? – hanno Nov 24 '14 at 00:45
  • 1
    You can work around that by passing in `rasterized=True` to `colorbar`. – Joe Kington Nov 24 '14 at 01:14
  • 1
    I'm getting an "unexpected keyword argument 'rasterized'" error when calling `pl.colorbar(rasterized=True)`. With MPL version 1.3.1 and 1.4.x. The top answer on [this question](http://stackoverflow.com/questions/15003353/why-does-my-colorbar-have-lines-in-it) works for me. – farenorth Nov 24 '14 at 01:52
  • 1
    Try `cb.solids.set_rasterized(True)` – hanno Nov 24 '14 at 02:04
  • This is a long-ongoing bug in Matplotlib, and for 10 years there seems to be no solution still. https://github.com/matplotlib/matplotlib/issues/1188 – Neinstein Aug 27 '21 at 07:02

4 Answers4

36

The comments have a good solution that utilizes imshow. When imshow is not appropriate for the input data (e.g. it is not uniformly spaced) this generally solves this problem,

pcol = pl.pcolormesh(x,y,z,cmap="Blues",linewidth=0,)
pcol.set_edgecolor('face')

If that approach does not reduce the lines sufficiently, you can also try this:

pl.pcolormesh(x,y,z,cmap="Blues",linewidth=0,rasterized=True)

In addition to reducing the lines between squares this approach also tends to reduce file size a bit, which is sometimes useful. In this case you may want to tune the dpi setting when saving (e.g. pl.savefig("heatmap.pdf", dpi=300)) until you get something that is satisfactory.

farenorth
  • 10,165
  • 2
  • 39
  • 45
  • For `evince` just the `set_edgecolor` was enough (note that for a colorbar it is `cbar.solids.set_edgecolor("face")`). – Graipher Oct 20 '19 at 09:56
9

The accepted answer didn't work very well for me. I seemed to have gotten closer by using antialiased=True, in addition to linewidth=0. This was with matplotlib version 3.0.2. Note the middle plot corresponds to the best version.

fig, axes = plt.subplots(1,3, figsize=(15,5))
axes[0].pcolormesh(XX, YY, ZZ_r, zorder=-1, norm=norm, cmap='magma', alpha=0.5, antialiased=True)
axes[1].pcolormesh(XX, YY, ZZ_r, zorder=-1, norm=norm, cmap='magma', alpha=0.5, antialiased=True, linewidth=0.0)
axes[2].pcolormesh(XX, YY, ZZ_r, zorder=-1, norm=norm, cmap='magma', alpha=0.5, antialiased=False, linewidth=0.0)

enter image description here

eqzx
  • 5,323
  • 4
  • 37
  • 54
9

I had this problem, using rasterized=True solved it (on matplotlib version 3.1.0).

user3111650
  • 91
  • 1
  • 2
2

Building on the answer by @eqzx: If you set alpha=1, you will get better results as far as grid lines are concerned. However, your application/use case may differ.

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
y = np.linspace(0, 10, 100)
xx, yy = np.meshgrid(x, y)

zz = xx**2 + yy*2
fig, axes = plt.subplots(2,3, figsize=(15,5))
axes[0,0].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=0.5, antialiased=True)
axes[0,1].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=0.5, antialiased=True, linewidth=0.0)
axes[0,2].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=0.5, antialiased=False, linewidth=0.0)
axes[1,0].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=1, antialiased=True)
axes[1,1].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=1, antialiased=True, linewidth=0.0)
axes[1,2].pcolormesh(XX, YY, ZZ_r, zorder=-1, cmap='magma', alpha=1, antialiased=False, linewidth=0.0)


See plot here

user408108
  • 135
  • 11