ART FROM CODE

Danielle Navarro

Workshop housekeeping

Schedule for day 1

Time Activity
09:00 - 10:30 Session 1: Get started
10:30 - 11:00 Coffee break
11:00 - 12:30 Session 2: Spatial noise tricks
12:30 - 13:30 Lunch break
13:30 - 15:00 Session 3: Polygon tricks
15:00 - 15:30 Coffee break
15:30 - 17:00 Session 4: Shading tricks

Schedule for day 2

Time Activity
09:00 - 10:30 Session 1: Iterated function systems
10:30 - 11:00 Coffee break
11:00 - 12:30 Session 2: Tiles and tesselations
12:30 - 13:30 Lunch break
13:30 - 15:00 Session 3: Pixel shaders
15:00 - 15:30 Coffee break
15:30 - 17:00 Session 4: Wrap up

Set up, option 1: Local install

  • Create project from Github, e.g.:
usethis::create_from_github(
  repo_spec = "rstudio-conf-2022/art-from-code", 
  destdir = "wherever/you/would/like"
)
  • Within the project, install dependencies:
remotes::install_deps()

Set up, option 2: RStudio cloud

remotes::install_deps()

Say hello!

Get started

Session 1: Hands on introduction to generative art. Make your own pieces using ggplot2 and dplyr

Get started: Topics

Art is theft

Typical ggplot2 output

Slightly styled output

Now is it art?

Technique and art functions

polar_art(seed = 1, n = 500, palette = c("antiquewhite", "orange", "bisque"))
polar_art(seed = 1, n = 500, palette = c("red", "black", "white"))
polar_art(seed = 2, n = 50, palette = c("red", "black", "white"))

Output 1

Output 2

Output 3

Colour and palettes

sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}

Composition and grammar

Multiple data

Multiple copies

Trickery with linetypes

Spatial noise tricks

Session 2: Multidimensional noise generators. Flow fields, fractals, and more using the ambient package

Spatial noise: Topics

Sampling spatial patterns

A spatial pattern expressed as a matrix of zeros, with one column and one row set to 1

Same idea as an image



What if we want fancier patterns? Use ambient!

Our first ambient artwork

  • The recipe:
    • Create blank “canvas” with long_grid()
    • Add “paint” with gen_perlin()
    • Plot image with geom_raster()

Our first system

  • Writing art functions:
    • First, play!
    • Then: what varies?
    • Variable things are arguments

Using dplyr with ambient

blank_canvas |> 
  mutate(
    lf_noise = gen_simplex(x, y, frequency = 1, seed = 1234),
    mf_noise = gen_simplex(x, y, frequency = 20, seed = 1234),
    hf_noise = gen_simplex(x, y, frequency = 99, seed = 1234),
    paint = lf_noise + mf_noise + hf_noise
  )

Fractals in ambient

fractal_art(ridged, gen_simplex, seed = 2, octaves = 1)
fractal_art(ridged, gen_simplex, seed = 2, octaves = 2)
fractal_art(ridged, gen_simplex, seed = 2, octaves = 20)

Curl fields

Simplex noise as surface

Slope of the surface

Curl of the surface

Curl of fractal patterns

Polygon tricks

Session 3: Create textures with recursive polygon deformation, draw wonky hearts as animated gifs, and convert boring lines to textured strokes

Polygon tricks: Topics

Semi-transparent polygons

Part 1: Growing polygons by edge insertion

Semi-transparent polygons

Part 2: Overlaying many nearly-transparent polygons

Optional: Growing polygons a bit faster

  • The TL;DR to a lot of code:
    • Growing vectors in a loop is very slow
    • Adding to lists in a loop is less slow

Example: Splotches

show_multipolygon(splotch_1, "#f51720", alpha = .2)
show_multipolygon(splotch_2, "#f8d210", alpha = .2)
show_multipolygon(splotch_3, "#059dc0", alpha = .2)
show_multipolygon(splotch_4, "#81b622", alpha = .2)

Example: Smudged hexagons

Slightly misshapen objects

Perlin blobs

  tibble(
    angle = seq(0, 2*pi, length.out = n),
    x_base = cos(angle),
    y_base = sin(angle),
    radius = fracture(
      x = x_base, 
      y = y_base, 
      freq_init = freq_init,
      noise = gen_perlin, 
      fractal = fbm, 
      octaves = octaves
    ) |>
      normalise_radius(r_min, r_max),
    x = radius * x_base,
    y = radius * y_base
  )

Perlin hearts

heart_x <- function(angle) {
  x <- (16 * sin(angle) ^ 3) / 17
  return(x - mean(x))
}

heart_y <- function(angle) {
  y <- (13 * cos(angle) - 
      5 * cos(2 * angle) - 
      2 * cos(3 * angle) -
          cos(4 * angle)) / 17
  return(y - mean(y))
}

Animated Perlin hearts

  • The “gifski” recipe:
    • Write a function to generate one plot (“frame”)
    • Call it repeatedly in save_gif()

Textured lines

  • Basic recipe:
    • Dots not lines
    • But have many noisy copies

original

textured

Shading tricks

Session 4: Use rayshader to add depth to 2D plots, and generate 3D graphics from generative art

Shading tricks: Topics

Rayshader art

circle_shadow <- ray_shade(
  heightmap = circle_array,
  sunaltitude = 15, 
  sunangle = 135,
  zscale = .01,
  multicore = TRUE
)

plot_map(circle_shadow, rotate = 270)

Rayshader art

circle_scape <- circle_array |> 
  height_shade() |>
  add_shadow(
    shadowmap = circle_shadow,
    max_darken = .1
  )

plot_map(circle_scape, rotate = 270)

Spatial noise with shadows

Fractured terrain

(Optional) Three dimensional art

Welcome to Day 2

Iterated function systems

Session 1: Embrace the chaotic joy of the fractal flame and render quickly with Rcpp. This one is a bit technical

Iterated function systems: Topics

The Barnsley fern

Chaos game for unboxing

Let’s just chat about…

Tiles and tesselations

Session 2: Make lovely things by subdividing a rectangle, explore Voronoi tesselations, and have a passing encounter with Truchet tiles

Tiles and tesselations: Topics

Rectangle subdivision

Mosaica

Voronoi tesselation

Voronoi baroque

Truchet tiles

Pixel filters

Session 3: Manipulate ggplot objects as if they were raster graphics using ggfx: learn to dither, mask, displace, blend, and more. The flametree package makes as special guest appearance

Pixel filters: topics

Prelude with flametree

tree <- flametree_grow(
  seed = 1, 
  time = 9, 
  angle = c(-15, 15, 30)
)
tree |> 
  flametree_plot(
    background = "#222222", 
    palette = c("#ffffff", "#f652a0")
  )

Adding glow

Dithering an image

Applying a mask

Displacement filters

Image blends

Wrap up

Session 4: In which we end things by making things up as we go along, because this is, after all, an art workshop!