Generating art from lattice graphs
A couple of weeks ago, I went to see my sister playing percussion in a brass band at the Proms. While I was on the train home, I had an idea for a fun art project. I sketched it out on a napkin, got it working, posted a few pictures on Twitter, then put it down.
On Saturday I was sitting in the foyer of the Birmingham Symphony Hall, ready to watch her play in another band at the British Open. While I was waiting for her to start, I had some time to revisit those ideas, and write them up properly.
(There’s a lesson here about how art begets more art.)
These are a few of the pictures I was able to make:
I think these are pretty fun, and I’m surprised by how much variation I got from a single idea. In this post, I’m going to explain my ideas and thinking, and share the code I used to make them.
The basic idea
In maths, a graph is a structure made up of vertices and edges. Here’s a simple example:
My idea was to start with a graph and delete a random subset of edges. (In particular, I’m assigning random weights to edges then finding a minimal spanning tree. This gets a graph where all the edges are connected, but there are no loops.)
If I picked starting graphs with a certain structure, I thought I could get some fun pictures.
I used the networkx Python library to do all the graph logic, then I wrote my own template logic to render the graphs as SVGs. All the images are inline SVGs, so you can right click and “View source” to see how they’re drawn. I’ll link to the code at the end of the post.
Input graph #1: a square lattice
My initial napkin sketch had a square lattice. By deleting edges at random (but keeping the graph connected), these are some of the pictures I was able to make:
When I shared them on Twitter, somebody compared them to the characters of a conlang (“constructed language”). I quite liked the comparison, so I drew another batch with an earthy brown and varying stroke widths:
To me, these images feel vaguely evocative of Chinese characters, or kanji.
Input graph #2: triangular lattice
When I was drawing the square lattices, I used a networkx function called
grid_2d_graph. While reading the documentation, I discovered another function called
triangular_lattice_graph. I had no idea a triangular lattice graph was, but it dropped straight into my code, so I tried it.
That gave me a set of patterns that felt like creeping vines on a wall, so I coloured them green:
Input graph #3: radial lattice
I wanted to try using spiderweb-like diagrams as the input; I thought they’d look fun:
Although I wanted to use circles, drawing the curved arcs proved to be a bit tricky, so I started with straight lines between spokes. I fixed the number of rings at 4, and just varied the number of spokes. I also experimented with removing the central point, which creates a sort of “open” core.
It took a bit of time to work out the bugs, but I really like the results:
Then I added even more randomness: varying the number of rings, the colour, and the stroke width. These are a few of my favourites:
I especially like the blue hexagon, which feels like the topdown view of some sort of seafaring vessel.
On reflection, I can already see that “less is more”. Some of the most striking images are those with just a few spokes, or just a few rings – as those numbers increase, the shapes get more crowded and noisy. You’re less likely to get an interesting pattern.
Input graph #4: radial lattice with curves
As you crank up the number of spokes in a radial lattice, it starts to approximate a circle – so I wondered if I could actually do proper curves in the lattice? This requires the ability to draw arbitrary curved arcs, which took a bit more work, and ended up as a separate post.
Honourable mention to these image, which was created when I didn’t set a
fill attribute properly. I didn’t take this any further, but the opportunity for slices of a second colour feels like an interesting idea to explore.
Once I had the code for curves working, adding it to the radial lattice was fairly straightforward. I had a lot of fun generating these images.
These feel like designs out of science-fiction: the red circles feels evocative of radiation warnings, and several of them look like radar scanning screens (especially the dark green). As the spoke count increases, some of them feel like large mazes. The thin yellow line is one of my favourites, because it reminds me of a key hole.
Once again, I think some of the most striking images are those with just a few spokes and rings.
Input graph #5: radial lattice with convave curves
For a final variation, I tried using concave curves in the lattice. This matches the spider-web emoji, where the individual arcs bend towards the centre of the circle, rather than outward.
This got even more fun when I allowed arcs to bend alternately in and out, creating some extremely funky patterns.
At one point I had this running in a background window, generating a new image every thirty seconds, which made for a fun bit of decoration.
The only limit here is the graphs you start with: the stranger the input, the stranger the output. I have a bunch of ideas for other variations I could try, including:
- rotating the initial graph
- allowing for non-uniform gaps between spokes/rings in the radial lattice
- adding markers to the leaf nodes
- systematically deleting chunks of the original graph, say alternate spokes
- create filled segments, not just lines
I have no immediate plans to work on this any further – I proved the initial idea is workable, and I got some pretty pictures. That’s enough for now.
I mentioned earlier that some of the patterns look like the walls of a maze. These wouldn’t actually work as mazes, but it feels like this isn’t too far from a maze generator. Maybe if you used this to create the negative space, not the walls?
I made these with some scrappy Python scripts, using networkx for the graph logic and generating the SVG markup with string templates. I’ve put the code on GitHub, although it’s not documented.
There’s no point or greater moral to this post; I just made some pictures that I think are pretty and interesting. They don’t serve a purpose, and that’s okay. I spend a lot of time doing work on the computer, and it’s nice to use it for fun things too.