Search code examples
pythonmatplotliberrorbarrasterizingsavefig

Ugly Outline When Rasterizing Errorbar


I'm plotting a large number of data points with errors using Matplotlib (version 2.2.5), and I'm rasterizing the data because there are a few thousand data points. I've found that when I rasterize the data and save as a PDF, however, the error bars produce an ugly white outline that isn't acceptable for publication. I've constructed a MWE that shows the problem:

import numpy as np
import random as rand
import matplotlib.pyplot as plt

rand.seed(10)
seeds = range(0, 1000)
data = np.empty((len(seeds), 2))
for n in seeds:
    data[n, 0] = rand.gauss(1, 0.01)
    data[n, 1] = rand.gauss(1, 0.01)

fig, ax = plt.subplots(1, 1, figsize=(6, 6))

ax.scatter(data[:, 0], data[:, 1], s=10, facecolors="k", rasterized=True, zorder=1)
ax.errorbar(data[:, 0], data[:, 1], xerr=0.01, yerr=0.01, color="k", fmt="none", rasterized=True, zorder=2)

fig.savefig("Test.pdf", dpi=250)

This looks fine in the Jupyter Notebook output, and also as a saved PNG file. The output PDF file, however, looks like this: PDF output How do I get rid of that white fuzz caused by the error bars? If I don't rasterize, the problem vanishes, but then the file takes annoyingly long to load in my paper, and the last thing I want to do is annoy my reader.


Solution

  • I found the solution thanks to an older question: I needed to add ax.set_rasterization_zorder(0) to the code and change the zorder of the plotted points to be below 0. This produced a perfect graph that has no ugly outlines of the data and retains a vectorized axis, exactly what I wanted. The working code is:

    import numpy as np
    import random as rand
    import matplotlib.pyplot as plt
    
    rand.seed(10)
    seeds = range(0, 1000)
    data = np.empty((len(seeds), 2))
    for n in seeds:
        data[n, 0] = rand.gauss(1, 0.01)
        data[n, 1] = rand.gauss(1, 0.01)
    
    fig, ax = plt.subplots(1, 1, figsize=(6, 6))
    
    ax.scatter(data[:, 0], data[:, 1], s=10, facecolors="k", rasterized=True, zorder=-2)
    ax.errorbar(data[:, 0], data[:, 1], xerr=0.01, yerr=0.01, color="k", fmt="none", rasterized=True, zorder=-1)
    
    ax.set_rasterization_zorder(0)
    
    fig.savefig("Test.pdf", dpi=250)
    

    and the output is:new test output