Dec 312009

I have to admit that the previous post on Christmas is actually not much fun. Today I received another pResent from Yixuan which is more interesting:

Basically the code deals with letter polygons (i.e. glyphs) and plot them with proper projections from 3D to 2D space:

## original code by Yixuan <yixuan.qiu@cos.name>, with my slight modification
h.x = c(0.193, 0.295, 0.295, 0.703, 0.703, 0.804, 0.804, 0.703, 0.703,
    0.295, 0.295, 0.193, 0.193)
h.y = c(0.935, 0.935, 0.575, 0.575, 0.935, 0.935, 0.063, 0.063, 0.475,
    0.475, 0.063, 0.063, 0.935)
a1.x = c(0.433, 0.546, 0.865, 0.746, 0.656, 0.328, 0.242, 0.136)
a1.y = c(0.935, 0.935, 0.063, 0.063, 0.326, 0.326, 0.063, 0.063)
a2.x = c(0.488, 0.629, 0.355)
a2.y = c(0.841, 0.418, 0.418)
y.x = c(0.136, 0.259, 0.496, 0.734, 0.853, 0.543, 0.543, 0.441, 0.441)
y.y = c(0.935, 0.935, 0.523, 0.935, 0.935, 0.431, 0.063, 0.063, 0.427)
n.x = c(0.189, 0.295, 0.707, 0.707, 0.804, 0.804, 0.701, 0.287, 0.287, 0.189)
n.y = c(0.935, 0.935, 0.248, 0.935, 0.935, 0.063, 0.063, 0.747, 0.063, 0.063)
e.x = c(0.222, 0.787, 0.787, 0.324, 0.324, 0.757, 0.757, 0.324, 0.324,
    0.804, 0.804, 0.222)
e.y = c(0.935, 0.935, 0.834, 0.834, 0.564, 0.564, 0.464, 0.464, 0.163,
    0.163, 0.063, 0.063)
w.x = c(0, 0.099, 0.254, 0.439, 0.564, 0.738, 0.902, 1, 0.789, 0.687,
    0.5, 0.31, 0.205)
w.y = c(0.935, 0.935, 0.187, 0.935, 0.935, 0.189, 0.935, 0.935, 0.063,
    0.063, 0.826, 0.063, 0.063)
p.x = c(0.218, 0.56, 0.56, 0.56, 0.56, 0.32, 0.32, 0.218, 0.32, 0.32)
p.y = c(0.935, 0.933, 0.832, 0.518, 0.418, 0.418, 0.063, 0.063, 0.518, 0.834)
p.cir.th = seq(pi/2, -pi/2, length.out = 50)
p1.cir.x = 0.56 + 0.2575 * cos(p.cir.th)
p1.cir.y = 0.6755 + 0.2575 * sin(p.cir.th)
p2.cir.x = 0.56 + 0.157 * cos(p.cir.th)
p2.cir.y = 0.6755 + 0.157 * sin(p.cir.th)
p1.x = c(0.218, p1.cir.x, 0.32, 0.32, 0.218)
p1.y = c(0.935, p1.cir.y, 0.418, 0.063, 0.063)
p2.x = c(0.32, p2.cir.x, 0.32)
p2.y = c(0.832, p2.cir.y, 0.518)
r1.cir.th = seq(pi/2, -7/18 * pi, length.out = 50)
r2.cir.th = seq(pi/2, -pi/2, length.out = 50)
r1.cir.x = 0.578 + 0.243 * cos(r1.cir.th)
r1.cir.y = 0.6955 + 0.243 * sin(r1.cir.th)
r2.cir.x = 0.578 + 0.145 * cos(r2.cir.th)
r2.cir.y = 0.6955 + 0.145 * sin(r2.cir.th)
r1.x = c(0.191, r1.cir.x, 0.877, 0.75, 0.54, 0.297, 0.297, 0.191)
r1.y = c(0.937, r1.cir.y, 0.059, 0.059, 0.448, 0.448, 0.059, 0.059)
r2.x = c(0.297, r2.cir.x, 0.297)
r2.y = c(0.841, r2.cir.y, 0.55)
draw.ch = function(x1, y1, x2 = NULL, y2 = NULL, center.x,
    color, alpha, xscale) {
    rgb.col = col2rgb(color)/255
    x1 = x1 * xscale + center.x - 0.5 * xscale
    x2 = x2 * xscale + center.x - 0.5 * xscale
    polygon(x1, y1, col = rgb(rgb.col[1], rgb.col[2], rgb.col[3],
        alpha = alpha), border = NA)
    polygon(x2, y2, col = "black", border = NA)
}
x1 = list(h.x, a1.x, p1.x, p1.x, y.x, n.x, e.x, w.x,
    y.x, e.x, a1.x, r1.x)
