Simulating Abstract Art with R

November 3, 2013

(This article was first published on Decisions and R, and kindly contributed to R-bloggers)

Piet Mondrian Composition with Red, Blue, Black, Yellow, and Gray (1921):

An example draw from my simulation function:

We're in the midst of planning our spring course on Empirical Research Methods, and as a result, I've found myself spending a lot of time thinking about some of the fist ideas in statistics – For example, that the data we observe are actually draws from some (usually unobserved) generating function.

On a recent museum triup, I started thinking about how we could apply this idea to abstract art. Here, I thought, we could think of a particular painting as a single manifestation of some set of generating rules.

Piet Mondrian has a ton of work in a style I thought would be interesting to explore – his work involves combinations of a small number of lines and filled rectangles.

In order to experiment, I decided to write a function which would simulate the (1921) Composition with Red, Blue, Black, Yellow, and Gray (1921) featured above.

My first idea was to maintain the same set lines and colors, while varying (slightly) the locations and widths of those lines – we can think of these locations as parameters drawn from specified distributions. To start, I only use uniform distributions, with means near the values in the original.

For the color, I found a site that extracts hexadecimal colors, which R recognizes.

The result, I think, is interesting. While the variation is still quite constrained, this lets us examine the abstract art.. abstractly (ha!)

Here are a few more draws from the function:

Here is the code for the simulation – (it's a bit of a mess). Feel free to download, experiment with, and improve it!

sim.func = function() {

# pick a place (near the middle) for central anchor line:
left.anchor = runif(1, 40, 60)

width = runif(1, 2, 3)

right.anchor = left.anchor + width

# plot:
plot(0, 0, type = "n", xlim = c(0, 100), ylim = c(0, 10), xaxt = "n", yaxt = "n",
ann = FALSE)

polygon(c(left.anchor, left.anchor, right.anchor, right.anchor), c(-1, 11,
11, -1), col = "#1c1b23")

upper.left = runif(1, 7, 9)
lower.left = runif(1, 2, 5)

small.line.height = runif(1, 0.1, 0.2)

polygon(c(-100, -100, left.anchor, left.anchor), c(lower.left, lower.left +
small.line.height, lower.left + small.line.height, lower.left), col = "#1c1b23")

polygon(c(-100, -100, left.anchor, left.anchor), c(upper.left, upper.left +
small.line.height, upper.left + small.line.height, upper.left), col = "#1c1b23")

polygon(c(-10, -10, left.anchor, left.anchor), c(upper.left + small.line.height,
12, 12, upper.left + small.line.height), col = "#cbccd4")

polygon(c(-10, -10, left.anchor, left.anchor), c(-1, lower.left, lower.left,
-1), col = "#cbccd4")

upper.right = runif(1, 7, 9)

polygon(c(left.anchor, left.anchor, 200, 200), c(upper.right, upper.right +
small.line.height, upper.right + small.line.height, upper.right), col = "#1c1b23")

polygon(c(left.anchor + width, left.anchor + width, 200, 200), c(upper.right +
small.line.height, 20, 20, upper.right + small.line.height), col = "#db5b2c")

polygon(c(-10, -10, left.anchor, left.anchor), c(lower.left + small.line.height,
upper.left, upper.left, lower.left + small.line.height), col = "#273f70")

lowest.left = runif(1, 0.1, 1.2)

polygon(c(-100, -100, left.anchor, left.anchor), c(lowest.left, lowest.left +
small.line.height, lowest.left + small.line.height, lowest.left), col = "#1c1b23")

lh.ref = runif(1, 5, 20)

polygon(c(lh.ref, lh.ref, lh.ref + width, lh.ref + width), c(lowest.left,
upper.left, upper.left, lowest.left), col = "#1c1b23")

lh.mid = lower.left + runif(1, 0.1, 0.4) * (upper.left - lower.left)

polygon(c(lh.ref, lh.ref, 200, 200), c(lh.mid, lh.mid + small.line.height,
lh.mid + small.line.height, lh.mid), col = "#1c1b23")

lowest.right = runif(1, 0.1, 1.6)

polygon(c(left.anchor + width, left.anchor + width, 105, 105), c(lowest.right,
lowest.right + small.line.height, lowest.right + small.line.height,
lowest.right), col = "#1c1b23")

rh.ref = runif(1, 75, 90)

polygon(c(left.anchor + width, left.anchor + width, rh.ref, rh.ref), c(-1,
lowest.right, lowest.right, -1), col = "#1c1b23")

polygon(c(rh.ref, rh.ref, 200, 200), c(-1, lowest.right, lowest.right, -1),
col = "#dccd1e")

polygon(c(right.anchor, right.anchor, 200, 200), c(lowest.right + small.line.height,
lh.mid, lh.mid, lowest.right + small.line.height), col = colors()[358])

polygon(c(right.anchor, right.anchor, 200, 200), c(lh.mid + small.line.height,
upper.right, upper.right, lh.mid + small.line.height), col = "#cbccd4")

top.left = runif(1, 0.1, 0.3) * (10 - upper.left) + upper.left + small.line.height

polygon(c(-100, -100, left.anchor, left.anchor), c(top.left, top.left +
small.line.height, top.left + small.line.height, top.left), col = "#1c1b23")

polygon(c(-100, -100, left.anchor, left.anchor), c(upper.left + small.line.height,
top.left, top.left, upper.left + small.line.height), col = colors()[358])


To leave a comment for the author, please follow the link and comment on their blog: Decisions and R. offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.


Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)