Getting Started with Generative Art in R | by Vít Gabrhel | Towards Data Science

Generative art represents the involvement of a human-independent system (such as an algorithm) in a creative process. Such a system is a key element within the creative process, including its outputs.
Unsurprisingly, there are many “tools” you can use if you want to delve into generative art. In case you want to have “hands-on” experience in R, there are two basic directions you can go.
If you are a person proficient in working with code, you may write your code straight away. I dare to argue that this is the way of the “individual” expression as it allows for more flexibility, and, well, freedom.
However, getting to that point takes time. Luckily, you can begin experimenting with your pieces of generative art by using one of the existing packages. Not only it could be quite rewarding, but it also works perfectly for grasping the basics of the “trade”.
In this article, I am going to present to you some of the “ready-to-use” packages for making generative art. Also, I will tap into some of the examples of using general packages or libraries to arrive at the same goal.
The first package I would like to present is called simply generativeart.
One of its key features is the way how it structures the output files. In order to get the output files, you have to specify the location where they will be stored. Also, it iterates on the provided formula that doesn’t need to be supported with a seed. In this scenario, each of the outcome files is unique.
Also, it is worth mentioning that the generativeart package is well documented and easy to use.
library(generativeart) # devtools::install_github("cutterkom/generativeart")library(ambient)library(dplyr)# set the pathsIMG_DIR <- "img/"IMG_SUBDIR <- "everything/"IMG_SUBDIR2 <- "handpicked/"IMG_PATH <- paste0(IMG_DIR,                    IMG_SUBDIR)LOGFILE_DIR <- "logfile/"LOGFILE <- "logfile.csv"LOGFILE_PATH <- paste0(LOGFILE_DIR,                        LOGFILE)# create the directory structuregenerativeart::setup_directories(IMG_DIR,                                  IMG_SUBDIR,                                  IMG_SUBDIR2,                                  LOGFILE_DIR)# include a specific formula, for example:my_formula <- list(  x = quote(runif(1, -1, 10) * x_i^2 - sin(y_i^2)),  y = quote(runif(1, -1, 10) * y_i^3 - cos(x_i^2) * y_i^4))# call the main function to create five images with a polar coordinate systemgenerativeart::generate_img(formula = my_formula,                             nr_of_img = 5, # set the number of iterations                            polar = TRUE,                             filetype = "png",                             color = "#c1a06e",                             background_color = "#1a3657")
Danielle Navarro, the author of the Learning Statistics with R Learning Statistics with R handbook, is a well-known person among psychology students.
Besides her teaching and research activities at the University of Adelaide, she also released the jasmines package, a tool allowing for creating a generative art in R.
This package gives you an opportunity to play with simulation parameters (e.g. grain or interaction), shapes (e.g. entity_circle or scene_discs) and their modifications (like style_ribbon) or colours (palette or alpha). And noise, linked to the ambient library:
library(dplyr) # or install.packages("dplyr") firstlibrary(jasmines) # or devtools::install_github("djnavarro/jasmines")p0 <- use_seed(100) %>% # Set the seed of R‘s random number generator, which is useful for creating simulations or random objects that can be reproduced.  scene_discs(    rings = 10,     points = 50000,     size = 50  ) %>%  mutate(ind = 1:n()) %>%  unfold_warp(    iterations = 10,    scale = .5,     output = "layer"   ) %>%  unfold_tempest(    iterations = 5,    scale = .01  ) %>%  style_ribbon(    color = "#E0542E",    colour = "ind",    alpha = c(1,1),    background = "#4D7186"  )ggsave("p0.png", p0, width = 20, height = 20, units = "in")
The mathart package wraps many commonly used algorithms into functions. One of such examples is the nearest neighbour graph, a visualisation of the k-d tree, a data structuring procedure of multidimensional space:
library(mathart) # devtools::install_github("marcusvolz/mathart")library(ggart) # devtools::install_github("marcusvolz/ggart")library(ggforce)library(Rcpp)library(tidyverse)points <- mathart::pointsresult <- kdtree(points)p1 <- ggplot() +  geom_segment(aes(x, y, xend = xend, yend = yend), result) +  coord_equal() +  xlim(0, 10000) + ylim(0, 10000) +  theme_blankcanvas(bg_col = "#fafafa", margin_cm = 0)# save plotggsave("kdtree.png", p1, width = 20, height = 20, units = "in")
mathart is a well-documented package. This fact widens the scope for experimenting. Maybe more importantly, by looking “under the hood”, the package improves understanding of data simulation.
In many instances, previously mentioned packages built on more generally used packages such as magritr (the pipeline operator comes in handy even in the art creation), ggplot, dplyr, or purr.
The k-d tree from the mathart package is no different. As we can see from the example of Marcus Volz, the original k-d tree algorithm can be tweaked using even base R:
# Metropolis: Generative city visualisations# Packageslibrary(ggart)library(tidyverse)library(tweenr)library(viridis)# Make reproducibleset.seed(10001)# Parametersn <- 10000 # iterationsr <- 75 # neighbourhoodwidth <- 10000 # canvas widthheight <- 10000 # canvas heightdelta <- 2 * pi / 180 # angle direction noisep_branch <- 0.1 # probability of branchinginitial_pts <- 3 # number of initial pointsnframes <- 500 # number of tweenr frames# Initialise data framespoints <- data.frame(x = numeric(n), y = numeric(n), dir = numeric(n), level = integer(n))edges <-  data.frame(x = numeric(n), y = numeric(n), xend = numeric(n), yend = numeric(n), level = integer(n))if(initial_pts > 1) {  i <- 2  while(i <= initial_pts) {    points[i, ] <- c(runif(1, 0, width), runif(1, 0, height), runif(1, -2*pi, 2*pi), 1)    i <- i + 1  }}t0 <- Sys.time()# Main loop ----i <- initial_pts + 1while (i <= n) {  valid <- FALSE  while (!valid) {    random_point <- sample_n(points[seq(1:(i-1)), ], 1) # Pick a point at random    branch <- ifelse(runif(1, 0, 1) <= p_branch, TRUE, FALSE)    alpha <- random_point$dir[1] + runif(1, -(delta), delta) + (branch * (ifelse(runif(1, 0, 1) < 0.5, -1, 1) * pi/2))    v <- c(cos(alpha), sin(alpha)) * r * (1 + 1 / ifelse(branch, random_point$level[1]+1, random_point$level[1])) # Create directional vector    xj <- random_point$x[1] + v[1]    yj <- random_point$y[1] + v[2]    lvl <- random_point$level[1]    lvl_new <- ifelse(branch, lvl+1, lvl)    if(xj < 0 | xj > width | yj < 0 | yj > height) {      next    }    points_dist <- points %>% mutate(d = sqrt((xj - x)^2 + (yj - y)^2))    if (min(points_dist$d) >= 1 * r) {      points[i, ] <- c(xj, yj, alpha, lvl_new)      edges[i, ] <- c(xj, yj, random_point$x[1], random_point$y[1], lvl_new)      # Add a building if possible      buiding <- 1      valid <- TRUE    }  }  i <- i + 1  print(i)}edges <- edges %>% filter(level > 0)sand <- data.frame(alpha = numeric(0), x = numeric(0), y = numeric(0))perp <- data.frame(x = numeric(0), y = numeric(0), xend = numeric(0), yend = numeric(0))# Create plotp2 <- ggplot() +  geom_segment(aes(x, y, xend = xend, yend = yend, size = -level), edges, lineend = "round") +  #geom_segment(aes(x, y, xend = xend, yend = yend), perp, lineend = "round", alpha = 0.15) +  #geom_point(aes(x, y), points) +  #geom_point(aes(x, y), sand, size = 0.05, alpha = 0.05, colour = "black") +  xlim(0, 10000) +  ylim(0, 10000) +  coord_equal() +  scale_size_continuous(range = c(0.5, 0.5)) +  #scale_color_viridis() +  theme_blankcanvas(bg_col = "#fafafa", margin_cm = 0)# print plotggsave("plot007w.png", p2, width = 20, height = 20, units = "cm", dpi = 300)
You don’t need to stop here. Some time spent playing with the code can easily end up by creating your distinct wall poster.
Generative art demonstrates that code can be beautiful. If you are still not persuaded, go and see more elaborated works like these.
Not only can generative art result in something astonishing, but it also helps you to understand the code itself. Interestingly, getting to the code underlying generative art may not be as easy as with other open-source areas. Some “generative artists” conclude not to share the code used in the creative process:
“I do not share the code I use to create my pieces. The main reason for this is that I don’t think it would be beneficial to anyone. People interested in getting started with generative art would become to focused on my ideas instead of developing their own. Knowing the answer is the killer of creativity.”
Thomas Lin Pedersen, Data Imaginist
Regardless if we agree or not, generative art confronts us with ideas that are not that common in the world of coding.
So, what are your ideas on the matter? Do you have any favourite generative artists? Or maybe your pieces of art you would like to share? Feel free to discuss this on Twitter.
Originally published at https://www.data-must-flow.com.