Getting started with generative art
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Last month, as part of the RSS pre-conference workshop for early career statisticians organised by the Young Statisticians Section, I delivered a workshop on Getting started with generative art. The slides from the workshop can be found online. I’ve now finally gotten around to writing up the workshop as a blog post which will explain what generative art is, where to find some inspiration, and how to start creating your own generative art systems.
What is generative art?
So let’s start with the obvious questions: what is generative art, and why should statisticians or data scientists care about it?
Let’s first define what it isn’t. These days it’s all too easy to hear the word generative and jump straight to thinking we’re talking about art made with generative AI. That’s not what we’re talking about in this blog post. When I’m talking about generative art, I mean
-
a form of art that is created using algorithms, rules, or systems that is
-
often (but not always) executed by computers, where
-
artists set parameters for the system to generate the artwork.
You can of course argue that AI-generated art fits all of these criteria, but there are many types of non-AI art that come under the umbrella of generative art. And generative art isn’t a new thing – Harold Cohen was considered one of the first practitioners of generative art in the 1960s.
Why should data scientists care about generative art?
Ahead of a conference about statistics and data science, a workshop about art might initially seem out of place. But there are many reasons why learning about generative art can benefit statisticians and data scientists. Here are five of those reasons:
-
Get better at programming – especially functions that simulate data: it’s a low stakes way to learn a programming language. The worst thing that can happen is that you make something that looks not so great. It’s also good for learning how to simulate data – useful for testing functions or sharing reproducible examples.
-
Practice designing algorithms (that are efficient): many generative art systems use very high-dimensional data, and it’s important to think about techniques to develop algorithms that work in efficient ways.
-
Using functions and statistical methods in ways they weren’t designed for: when you use functions for things that the developer never intended for you to do, you’ll find the limits of how they work. Perhaps you’ll come across different error messages and have to think about what you need to do to debug your code – which is more difficult when you’re using it for something not listed in any documentation.
-
Improve the aesthetics of your data visualisations: when creating art, you often focus on the visual elements of what you are creating. When visualising data, the aesthetics of the plot are not the most important aspect, but it is still something you should pay attention to. Generative art makes you think about how colours fit together, and how you place different geometric objects together – ideas that also apply in data visualisation.
-
It’s fun!: and that’s reason enough.
Creating a generative art system
When developing a generative art system, there are three components I usually start thinking about: parameters, randomness, and rules.
-
Parameters: the elements that the user (artist) can define and change.
-
Randomness: the elements that are generated through random chance.
-
Rules: the algorithm that processes the parameters and the randomness to create art.
Look at the three images below. These were all created by the same generative art system. What are the parameters? What are the random elements? What are the rules?
In these examples, the generative art system creates a grid of squares, where each square is subdivided in two by a straight line with one half coloured in.
-
Parameters:
- Colour palette for the polygons.
- Background colour.
- Number of rows.
- Number of columns.
-
Randomness:
- Whether the subdividing line goes from top to bottom, or left to right.
- The x-coordinates of the top to bottom line (or y-coordinates if left to right).
- The assignment of colours to each grid square.
-
Rules:
- Create a grid that has a user-specified number of rows and columns.
- For each grid square, draw a line that is either top to bottom or left to right.
- Colour in one of the half-squares.
Finding inspiration
One thing that prevents people from trying out generative art is the but I’m not an artistic person, I don’t know what to draw feeling. There are lots of places to find inspiration. An easy place to find inspiration is R or Python packages that have been developed to create generative art. This way you can play with functions and their parameters, without having to write the code to implement the system yourself. The {jasmines} package by Danielle Navarro is a great one to start with. I’ve also created my own generative art R package called {aRt}.
You might also find inspiration from other people who do art (generative or otherwise). Austin Kleon’s book, Steal Like An Artist, talks about art as an iterative process. When you see a piece of generative art, think about how it was implemented, think about whether you could implement it different, or think about how you might combine ideas from different sources. I’d also encourage you to be inspired by everyday things – the pattern on some hotel wallpaper, the stitching on a pair of jeans, or the way the shadows from a lamp fall on the wall.
During the generative art workshop, we took inspiration from an everyday item that many statistician and data scientists may have used to learn to count – an abacus:
Image: Unsplash
If you imagine the abacus as a two dimensional object, it essentially becomes some horizontal lines with circles along those lines. So let’s take that idea and define some parameters, rules, and randomness:
-
Rules:
- Draw a specified number of horizontal lines
- On each line, draw a specified number of circles of varying sizes
-
Parameters:
- Number of lines
- Number of circles per line
- Background colour
- Colour of circles and lines
-
Randomness:
- Position of circles on line
- Size of the circles
The only additional feature of this art (compared to the two dimensional abacus) is that we allow the size of the circles to vary.
Implementing generative art systems
Now we need to think about how to take this set of parameters, randomness, and rules and produce an image. You can use anything you like to implement a generative art system, as long as you have a way to draw lines, circles, and polygons and a way to generate random numbers. In this example here, we’re going to use R but you can use any programming language you want to. In the workshop, we used crayons, paper, and some six-sided dice – you don’t have to use a computer to create generative art (though it will take longer if you don’t!)
Parameters as variables
Let’s start by defining some initial values for the parameters we have, and saving them as variables. I’d recommend keeping the size and complexity of the system fairly low as you’re building it, to make it faster and easier to iterate. Here, we keep it quite small with only 8 lines and 10 circles per line. To limit overlapping between the circles, we also set a maximum size of the circles. The circles and lines will be the same colour, with a different colour for the background. Since the art contains an element of randomness, we choose a value for the random seed to make sure we’re always iterating on the same version of the art.
1 2 3 4 5 6 |
n_lines <- 8 n_dots <- 10 max_size <- 3 main_col <- "black" bg_col <- "white" s <- 1234 |
Simulating generative art data
Let’s start by generating the data that underlies our generative art. We need the x- and y- coordinates of the circles, as well as the size of the circles. Since the circles will lie on the horizontal lines, we don’t need to separately obtain the coordinates of the lines - they can be extracted from the circles coordinates.
We start by setting our random seed to aid in reproducibility, before constructing a data.frame
with the data we need. The x-coordinates come from a Uniform distribution - meaning the circles are equally likely to lie anywhere between 0 and 10. You may choose a different distribution if you want a different effect. For example, choosing a Normal distribution will result in the circles clustering around the mean of the distribution.
The y-coordinates are easier. Since we need all circles on the same horizontal line to have the same y-coordinate, we use the rep()
function to make repeats of the y-coordinates. Finally, the size of the circles is generated from an Exponential distribution since the circle sizes need to be non-negative. Alternatively, you could choose a different distribution and make use of the abs()
function to use the absolute value.
1 2 3 4 5 6 |
set.seed(s) plot_data <- data.frame( x = stats::runif(n_lines * n_dots, 0, 10), y = rep(1:n_lines, n_dots), size = stats::rexp(n_lines * n_dots) ) |
which gives us data that looks like this:
1 2 3 4 5 6 7 |
x y size 1 1.137034 1 0.05974751 2 6.222994 2 1.52295591 3 6.092747 3 0.84918014 4 6.233794 4 0.60822881 5 8.609154 5 1.20614573 6 6.403106 6 0.24495252 |
Plotting with {ggplot2}
Now we’re ready to start plotting. After loading {ggplot2}, we make use of functions that we’d normally use for making scatter plots (geom_point()
) and line charts (geom_line()
). We set up the plot by passing in our simulated data to the ggplot()
function, and specifying the x and y coordinates. We set the line colour, making the lines thinner and semi-transparent using the alpha
argument. We choose a different shape for the points (allowing both a fill colour and a line colour), and again set the colour and transparency. We also make sure to map the size of the points to the size
column in our simulated data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
library(ggplot2) g <- ggplot( data = plot_data, mapping = aes(x = x, y = y) ) + geom_line( mapping = aes(group = y), alpha = 0.1, colour = main_col, linewidth = 0.3 ) + geom_point( mapping = aes(size = size), pch = 21, fill = main_col, colour = main_col, alpha = 0.3 ) g |
Many of the circles are currently overlapping, and we need to apply the maximum size argument, max_size
, that we’ve already defined. We use the scale_size()
function to set the size range between 0.3
and max_size
. If you want, you could add a min_size
parameter instead of hard coding the value of 0.3
.
You’ll notice that elements such as axis labels and grid lines are added automatically (since {ggplot2} is designed to make charts not art). These aren’t elements that it makes sense to include in our generative art. In {ggplot2}, we can remove all of these elements easily using theme_void()
. We then further modify the theme to set the background colour based on the bg_col
variable we defined earlier, remove the legend for the circle size, and remove the border around the edges.
1 2 3 4 5 6 7 8 9 10 |
g + scale_size(range = c(0.3, max_size)) + theme_void() + theme( plot.background = element_rect( fill = bg_col, colour = bg_col ), legend.position = "none", plot.margin = unit(c(0, 0, 0, 0), "cm") ) |
We can now alter the values of the parameters: increase the number of horizontal lines and number of circles, make the circles smaller, choose different colours, and set a different random seed.
1 2 3 4 5 6 |
n_lines <- 30 n_dots <- 100 max_size <- 2 main_col <- "#326273" bg_col <- "#BDD8DE" s <- 2024 |
We can then re-run the plotting code, to produce a different piece of generative art.
The next step might be to turn this into a function: the parameters become arguments to the function, and the function itself simulates the data and returns the plot. You can also add some checks to make sure the values of the arguments are valid e.g. is the max_size
a positive number? Then, with one function, you can create many iterations of your generative art.
Further resources
If you want some more inspiration before getting started with your first (or next) generative art project, here are some additional resources:
-
The materials from Danielle Navarro’s Art from Code workshop at rstudio::conf(2022) are available online, and they are my favourite resource for help with anything related to spatial noise, shading, pixel filters, tesselations, and more.
-
Meghan Harris wrote an Intro to Data Art blog post talking about the basics of geometries, aesthetics, and layering for generative art, and walks through two examples with code.
-
I previously wrote a blog post with a step-by-step guide to creating generative art in Python using plotnine: nrennie.rbind.io/blog/making-art-python-plotnine
Image: Making art in Python with plotnine
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.