I am trying to make a publication-quality graph that nicely shows the density of where randomly generated lines fall on a plot. However, when I try to save these plots in .svg format, there is always a loss in quality because I think the lines are being rasterized. Calling the set_rasterized function doesn't appear to help.
Is there a way to force matplotlib to save these lines in vector format, or at least save them at higher quality so the images don't look terrible when zoomed in? Saving as a .png with high DPI does not help either.
import matplotlib.pyplot as plt
import numpy as np
num_lines = 1000
np.random.seed(42)
xs = np.linspace(0, 10, 100).reshape(1,-1)
ys = xs*np.random.normal(1,1,(num_lines,1)) + np.random.normal(0, 1, (num_lines,100))
for y in ys:
l = plt.plot(xs.flatten(), y, 'k', alpha=0.01)
l[0].set_rasterized(False)
plt.savefig('ex.svg')
plt.show()
You allude to this in your comment, so I'll add an example of how I've addressed this by manipulating linewidth rather than alpha to get a similar visualization of distribution that still has sharp lines.
Here's a replication of your current approach:
import matplotlib.pyplot as plt
import numpy as np
num_lines = 1000
np.random.seed(42)
xs = np.linspace(0, 10, 100).reshape(1,-1)
ys = xs*np.random.normal(1,1,(num_lines,1)) + np.random.normal(0, 1, (num_lines,100))
for y in ys:
l = plt.plot(xs.flatten(), y, 'k', alpha=0.01)
l[0].set_rasterized(False)
plt.savefig('ex.svg')
plt.show()
Here's an alternative -- I also try to explicitly tell matplotlib
not to rasterize via ax.set_rasterization_zorder(None)
(I believe this is the same as your l[0].set_rasterized(False)
call).
The difference is that I switch to manipulating linewidth
rather than alpha
. I think the effect is fairly similar.
fig, ax = plt.subplots()
ax.set_rasterization_zorder(None)
num_lines = 1000
np.random.seed(42)
xs = np.linspace(0, 10, 100).reshape(1, -1)
ys = xs * np.random.normal(1, 1, (num_lines, 1)) + np.random.normal(0, 1, (num_lines, 100))
for y in ys:
ax.plot(xs.flatten(), y, color='black', linewidth=0.01)
fig.savefig('ex_width.svg', format='svg')
When you zoom way in, you can see that the alpha
approach (left) is fuzzier than the linewidth
approach (right):