A Brief Intro to Generative Art in Python and the Axidraw Plotter
Updated: Jan 21, 2020
Over the past year, I've been getting into creating generative art and then using a mechanical plotter to draw them line by line. Plotter prints operate way different than your run of the mill printers because they physically move a pen to a location to draw a line. This means you can't draw a high-resolution JPEG, but you can make drawings that look human-made but that would take months for a person to draw.
When I was first getting started doing this, I noticed there wasn't a ton of introductory material out there, and now that I'm more versed I figure it would be good to write something as a starting guide.
In this post, I’m going to walk you through creating a basic art piece using some of the tools you commonly find in the standard Python data science stack (numpy and matplotlib) and getting that drawn with multiple colors with an Axidraw. There are going to be two main pieces - creating an SVG from python, and an overview of a bunch of the tools out there for turning that into a drawing.
The goal of this blog post is to get you able to make a piece that looks like this
And the full source code to make that SVG can be found here.
To get started, we are going to be using matplotlib to create our SVGs. Matplotlib is a good choice because it is very flexible and extensively documented/stack overflowed.
To get started lets import numpy and matplotlib
Now, how we are going to make this piece is by trying to stuff as many non-overlapping circles as we can randomly into a box. The first thing we want to do is figure out how big our box should be, and how big our circles should be
And now we are going to make a pretty dumb brute force approach. All we are going to do is pick a random starting point within our box for a new circle, and we are going to try to find the largest it can be without hitting any other circle, and if it is bigger than our minimum size we keep it. We aren't going to be particular smart about this - we aren't going to check to see if it's within another circle or anything like that, we are just going to make up for it by trying our dumb approach a lot of times.
Now that we have our circles, we are going to make matplotlib patches that we can draw and visualize. In order to get two different colors, we're just going to flip a coin to decide which one is which.
And finally, we can plot it. We can tell matplotlib to turn off the grid and axes so it doesn't look ugly
The final step is to save it as two SVGs (you'll see why later). One nice thing about matplotlib is it lets you save your plots directly to SVGs. It does automatically generate a bounding box with a margin, so there is some code to make that margin be 0 (I haven't been able to find a way for it to have no bounding box)
And do that again for the red layer and voila, we are done!
Now the next step that you have your drawings is to optimize the drawing paths. By optimize the paths, I mean you want to reorder the elements in the SVG so that an element starts right after where the last element finished. The reason you want to do this is that whenever you generate random drawings, chances are lines are just in a random order in the file, and this will make it take ages to actually draw since the robot will spend lots of time moving back and forth. Fortunately, there are tons of different optimization tools out there for plotters.
Personally, I’ve used the Axidraw/Inkscape optimizers, Saxi’s optimizer, and written my own (based on Saxi’s algorithm). In terms of how well they work - I find that Saxi’s is the best because it will reverse some paths to minimize the up-down toggles (which takes up a surprisingly large amount of the total draw time), and it has the option to join path starting points if they are within a certain radius which can speed things up 10-20% (but it can affect how lots of fine-close lines are drawn)
The Axidraw one is better than nothing, but typically if I’m not using Saxi (it doesn’t handle multilayered SVGs well) then I just prefer to use my homemade one. It doesn't do any path reversing, and I've found it a big factor in overall plot time.
In addition, I know there are a few other optimizers out in the wild but I haven’t had a chance to try them. The ones that come to mind are Inconvergent's and Folegman's, as well as vpype. Vpype seems really cool as a tool for dealing with multiple layers (which I'll talk about in the next section), but right now it does line merging, line reversing, and line sorting is under active development (this is one of the few libraries being actively worked on and the developer is really open to suggestions, and so it's pretty great).
The Axidraw can only have one pen in it at a time. So if you want to do multiple colors or multiple pen sizes, you're going to need to use multiple layers so that when you are done with one, you can pause, load the next pen in and do the next layer.
Programatically making multiple layers is tricky. When dealing with layers Axidraws don’t exactly interface with normal SVGs, they interface with Inkscape SVGs. I’ve found the best way to do multiple layers is to save your file as multiple SVGs and then combine them down the road into an Inkscape SVG.
Most standard SVG libraries don’t deal with Inkscape stuff (the only one I found was svgwrite ). For a long time, to combine multiple layers I had a script that would read in several SVGs, and use XML to parse out the elements that would be drawn, and then I would paste that into an Inkscape SVG template I made. Between you and me that was some of the most awful code I had the misfortune of depending on.
Fortunately for us, Antoine Beyeler has been developing a good command-line interface called vpype for dealing with SVGs. This CLI lets you resize SVGs, stitch together layers, and there are some core optimizations with more of it under active development. I'd highly recommend it. You can find it here. So I’d recommend using that software, with one caveat to note - it works by converting everything polylines, so if you use a lot of circles, ellipses, or arcs in your SVG it might inflate the file size a bit [this could be problematic if you're using Inkscape after, I'll discuss this in the next section, but imho you probably don't need Inkscape with vpype].
For a note on usages - the Axidraw looks for layers with IDs that start with numbers. I’d also consider putting your layer colors in order from lightest to darkest, or else the ink on the paper might bleed into the pen.
Now we have gotten to the final step, actually drawing our work. The final step is to somehow to our physical robot and give it our SVG. There are a few different ways to do this.
The most basic way is to use the Inkscape extension. This has some advantages - it natively handles multiple layers, you can resize to the desired paper size in Inkscape, can do path optimization, and you can edit the SVGs directly. The biggest drawback I’ve found to using Inkscape is that it gets unusably slow for SVGs once they start getting past the 2mb range.
Option number two is to use Saxi. I personally really like Saxi. It does drawing resizing really well, it has a great optimizer, it can usually handle larger files (although it starts running into issues around the 10mb range), and if you’re ambitious you can throw it onto a Pi so you don’t have to have your laptop tethered to your robot. The only big downside is that this doesn’t really do multiple layers.
Option number three is to directly interface with your robot using the Axidraw Python CLI. I’ve only recently seen this, but I’ll probably start using this exclusively going forward. Because you’re going through python it doesn’t have file size issues, and it can do optimization, as well as multiple layers, and it’s in python so you can chain it with whatever tooling you want to. The only thing it doesn’t really do is resizing your art to a given size, but if you throw vpype as a preprocessing step you should be.
Conclusion and Additional Resources
Glad you made it this far! If you’re new there is a lot of stuff to wrap your head around, but I hope this helped give you some starting points.
If you want to explore the space, I've compiled a broad list of resources here.
If you want to learn more about the generative algorithms side of things, you might want to check out this talk I gave on trying to create photorealistic drawings.
And lastly, if you want to follow what I'm up to, you can find my work here or follow me on Instagram.