How can I get the output of a matplotlib plot as an SVG?

user391339 picture user391339 · Jul 2, 2014 · Viewed 90.9k times · Source

I need to take the output of a matplotlib plot and turn it into an SVG path that I can use on a laser cutter.

import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,100,0.00001)
y = x*np.sin(2*pi*x)
plt.plot(y)
plt.show()

For example, below you see a waveform. I would like to be able to output or save this waveform as an SVG path that I can later work with in a program such as Adobe Illustrator.

I am aware of an SVG library called "Cairo" that matplotlib can use (matplotlib.use('Cairo')), however it's not clear to me that this will give me access to the SVG path that I need, even though matplotlib will now be using Cairo to generate the plot.

enter image description here

I do have cairo working on my system, and can successfully draw an example composed of SVG paths that I can indeed edit in Illustrator, but I don't have a way to take my equation above into an SVG path.

import cairo
from cairo import SVGSurface, Context, Matrix    
s = SVGSurface('example1.svg', WIDTH, HEIGHT)
c = Context(s)

# Transform to normal cartesian coordinate system
m = Matrix(yy=-1, y0=HEIGHT)
c.transform(m)

# Set a background color
c.save()
c.set_source_rgb(0.3, 0.3, 1.0)
c.paint()
c.restore()

# Draw some lines
c.move_to(0, 0)
c.line_to(2 * 72, 2* 72)
c.line_to(3 * 72, 1 * 72)
c.line_to(4 * 72, 2 * 72)
c.line_to(6 * 72, 0)
c.close_path()
c.save()
c.set_line_width(6.0)
c.stroke_preserve()
c.set_source_rgb(0.3, 0.3, 0.3)
c.fill()
c.restore()

# Draw a circle
c.save()
c.set_line_width(6.0)
c.arc(1 * 72, 3 * 72, 0.5 * 72, 0, 2 * pi)
c.stroke_preserve()
c.set_source_rgb(1.0, 1.0, 0)
c.fill()
c.restore()

# Save as a SVG and PNG
s.write_to_png('example1.png')
s.finish()

enter image description here

(note that the image displayed here is a png, as stackoverflow doesn't accept svg graphics for display)

Answer

DrV picture DrV · Jul 2, 2014

You will most probably want to fix the image size and get rid of all sorts of backgrounds and axis markers:

import matplotlib.pyplot as plt
import numpy as np

plt.figure(figsize=[6, 6])
x = np.arange(0, 100, 0.00001)
y = x*np.sin(2* np.pi * x)
plt.plot(y)
plt.axis('off')
plt.gca().set_position([0, 0, 1, 1])
plt.savefig("test.svg")

The resulting SVG file contains only one extra element, as savefig really wants to save the figure background. The color of this background is easy to change to 'none', but it does not seem to get rid of it. Anyway, the SVG is very clean otherwise and in the correct scale (1/72" per unit).