y1 = list(h.y, a1.y, p1.y, p1.y, y.y, n.y, e.y, w.y,
    y.y, e.y, a1.y, r1.y)
x2 = list(NULL, a2.x, p2.x, p2.x, NULL, NULL, NULL,
    NULL, NULL, NULL, a2.x, r2.x)
y2 = list(NULL, a2.y, p2.y, p2.y, NULL, NULL, NULL,
    NULL, NULL, NULL, a2.y, r2.y)
th = seq(pi/6, 2 * pi, length.out = 12)
cols = rainbow(200)
## if you don't want to save the animation into SWF,
## just comment the function saveSWF()
library(animation)
saveSWF({
    for (j in 1:238) {
        th = th - pi/120
        center.x = 3 + 5 * cos(th)
        cols = c(cols[-1], cols[1])
        alpha = 0.1 + (50 * (1 - sin(th)))/100
        alpha = ifelse(alpha > 1, 1, alpha)
        xscale = -sin(th) * 1.2
        plot(1, xlim = c(-2, 8), ylim = c(-2.5, 3.5), type = "n")
        plot.order = (1:12)[order(xscale > 0)]
        for (k in 1:12) {
            i = plot.order[k]
            draw.ch(x1[[i]], y1[[i]], x2[[i]], y2[[i]], center.x[i],
                color = cols[k + 60 * ( i >= 6 & i <= 8 ) + 120 *
                    (i > 8)], alpha[i], xscale[i])
        }
        text(8, -2.5, "Yixuan @ 2009-12-31 (http://yixuan.cos.name)",
            adj = c(1, 0), col = "white", cex = 0.8)

    }
}, interval = 0.05, dev = "pdf", para = list(bg = "black", mar = rep(0,
    4)), width = 7, height = 4)
## in the 'fun' package (currently on R-Forge),
## see demo('HappyNewYear2010Yixuan')

Thanks, Yixuan!

By the way, there are even more interesting demos in the fun package, just install the package by install.packages('fun', repos = 'http://r-forge.r-project.org') to see demo(package = 'fun')$results[, 'Item'].

Related Posts

6 Responses to “Happy New Year with R”

Comments (4) Pingbacks (2)
  1. zwdbordeaux says:

    Hi Yihui,
    I would like to ask you for a favor. It will be my superviser’s birthday just several days later. And I would like to send him a piece of code for showing “Happy Birthday” and its translation in French or maybe the translation fo Chinese. Therefore I tried the code that you provied above. It worked not very well: I got the moving letters “Happy new year”, but for the letters “A, R,P” the sealed sapce in the letters were filled with black color which looks not well when I use white as background.
    So, here is my questions:
    1) I didnot find where you define the strings “Happy new year”, therefore I could change them accordingly to “Happy birthday” and other words I want.
    2)How to remove or modify the color filled within the sealed sapce for letters such as “A, R, P”.

    Thank you!
    Happy spring festival!

    • yixuan says:

      1)These letters are recorded in polygon coordinates, that is, the vectors in the beginning of the code.
      2)In the function draw.ch(), change “black” in the last line into your background color.

    • Yihui Xie says:

      1. These letters were drawn by their glyphs, so you need to figure out the locations of each glyph of each letter. That’s a tedious job, but I guess you can find such data somewhere by Google…

      2. See the function polygon() in the code; colors were filled by polygons.

Leave a Reply

(required)

(required)

WWW.YIHUI.NAME XIE@YIHUI.NAME © 2007 - 2010 by Yihui Xie