Categories
Generative Art R

Generating beautiful patterns with R

Motivated by my last experiments with Glitch Art I decided to look a bit more into generating images with R. One of my favorite musicians Max Cooper released another absolutely gorgeous music video. Check it out, the animation is fantastic. I was intrigued by the simple basic structure. It was just a rectangle divided by rectangles divided by rectangles. Something I can absolutely do with my R skills. So, I tried. The pictures are a result of that.

My tactic was to create a data frame just starting with the first rectangle, defined by start and end coordinates then just splitting them. I filled them randomly with colors. Honestly quite simple. Doing this and other experiments, I got a lot better making code run faster in R. Of course there is still a lot of space to improve. The code in my last post for example was super inefficient and I made a lot of basic mistakes (I improved it and now it runs a lot faster).

Here is the code if anyone is interested:

library(tidyverse)

rectanglesplitter=function(data,i){
#data is one line of the total dataset, i is the number of the loop.
#because I don't want super long rectangles, I always first check which is the longe side.
yaxsplit=ifelse((data$z.x-data$a.x)^2>=(data$z.y-data$a.y)^2,F,T )
#create the divider which is a value which defines the proportions of the two new rectangles
divider=1/(random[i]+1)

#rectangle 1
########
#ifelse is necessary to change if it is a vertical split or not.
#here the new x.a1 and new y.a1 is created. (naming was a bit stupid I admit)
data[2,1]=ifelse(yaxsplit==T, data[1,1] , data[1,1]+(data[1,3]-data[1,1])*divider)
data[2,2]=ifelse(yaxsplit==T, data[1,2]+(data[1,4]-data[1,2])*divider, data[1,2])

#Points stay stay the same no mater the orientation.
#x.z1 and y.z1 are created
data[2,3]=data[1,3]
data[2,4]=data[1,4]

#rectangle 2
#are the same like in the first created recangle (x.a and y.a)
data[3,1]= data[2,1]
data[3,2]= data[2,2]
#y.z2 and y.z2 
data[3,3]=ifelse(yaxsplit==T, data[1,3] , data[1,1] )
data[3,4]=ifelse(yaxsplit==T, data[1,2] , data[1,4])


#add level (for potential animations)
data[2,5]=i
data[3,5]=i
#add a color. one of the rectangles keeps the color of the bigger rectangle, not necessary
data[2,6]=random[i]
data[3,6]=data[1,6]

#this changes which one of the rectangles is saved first. this should change it up and make sure there aren't more splits on one side.
if(random[i]%%2==0){
data[3:2,]
}
else{data[2:3,]}
}

# a list of color palettes
pallist=list(
palette=c("black","#CDCFE2","#423E6E","#FF352E"),
palette=c("#233142","#455d7a","#f95959","#e3e3e3",NA)
)

#how many splits should be done?
loops=50000
#create empty dataframe
df=data.frame(a.x=rep(NA,loops*2),
a.y=NA,
z.x=NA,
z.y=NA,
level=NA,
color=NA,
alpha=NA)
#fill first row
df[1,]=c(0,0,100,100,1,1,1)


#precreate random vector used for proportions and colors.
random=sample(1:4,loops,replace = T)

i=1
while(i <loops){
#filling up dateframe with simple loop and splitter functions
df[((2*i):((2*i)+1)),]=rectanglesplitter(df[i,],i)

#this skips every few rows, so there stay a few bigger rectangles.
i=ifelse(i%%17==0&i>881,i+2,i+1)
}


#this is just for me to choose one palettes in the list
farbe=1
ggplot(df)+
geom_rect(aes(xmin=a.x,ymin=a.y,xmax=z.x,ymax=z.y),
alpha=9,show.legend = F,fill=pallist[[farbe]][df$color],col=pallist[[farbe]][5])+
coord_fixed()+
theme_void()