Skip to main content

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:

A graph with various vertices (black circles) connected by grey lines.

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.

A collection of grey circular arcs, where the area between the curve and the straight line connecting two points has been filled in black.

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.

A graphic made of yellow lines and circular arcs. There are lots of spokes and little arcs, so it looks quite busy. A graphic made of connected red circular lines. They're arranged into seven segments, with three segments forming along the outer edge. This looks similar to the three sections of a radiation warning symbol. A graphic made of dark green lines and circular arcs. To me, it looks a bit like some sort of complex radar scanning screen. A simple graphic made of connected lime-coloured lines. They're arranged around a circle: some concentric rings around a central point, then spokes going from the centre to the outer edge. Some of the lines are missing -- some of the circles and spokes have gaps. A simple graphic made of thin, yellow, circular lines. There's a gap in the middle of the circle, which looks a bit like a keyhole. A graphic made of pink lines and quarter circle arcs. The arrangement of lines and arcs around the central vertical line look a bit like a helmet, or maybe a stylised face. A graphic made of thick orange lines and circular arcs. A graphic made of black lines and circular arcs. There are five spokes which makes it look vaguely like a star. A graphic made of thick blue lines and circular arcs, split into three segments. It looks vaguely like some sort of radar scanner. A graphic made of turquoise lines and circular arcs. There are lots of spokes and little arcs, so it looks quite busy. A graphic made of purple semicircular arcs. You can see where the complete circle should be, but the graphic is divided down the middle: there are only arcs on the left-hand side. A graphic made of thick blue lines and circular arcs, split into quarters. It looks vaguely like some sort of radar scanner.

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.

Further ideas

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:

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.