# Collages and Patterns

Making art in R

October 12th 2022 | 2022-10-12

• I’m Meghan Harris 👋🏾
• Data Scientist 💻
• Prostate Cancer Clinical Trials Consortium (PCCTC) - Memorial Sloan Kettering ⚛️
• thetidytrekker.com 🌐
• @meghansharris
• meghan-harris
• I like making generative aRt in R (Rtistry) 🎨 - That’s why we’re here!

# What is Rtistry?

Pieces of art created with code in the R programming language.

# What is Rtistry?

These pieces can be generated randomly…

# What is Rtistry?

…or intentionally calculated

# What’s the Point of Rtistry?

• It’s fun
• It can be therapeutic

# What’s the Point of Rtistry?

You don’t need to be a programming genius or computational scientist to create Rtistry, but sometimes it helps to think about your toolbox before you start creating pieces.

## Tool Inspiration - Colors

### Colors and Palettes

grDevices Functions (like colorRampPalette())

Custom Palettes

Creating Functions

## Tool Inspiration - Geoms

### Paintbrushes, Pens, etc. AKA Geoms

# Library Load-in===
library(ggplot2)

#Generate a grid===
points <- data.frame(x = seq(0,5, by = .5),
y = seq(0,5, by = .5))

grid_points <- expand.grid(points)

#Create the ggplot===
grid_points |>
ggplot(aes(x,y))+
geom_point(shape = 22,
color = "black",
fill = "purple",
size = 10,
stroke = 3)+
geom_point(color = "white")

# Library Load-in===
library(ggplot2)

#Calculate data for lines===
vert_lines <- data.frame(x = seq(0,5, by = .1),
xend = seq(0,5, by = .1),
y = 0,
yend = 5)

pretty_colors <- c("#4CACBC", "#6CC4A1", "#A0D995", "#F6E3C5")

pretty_pal <- colorRampPalette(pretty_colors)(nrow(vert_lines))

#Create the ggplot===
vert_lines |>
ggplot(aes(x,y, xend = xend, yend = yend))+
geom_segment(color = pretty_pal, size = 10)

#Library Load-in===
library(ggplot2)
library(dplyr)
library(purrr)

#Generate angles===
angles <- seq(0,2*pi, length.out = 1000)

#Make a starter circle===
circle <- data.frame(x = cos(angles),
y = sin(angles))

#Set how many circles/iterations we want
iterations <- 1:10

#Make the final data set===
spirals <- map_df(iterations, ~circle %>%
mutate(x = x*.x,
y = y*.x,
group = .x))

#Create the ggplot===
spirals |>
ggplot(aes(x,y, group = group))+
geom_path(size = 5)+
coord_equal()

# Library Load-in===
library(ggplot2)

#Angle generation===
angle <- seq(0, 2*pi, length.out = 1000)

#Petal Length===
petal_length <- seq(1,10, length.out = 100)

#Dataframe for ggplot===
flower <- data.frame(x = cos(angle)*petal_length,
y = sin(angle)*petal_length)

#Create the ggplot===
flower |>
ggplot(aes(x,y))+
geom_polygon()+
coord_equal()

## Tool Inspiration - Supporting Information

### Supporting Information

💡 Knowing your way around the ggplot2 package can be super helpful:

Intro to Rtistry Blog Post

ggplot2 Book

ggplot2 References

💡 Creating sequences, samples, and distributions in R is useful:

Sequencing Functions: rep(), seq(), rep_along()

Distribution Functions: runif(), dnorm() & rnorm()

Sampling Functions: sample(), slice_sample

💡 Knowing how to use trig functions in R and understanding how to plot trig equations in ggplot may be helpful:

Trigonometric Functions: cospi(),cos(),sin(), etc.

Non-parametric vs. parametric equations/coordinates

Using packages that exist to make your life easier, like ggforce

Using workshops that exist to make your life easier, like Art From Code

💡 Playing around with code and/or having a desired output can help to bridge the connection from data to visual:

Ijemaka’s Anatomy of Generative Art

Danielle’s Art From Code

Recreation Thursday Project

# Making Data for Patterns

💡 No matter what your logical process is to creating rtistry, the most important aspect in the process is the data

