Site icon R-bloggers

Getting started in #rtistry

[This article was first published on %>% dreams, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Artists in the R community have been using the #rtistry hashtag to demonstrate their gorgeous, dynamic art using only the R programming language. Their creations are amazing and they inspired me to try out generative art this dreary Sunday.

I am proud to showcase my first #rtistry plot ever! Kinda reminds me of KidPix (remember KidPix?!). I wanted to share how I did it and welcome any feedback or advice, as this is totally new and I’m not even sure if I am doing it right?


As always, we start with the packages we will use:

# Load packages
library(tidyverse)
library(viridis)
library(ggdark)
< section id="write-a-parametric-equation" class="level2">

Write a parametric equation

First up is figuring out the function you will use to create the plot. I decided to go with a parametric equation for my first #rtistry plot. A parametric equation of a curve expresses the coordinates of points of the curve as functions of a variable. This blog post explains the concept very clearly and also has various examples of wonderful parametric equations.

Why parametric equations? First, even simple equations can create beautiful symmetries. Second, they are easy to modify to find the perfect plot.

The simplest parametric equation uses cosine and sine to make the unit circle:

circleFun <- function(center = c(0, 0), diameter = 1, npoints = 100){
    r = diameter / 2
    tt <- seq(0,2*pi,length.out = npoints)
    xx <- center[1] + r * cos(tt)
    yy <- center[2] + r * sin(tt)
    return(data.frame(x = xx, y = yy))
}

dat <- 
  circleFun(c(1, -1), 2.3, npoints = 100)

ggplot(dat,aes(x, y)) +
  geom_path()

Let’s write a function to create a parametric equation. I based this equation on the aforementioned blog post equations. The parameters are:

genFun <- function(center = c(0, 0), npoints = 500, c1 = 2.5, c2 = -5, c3 = 4.28, c4 = 2.3){
    t <- seq(0, 2*pi, length.out = npoints)
    xx <- center[1] + c1*(sin(c2*t)*sin(c2*t))*(2^cos(cos(c3*c4*t)))
    yy <- center[2] + c1*sin(sin(c2*t))*(cos(c3*c4*t)*cos(c3*c4*t))
    a <- data.frame(x = xx, y = yy)
    
    return(a)
}

Playing around with the function, we see how the graph gets smoother with more points and how the shape changes with different coefficients.

dat <- 
  genFun(c(1,-1), npoints = 100)

ggplot(dat, aes(x, y)) +
  geom_path()

dat <- 
  genFun(c(1,-1), npoints = 500, c1 = 5, c2 = -3, c3 = 5, c4 = 2)

ggplot(dat, aes(x, y)) +
  geom_path()

< section id="create-variation-within-the-graph" class="level2">

Create variation within the graph

Now that we have a basic shape, let’s play around with different aspects of the graph:

< section id="geoms" class="level3">

geoms

We started off with geom_path but can play around with other geoms too. Here it is with geom_line:

dat <- 
  genFun(c(1,-1), npoints = 5000)

ggplot(dat, aes(x, y)) +
  geom_line()

And with geom_point:

set.seed(1234)

dat <- 
  genFun(c(1,-1), npoints = 500)

dat %>% 
  ggplot(aes(x, y)) +
  geom_point()

< section id="aesthetic-specifications" class="level3">

Aesthetic specifications

The {ggplot2} package has several aesthetic specifications available for plots. A full list can be found here.

We’re going to go ahead and get rid of all the background using theme_void().

< section id="size" class="level4">

Size

Let’s go with geom_point. In this case, we can start playing around with the aesthetics to see what would look interesting. With geom_point, you can edit the sizes of the points, so we create a column with random point sizes to create some variation.

set.seed(1111)

dat <- 
  genFun(c(1,-1), npoints = 5000) %>% 
  mutate(rand_w = sample(n())/3000)

dat %>% 
  ggplot(aes(x, y)) +
  geom_point(size = dat$rand_w) +
  theme_void()

< section id="shape" class="level4">

Shape

We could also change the shape of each of the points, but I liked the circles more:

dat %>% 
  ggplot(aes(x, y)) +
  geom_point(size = dat$rand_w,
             shape = 8) +
  theme_void()

< section id="opacity" class="level4">

Opacity

We could also change the opacity of the points:

set.seed(1234)

dat <- 
  dat %>% 
  mutate(rand_o = sample(n())/5000)

dat %>% 
  ggplot(aes(x, y)) +
  geom_point(size = dat$rand_w,
             alpha = dat$rand_o) +
  theme_void()

< section id="color" class="level4">

Color

We can also create a column for random numbers to ascribe colors to each point. I decided to use the magma color palette from the {viridis} package because it is so vibrant. Now that we’re not using only black points, we can use dark_theme_void() from the {ggdark} package for a fully black background.

set.seed(1234)

dat <- 
  dat %>% 
  mutate(rand_c = sample(n()))

dat %>% 
  ggplot(aes(x, y,  color = rand_c)) +
  geom_point(size = dat$rand_w,
             alpha = dat$rand_o) +
  scale_color_viridis(option = "magma") +
  dark_theme_void() +
  theme(legend.position = "none") # remove legend
Inverted geom defaults of fill and color/colour.
To change them back, use invert_geom_defaults().

< section id="repetition" class="level3">

Repetition

Notice we added rand_w, rand_o, and rand_c so that we can randomly change up the size, opacity, and color of the plot. Let’s go back to our original generative function and them as parameters. Now we can change them without having to add them to the data frame externally from the function. (Apologies for the switching back and forth from dplyr to base R!)

genFun <- function(center = c(0, 0), npoints = 500, c1 = 2.5, c2 = -5, c3 = 4.28, c4 = 2.3, size_denom = 1, opacity_denom = 1, color_denom = 1){
    t <- seq(0, 2*pi, length.out = npoints)
    xx <- center[1] + c1*(sin(c2*t)*sin(c2*t))*(2^cos(cos(c3*c4*t)))
    yy <- center[2] + c1*sin(sin(c2*t))*(cos(c3*c4*t)*cos(c3*c4*t))
    rand_w <- sample(0:20, npoints, replace = TRUE)/size_denom
    rand_o <- sample(1:100, npoints, replace = TRUE)/opacity_denom
    rand_c <- sample(1:100, npoints, replace = TRUE)/color_denom
    a <- data.frame(x = xx, y = yy, rand_w = rand_w, rand_o = rand_o, rand_c = rand_c)
    
    return(a)
}

Now playing around with the new parameters, I decided to go with this plot:

set.seed(1111)

dat <- 
  genFun(c(0, 0), npoints = 5000, c1 = 5, c2 = -3, c3 = 5, c4 = 2, size_denom = 1.5, opacity_denom = 50)

dat %>% 
  ggplot(aes(x, y,  color = rand_c)) +
  geom_point(size = dat$rand_w,
             alpha = dat$rand_o) +
  scale_color_viridis(option = "magma") +
  dark_theme_void() +
  theme(legend.position = "none") # remove legend

What this allows us to do is change up the generative function and build on our plot. I was interested in rotating the plot around the axis.

dat %>% 
  ggplot() +
  geom_point(aes(x, y,  color = rand_c),
             size = dat$rand_w,
             alpha = dat$rand_o) +
  geom_point(aes(-x, -y,  color = rand_c),
             size = dat$rand_w,
             alpha = dat$rand_o) +
  geom_point(aes(-y, x,  color = rand_c),
             size = dat$rand_w,
             alpha = dat$rand_o) +
  geom_point(aes(-y, -x,  color = rand_c),
             size = dat$rand_w,
             alpha = dat$rand_o) +
  scale_color_viridis(option = "magma") +
  dark_theme_void() +
  theme(legend.position = "none") # remove legend

# ggsave(here::here("public", "img", "rtistry2.png"), dpi = 320, height = 6, width = 8) + # this sames the image

Tada! My first ever #rtistry plot.

< section id="conclusion" class="level2">

Conclusion

This was my attempt to create generative art in R! It was fun to figure out how on earth to even get started and see how the plots change with new parameters on different attempts. I welcome any thoughts and please share your art using the #rtistry hashtag with me!

< section id="rtists-i-follow" class="level3">

rtists I follow

< section id="packages-for-creating-generative-art" class="level3">

Packages for creating generative art

Liked this article? I’d love for you to retweet!

New post! 📣 Interested in using #rstats to create KidPix-like #generativeart 🎨 ? Check out my first foray into #rtistry using a parametric equation here! 👩🏻‍🎨 https://t.co/ykkddoK5tm

reposted due to typo 😅 pic.twitter.com/V5bFSvDsOR

— Isabella Velásquez (@ivelasq3) May 11, 2021

To leave a comment for the author, please follow the link and comment on their blog: %>% dreams.

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.