LeWitt ReMix
The third #RecreationThursday challenge involved Sol LeWitt’s Colour Bands (2000), which you can see on this prints catalogue. In short, each piece is square and contains patterns of colourful concentric lines that are arranged into panels of varying shapes with black borders.
Rather than recreate his artworks exactly, I decided to riff on the approach with a (very basic) Shiny app, which adds different types of lines and some randomisation.
You can access it here (until I take it down1):
Alternatively, download and launch it locally via an R session:
shiny::runGitHub(
"viz-recreation", "matt-dray", "main",
"2021-07-01_rt_lewitt/lewitt-remix-app"
)
Or you can go to the app’s source on GitHub.
In the app, you can change a few parameters and then hit the ‘Generate’ button for a new variant, which can be downloaded to your computer. I’ve limited the inputs so that you get relatively ‘sensible’ outputs (whatever that means).
You could create something that looks similar to LeWitt’s original, or go off-piste and create a much larger number of panels or much thicker lines. Have fun!
Read on for an explanation and for some examples.
Approach
Once again, I’ve used only base R functions to generate the outputs, just like my previous #RecreationThursday attempt. I have nothing against other tools, I just don’t care much for dependencies.
The trick
I’ve used a cunning shortcut to mimic LeWitt: rather than draw any lines or shapes, I’ve just over-plotted points of decreasing size and variable colour with R’s built-in plotting characters. For example, 21
is a filled circle, 22
a square and so on. Here’s the shapes I used:
When several of these plotting points are stacked on the same origin, it gives the effect of concentric lines. Here’s an example of plotting 50 unfilled circles of decreasing size on the same point:
# Set variables
shape <- 21 # plotting character
shp_n <- 50 # number of points to plot
shp_x <- 2 # point size multiplier ('thickness')
pal <- rainbow(5) # colours
# Set margins to zero, see only the plot
par(mar = rep(0, 4))
# Plot concentric circles
plot(
x = rep(0, shp_n),
y = rep(0, shp_n),
axes = FALSE,
pch = shape,
cex = shp_x * shp_n:1,
col = pal
)
If these circles are filled from largest to smallest, it will give the impression that lines have been created, when really it is a stack of points. I’ve added in a ‘multiplier’ variable that increases the gap from the edge of one point to the edge of the next smallest. The larger that variable, the large the gap, which in the output makes it look like the ‘lines’ are thicker.
Functions
There are two custom functions in the app: one function uses this point-stacking principle to generate a single-panel LeWitt remix and the other function calls multiple of these panels into a square grid.2
The arguments include the plotting character (circle, diamond, etc), the origin position that the centre of the point-stack will take (named for cardinal directions, like NE
to place the origin in the top-right), the colours, the number of shapes to overplot (you want enough to completely cover the plot surface), the apparent ‘thickness’ of the ‘lines’ in the output, and the width of the box3 that surrounds the image.
Function demos
So here’s a demo of the function4 that generates a single panel. It uses uses the triangle plotting characters, which originate in the centre and alternate through rainbow colours. This is not too dissimilar from LeWitt’s originals.
# Grab the functions from the repo
source("https://raw.githubusercontent.com/matt-dray/viz-recreation/main/2021-07-01_rt_lewitt/lewitt-remix-app/global.R")
# Demo: plot a single panel
just_lewitt(
shape = 24, # triangle plotting character
place = "C", # 'centre'
pal = rainbow(7), # colours
shp_n = 200, # number of points to plot
shp_x = 4, # 'line thickness'
box_w = 20 # outer box thickness
)
And below is a panel made of four calls to the single-panel function. Elements like shape and the placement of the origin point are randomised.
Also, rather than use LeWitt’s colouring scheme, I decided to randomise the colour palette by sampling seven colours from R’s built-in named colours()
. This can produce some pretty garish results, but also some quite pleasing ones too. (I’m colourblind, so your mileage may vary.)
# Set a seed for reproducibility
set.seed(5)
# Set up a colour palette
my_pal <- sample(colours(), 7)
# Demo: plot a grid of randomised panels
just_lewitt2(
dimn = 2, # x and y dimensions of grid
pal = my_pal, # colour palette
shp_x = 4, # 'line thickness'
box_w = 10 # outer box thickness
)
This can end up looking like an eye-popping Magic Eye puzzle.
set.seed(7)
just_lewitt2(
dimn = 10,
pal = sample(colours(), 7),
shp_x = 1,
box_w = 0
)
Or a bit like semaphore.
set.seed(7)
just_lewitt2(
dimn = 2,
pal = sample(colours(), 7),
shp_x = 20,
box_w = 0
)
Or whatever this is.
set.seed(2)
just_lewitt2(
dimn = 10,
pal = sample(colours(), 7),
shp_x = 1,
box_w = 20
)
Uh-oh, I think I may have slipped through space-time.
set.seed(11)
just_lewitt2(
dimn = 2,
pal = sample(colours(), 7),
shp_x = 0.4,
box_w = 0
)
The Shiny app basically fills these function arguments with your inputs, providing some randomness with a new seed that’s generated with each click of the ‘Generate’ button or if you move any of the sliders.
You can control the number of panels in the grid, the ‘thickness’ of the lines (which, remember, is just the relative gap between the overlapping plot points) and the thickness of the border (I could have made this value respond to other inputs, but I particularly like ignoring ‘balance’ and choosing extremely thick borders, or none at all).5
I would love it if you tried out the app, used the ‘Download’ button to save a PNG copy6, and then showed me on Twitter.
Get involved
Check out #RecreationThursday on Twitter. It’s a community challenge to recreate an art piece selected each fortnight by a rotating curator.
The timetable, art pieces, curators and example alt-text are available in Sharla Gelfand’s RecreationThursday repo on GitHub.
Session info
## ─ Session info ───────────────────────────────────────────────────────────────
## setting value
## version R version 4.0.3 (2020-10-10)
## os macOS Mojave 10.14.6
## system x86_64, darwin17.0
## ui X11
## language (EN)
## collate en_GB.UTF-8
## ctype en_GB.UTF-8
## tz Europe/London
## date 2021-07-06
##
## ─ Packages ───────────────────────────────────────────────────────────────────
## package * version date lib source
## blogdown 0.21 2020-10-11 [1] CRAN (R 4.0.2)
## bookdown 0.21 2020-10-13 [1] CRAN (R 4.0.2)
## bslib 0.2.4 2021-01-25 [1] CRAN (R 4.0.2)
## cli 2.5.0 2021-04-26 [1] CRAN (R 4.0.2)
## digest 0.6.27 2020-10-24 [1] CRAN (R 4.0.2)
## evaluate 0.14 2019-05-28 [1] CRAN (R 4.0.1)
## highr 0.9 2021-04-16 [1] CRAN (R 4.0.2)
## htmltools 0.5.1.1 2021-01-22 [1] CRAN (R 4.0.2)
## jquerylib 0.1.3 2020-12-17 [1] CRAN (R 4.0.2)
## jsonlite 1.7.2 2020-12-09 [1] CRAN (R 4.0.2)
## knitr 1.32 2021-04-14 [1] CRAN (R 4.0.2)
## magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.0.2)
## R6 2.5.0 2020-10-28 [1] CRAN (R 4.0.2)
## rlang 0.4.11 2021-04-30 [1] CRAN (R 4.0.2)
## rmarkdown 2.7 2021-02-19 [1] CRAN (R 4.0.2)
## sass 0.3.1 2021-01-24 [1] CRAN (R 4.0.2)
## sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.0.2)
## stringi 1.6.1 2021-05-10 [1] CRAN (R 4.0.2)
## stringr 1.4.0 2019-02-10 [1] CRAN (R 4.0.2)
## withr 2.4.2 2021-04-18 [1] CRAN (R 4.0.2)
## xfun 0.22 2021-03-11 [1] CRAN (R 4.0.2)
## yaml 2.2.1 2020-02-01 [1] CRAN (R 4.0.2)
##
## [1] /Users/matt.dray/Library/R/4.0/library
## [2] /Library/Frameworks/R.framework/Versions/4.0/Resources/library
For now it’s hosted on the free version of shinyapps.io, which hosts a limited number of apps per user. I may take it down at some point to make room for an app in future, but the code will be available from the repo.↩︎
LeWitt’s art isn’t just square. Some panels extend the length of the piece, while sometimes the borders aren’t boxes, but follow the edge of the curved lines, for example. I’ve kept to a grid for simplicity.↩︎
Boxes are drawn on a panel-by-panel basis, so the ‘interior’ borders appear thicker because of the additive effect of surrounding boxes.↩︎
These are named like
just_lewitt()
because I like to start functions with verbs and thought it sounded a bit like a certain brand slogan.↩︎Note that there are no inputs for each panel’s plotting-point shape, nor the centre of origin within the panel (top-left, bottom-right, etc), nor the colours. Because chaos.↩︎
The filename of the output includes the date of creation and the values of each slider you selected, so you could get roughly recreate the format of the thing you generated. But I don’t want it to be that easy.↩︎