2025, Dec 03 17:00
Stop Fuzzy Matplotlib SVG Lines: Use Tiny Linewidths Instead of Alpha for Crisp, Dense Plots
Why Matplotlib SVGs get fuzzy with many transparent lines, and how tiny linewidths (not alpha) keep crisp vector strokes for sharp, publication-ready plots.
When you need a publication-quality density visualization of many random lines, saving from Matplotlib to SVG should preserve crisp vector strokes. Yet, with thousands of semi-transparent lines, zooming often reveals fuzzy, muddy edges. The usual suspicion is rasterization during export, and toggling rasterization flags may appear ineffective. The root cause here is more subtle.
Reproducing the issue
The following snippet draws 1000 random lines using low alpha to reveal distribution. Exporting to SVG and zooming shows degraded sharpness.
import matplotlib.pyplot as plt
import numpy as np
line_total = 1000
np.random.seed(42)
x_grid = np.linspace(0, 10, 100).reshape(1, -1)
y_stack = x_grid * np.random.normal(1, 1, (line_total, 1)) + np.random.normal(0, 1, (line_total, 100))
for y_seq in y_stack:
handle = plt.plot(x_grid.flatten(), y_seq, 'k', alpha=0.01)
handle[0].set_rasterized(False)
plt.savefig('ex.svg')
plt.show()
What actually happens
Looking at the SVG output reveals vector paths, not bitmaps. You may see style attributes like stroke-opacity and stroke-width attached to lots of line elements. That means the file itself keeps vector geometry intact.
svg is text file - so you can open it in any text editor and check if it is rasterized. Eventually you can open it some graphics editor which can work with SVG (ie. Inkscape) and check how it keep elements.
The fuzzy look appears because each line carries a very small alpha (e.g., stroke-opacity: 0.01) combined with a relatively standard stroke width (e.g., stroke-width: 1.5). When you zoom in using viewers or downstream tools, the stroke width remains the same while the transparency blends visually, producing a soft, blurry appearance. Some tools may also rasterize during display, further compounding the effect.
Solution: switch from alpha to linewidth
To keep the sharpness while still conveying density, render the lines fully opaque but dramatically reduce the linewidth. This preserves vector crispness while producing a distribution-like look. It also helps to explicitly disable rasterization logic on the axes level.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.set_rasterization_zorder(None)
line_total = 1000
np.random.seed(42)
x_grid = np.linspace(0, 10, 100).reshape(1, -1)
y_stack = x_grid * np.random.normal(1, 1, (line_total, 1)) + np.random.normal(0, 1, (line_total, 100))
for y_seq in y_stack:
ax.plot(x_grid.flatten(), y_seq, color='black', linewidth=0.01)
fig.savefig('ex_width.svg', format='svg')
This change replaces visual blending via alpha with visual thinning via linewidth. The overall impression of density remains similar, but zoomed-in regions keep clean edges because the viewer is no longer compositing thousands of semi-transparent strokes.
Why this matters
SVG is often the right choice for plots that must survive aggressive zooming in editors, slides, or documents. Relying on transparency to build up density can look fine on screen, yet it degrades under magnification and in certain rendering pipelines. Using linewidth to encode density-like variation gives you vector fidelity across toolchains, and avoids the artifacts that appear when viewers or document editors rasterize during display.
Practical takeaways
If you see fuzziness in an exported SVG with many overlapping lines, first verify whether your file truly contains vector geometry by inspecting it as text or in an editor capable of working with SVG elements. If the lines are indeed vector, reduce the linewidth substantially instead of lowering alpha. You can also direct Matplotlib not to rasterize by setting the rasterization z-order on the axes. Combined, these changes preserve the intent of the visualization while keeping the output crisp at any zoom level.
For workflows where the viewer or downstream document tool may rasterize on display, maintaining vector strokes with minimal linewidth provides robust, publication-quality results without sacrificing clarity.