How do we go from datasets with numbers and strings to rtistry?

# Making Data for Patterns

### 🔎 Observations we can make:

• There’s dots (points)
• There’s an order to how the dots are displayed
• The dots are white
• The background is green ( #598C4C to be exact )

# Making Data for Patterns

Code:

# "01_patterns_ex.R" in the example_scripts folder#

library(ggplot2) #For making the piece w/ ggplot
library(dplyr) #For data wrangling
library(tibble) #To work with tibbles

#Setting the axes limits for X and Y#
axis_min <- 0
axis_max <- 10

#Creating a "base" data frame to feed into ggplot#
base_data <- tibble(x = axis_min:axis_max,
y = x)

#Plotting the "blank" canvas#
base_data |>
ggplot(aes(x,y))

Code:

#Looking at the base_data frame points on the canvas#

base_data 
# A tibble: 11 × 2
x     y
<int> <int>
1     0     0
2     1     1
3     2     2
4     3     3
5     4     4
6     5     5
7     6     6
8     7     7
9     8     8
10     9     9
11    10    10
base_data |>
ggplot(aes(x,y))+
geom_point()

Code:

#1) Make a grid of points#

#Creates all combos of #s in the frame#
grid_points <- expand.grid(base_data)

#View the new dataset on the canvas#
grid_points |>
ggplot(aes(x,y))+
geom_point()

Code:

#2) Add spacing variations#

#Make a new "polka dot" set without the "dropped" values#
polka_dots <- grid_points |>
mutate(x = case_when(y %% 2 == 0 & x %% 2 > 0 ~ NA_integer_,
TRUE ~ x),
y = case_when(x %% 2 == 0 & y %% 2 > 0 ~ NA_integer_,
TRUE ~ y)) |>
filter(if_all(everything(), ~!is.na(.))) #Removes all rows with an NA#

#View the new dataset on the canvas#
polka_dots |>
ggplot(aes(x,y))+
geom_point()

Code:

#3) Add final aesthetic options to make it pretty

#Setting options for the image#
dot_size <- 10
dot_color <- "#ffffff" #"white" works too
background_color <- "#598C4C"

#Plotting the final image - while feeding in the options#
polka_dots |>
ggplot(aes(x,y))+
theme_void()+ #Removes axes, labels, etc.
geom_point(size = dot_size,
color = dot_color)+
theme(plot.background = element_rect(fill = background_color))

# Making Data for Patterns

### 🔎 Observations we can make:

• There’s wide, “zig-zagged” lines (paths)
• It’s the same line but copied and “shifted up” the plot
• There’s six lines with six distinct colors ( #c89658, #b6886f, #8867ab, #bbaa5f, #9fab7c, and #5aabc4 )
• The background is yellow ( #E3A934 to be exact )

# Making Data for Patterns

Code:

# "02_patterns_ex.R" in the example_scripts folder#

#library(ggplot2) #For making the piece w/ ggplot
#library(dplyr) #For data wrangling
#library(tibble) #To work with tibbles
library(purrr) #For iteration work

#Setting the axes limits for X and Y#
axis_min <- 0
axis_max <- 10

#Creating a "base" data frame#
base_data <- tibble(x = axis_min:axis_max,
y = axis_min) #this is a straight horizontal line

#Plotting the base_data canvas#
base_data |>
ggplot(aes(x,y))+
geom_point()+
geom_path()

Code:

#1) "Bump" up every other point#

#Creating a vector of "bumps"#
bumps <- rep_along(1:nrow(base_data), c(0,1))

#Mutating the base_data frame to add the "bumps"#
zigs <- base_data |>
mutate(y = y + bumps)

#Viewing the zigs frame#
zigs |>
ggplot(aes(x,y))+
geom_path()

Code:

#2) Copy and Paste the same line up the plot#

#Setting up the number of iterations and "shifts" up the plot#
n <- 1:6

#Creating a new dataframe with "copied and shifted" lines#
#n value is added to each y value 6 times#
zigzags <- map_df(n, ~ zigs |>
mutate(y = y + .x))

#Viewing the zigzags frame#
zigzags |>
ggplot(aes(x,y))+
geom_path()

Code:

#2) Copy and Paste the same line up the plot#

#Setting up the number of iterations and "shifts" up the plot#
n <- 1:6

#Creating a new dataframe with "copied and shifted" lines#
#n value is added to each y value 6 times#
#group value create a string to keep each "line" together#
zigzags <- map_df(n, ~ zigs |>
mutate(y = y + .x,
group = paste0("line",.x)))

#Viewing the zigzags frame#
zigzags |>
ggplot(aes(x,y, group = group))+
geom_path()

Code:

#3) Add final aesthetic options to make it pretty

#Setting options for the image#
line_size <- 10
line_colors <- c("#c89658", "#b6886f", "#8867ab",
"#bbaa5f", "#9fab7c", "#5aabc4")
background_color <- "#E3A934"

#Re-do the iterations - map colors into the dataset - it's easier#
zigzag_colored <- map2_df(n, line_colors, ~ zigs |>
mutate(y = y + .x,
group = paste0("line",.x),
color = .y))

#Plotting the final image - while feeding in the options#
zigzag_colored |>
ggplot(aes(x,y, group = group))+
theme_void()+ #Removes axes, labels, etc.
geom_path(size = line_size,
lineend = "square",
linejoin = "mitre",
color = zigzag_colored$color)+ theme(plot.background = element_rect(fill = background_color)) ## Patterns - Rainbow Wheel Example - First Look # Making Data for Patterns ### 🔎 Observations we can make: • This looks fancy, but we can use some illusions to make this • It’s really just one circle, just copied 20 times • There’s twenty distinct colors on a rainbow spectrum • Each circle has a white, dashed border around it • The background is black ## Patterns - Rainbow Wheel Example - Step by Step # Making Data for Patterns Code: # "03_patterns_ex.R" in the example_scripts folder# #Library Load-in# #library(ggplot2) #For making the piece w/ ggplot #library(dplyr) #For data wrangling #library(tibble) #To work with tibbles #library(purrr) #For iteration work #1) Calculate data for a circle from scratch# #Make a vector with angles for the circle# angles <- seq(0, 2*pi, length.out = 100) #Make the full circle with "converted" equations# circle <- tibble(x = cos(angles), y = sin(angles)) #View the base_circle plot# circle |> ggplot(aes(x,y))+ geom_path()+ coord_equal() Code: #2) Iterate the circle to copy and shift in a row# #Number of circles we want in total# n = 20 #Setting up the spectrum of colors we want to use# rainbow_pal <- c("#af3918", "#a21152", "#822b75", "#612884","#154baf","#0b82b9", "#277e9d", "#488e35","#e3a934","#b2336a") #Expanding this spectrum to match the number of circles we want# final_pal <- colorRampPalette(rainbow_pal)(n) #Creating a data frame with circles, colors, and group variables# circle_row <- map2_df(1:n,final_pal, ~circle |> mutate(x = x + .x, color = .y, group = paste0("group",.x))) #View the data as-is# circle_row |> ggplot(aes(x,y, group = group))+ geom_polygon() Code: #3) Add final aesthetic options to make it pretty #Setting options for the image# line_style <- 2 line_color <- "#ffffff" background_color <- "#000000" #Plotting the final image while feeding in options# #Fill variable gets the colors from the dataset# circle_row |> ggplot(aes(x,y, group = group))+ theme_void()+ geom_polygon(fill = circle_row$color,
color = line_color,
linetype = line_style)+
theme(plot.background = element_rect(fill = background_color))

Code:

#3) Add final aesthetic options to make it pretty#

#Setting options for the image#
line_style <- 2
line_color <- "#ffffff"
background_color <- "#000000"

#Plotting the final image while feeding in options#
#Fill variable gets the colors from the dataset#
circle_row |>
ggplot(aes(x,y, group = group))+
theme_void()+
geom_polygon(fill = circle_row$color, color = line_color, linetype = line_style)+ theme(plot.background = element_rect(fill = background_color))+ coord_polar() #warps the circles into a "wheel" # Making Data For Collages ## Making Data for Collages - What is a Collage? # Making Data for Collages ## What is a Collage? ### Def. (Oxford): a piece of art made by sticking various different materials on to a backing. ## Making Data for Collages - Sunset Example - A Closer Look # Making Data for Collages ## Patterns - Sunset Example - Observations # Making Data for Patterns ### 🔎 Observations we can make: • The image is landscape, (the max X limit is larger than the max Y limit.) • Background is a gradient of colors • A pattern of white lines varying in size is on top of the gradient • There’s a white circle in the middle that’s made up of thick solid white lines ## Collages - Sunset Example - Step by Step # Making Data for Collages Code: # "04_collage_ex.R" in the example_scripts folder# #Library Load-in# #library(ggplot2) #For making the piece w/ ggplot #library(dplyr) #For data wrangling #library(tibble) #To work with tibbles library(sp) #For doing more complicated polygon work #1) Set up our ggplot to be landscape# #X limits# xmin <- 0 xmax <- 20 #Y limits# ymin <- 0 ymax <- 10 #Creating the base_data# base_data <- tibble(x = seq(xmin,xmax, length.out = 100), y = seq(ymin,ymax, length.out = 100)) #Viewing the plot# base_data |> ggplot(aes(x,y)) Code: #2) Set up a color palette and data for geom_segment()# #Data frame with background segment lines# back_segments <- tibble(x = seq(xmin, xmax, length.out = 100), xend = x, #x == xend for vertical lines# y = ymin, yend = ymax) #Create a color palette to fit the data frame (100 rows)# color_pal <- c("#9C2C77", "#CD104D", "#E14D2A", "#FD841F") segment_colors <- colorRampPalette(color_pal)(nrow(back_segments)) #View the plot while feeding in color palette and tweaking size# back_segments |> ggplot(aes(x,y, xend = xend, yend = yend))+ geom_segment(color = segment_colors, size = 10) Code: #3) Expand the base data with expand.grid() to create a pattern# #Create a new expanded data frame off of base_data# overlay <- expand.grid(base_data) #Overlay Options# #Set the color for the overlay pattern overlay_color <- "#ffffff" #Create varying sizes for the overlay to fill the data# overlay_sizes <- sample(seq(.01, .2, length.out = nrow(overlay))) #Layer the overlay data frame onto the back_segments# back_segments |> ggplot(aes(x,y, xend = xend, yend = yend))+ theme_void()+ geom_segment(color = segment_colors, size = 10)+ geom_path(data = overlay, aes(x,y, group = y), color = overlay_color, size = overlay_sizes, inherit.aes = FALSE) Code: #4) Create a circle in the middle of the image from scratch# #Setting the angles# angles <- seq(0,2*pi, length.out = 100) #Storing in a dataframe for reference# ref_circle <- tibble(x = cos(angles) * (ymax/2) + (xmax/2) , y = sin(angles) * (ymax/2) + (ymax/2)) #Detecting points that only fit inside the circle# #Basing off overlay data because it's already created# fancy_circle <- overlay |> mutate(logic = point.in.polygon(x,y, circle$x, circle\$y)) |>
filter(logic == 1)

#Setting fancy circle options#
circle_width <- 2
circle_color <- "#ffffff"

#Setting options for the image#
line_style <- 2
line_color <- "#ffffff"
background_color <- "#000000"

#Layer the fancy circle data onto the existing plot#
back_segments |>
ggplot(aes(x,y, xend = xend, yend = yend))+
theme_void()+
geom_segment(color = segment_colors, size = 10)+
geom_path(data = overlay, aes(x,y, group = y),
color = overlay_color,
size = overlay_sizes,
inherit.aes = FALSE) +
geom_path(data = fancy_circle,
aes(x,y, group = x),
color = circle_color,
size = 2,
lineend = "butt",
inherit.aes = FALSE)

Code:

#This can be layered differently to reduce code#
#geom order from top to bottom determines display order#

overlay |>
ggplot(aes(x,y))+
theme_void()+
geom_segment(data = back_segments,
aes(x,y, xend = xend, yend = yend),
color = segment_colors,
size = 10,
inherit.aes = FALSE)+
geom_path(aes(x,y, group = y),
color = overlay_color,
size = overlay_sizes) +
geom_path(data = fancy_circle,
aes(x,y, group = x),
color = circle_color,
size = 2,
lineend = "butt")+
coord_equal(expand = FALSE)