Simulating Abstract Art with R

[This article was first published on Decisions and R, 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.

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 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.

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)