Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wondering how to output a chart I saw in the economist magazine

Tags:

r

ggplot2

I saw this in a recent economist and I was wondering if anyone has code that would help replicate it using ggplot. Economist Chart

alt text Thanks!

like image 818
datayoda Avatar asked Oct 14 '10 22:10

datayoda


People also ask

What does The Economist use for graphs?

The Economist typically only uses a vertical bar chart where the one or two categorical variables are being compared over time. For the data we are working on, a horizontal bar chart would be more appropriate.

What is the best chart to use for comparison?

Bar charts are good for comparisons, while line charts work better for trends. Scatter plot charts are good for relationships and distributions, but pie charts should be used only for simple compositions — never for comparisons or distributions.


2 Answers

I played around a little using only base plot functionality. This is the result:

alt text

Here is the code that produced it:

bigmacprice <- data.frame(
    country = c("Switzerland", "Brazil", "Euro area",
        "Canada", "Japan", "United States",
        "Britain", "Singapore", "South Korea",
        "South Africa", "Mexico", "Thailand",
        "Russia", "Malaysia", "China"),
    price = c(6.78, 5.26, 4.79, 4.18, 3.91, 3.71,
              3.63, 3.46, 3.03, 2.79, 2.58, 2.44,
              2.39, 2.25, 2.18)
)


plotbigmac <- function(mac, base = "United States", xlim = c(-40, 100)) {
    mac <- mac[order(mac$price),]
    base = which(mac$country == base)
    height <- (mac$price / mac[base, "price"] - 1) * 100
    par(bg = "#d0e0e7", col.main = "#262324", col.axis = "#393E46",
        mar = c(8, 8, 6, 6), las = 1)
    barplot(height, width = .1, space = .4,
        names.arg = mac$country, #cex.names = .8,
        col = "#01516c", border = "#7199a8", # border = "#577784",
        horiz = TRUE, xlim = c(-40, 100), axes = FALSE)
    axis(3, lty = 0)
    title(main = "Bunfight\nBig Mac index", col = "#393E46")

    abline(v = seq(-100, 100, 10), col = "white", lwd = 2)
    abline(v = 0, col = "#c8454e", lwd = 2)
    par(xpd = TRUE)
    for (i in 1:nrow(mac)) {
        rect(105, (i - 1) / 7, 118, i / 7 - 0.05,
        col = "white", border = "#7199a8")
        text(112, (i - 1) / 7 + 0.05, mac$price[i], cex = 0.8, col = "#393E46")
    }
    rect(-120, 2.5, -90, 3, col = "#c8454e", border = "#c8454e")
    text(-68, -.2, "Sources:", col = "#393E46")
    text(-64, -.3, "McDonald's;", col = "#393E46")
    text(-60, -.4, "The Economist", col = "#393E46")
}

plotbigmac(bigmacprice)

It might not be the exact match (ex. i don't know how to right align without calling text directly), and if you try to resize it the text will jump around, so you would have to tweak the parameters further to fit your needs. But it goes to show that you can get far with using only basic plot functionality in R.

EDIT: As was commented, the white stripes cross the bars. This is inevitable and cant be adjusted with another call to barplot since that would redraw the plot area. Thus we have to take a peek into the source-code of barplot and customize it for this purpose (love how easy this is in R). But now we have moved outside of the comfy basics in R (i.e. using built in barplot). Here is another go at it:

plotBigMac <- function(mac, base = "United States") {
    old.par <- par(no.readonly = TRUE)
    on.exit(par(old.par))
    # Create data:
    mac <- mac[order(mac$price),]
    base = which(mac$country == base)
    height <- (mac$price / mac[base, "price"] - 1) * 100
    # Costume 'barplot'
    NN <- length(height)
    width <- rep(1, length.out = NN)
    delta <- width / 2
    w.r <- cumsum(width + 0.5)
    w.m <- w.r - delta
    w.l <- w.m - delta
    xlim <- c(range(-.01 * height, height)[1], 100)
    ylim <- c(min(w.l), max(w.r))
    par(bg = "#d0e0e7", col.main = "#262324", col.axis = "#393E46",
        mar = c(8, 8, 6, 6), las = 1, cex = 0.9)
    plot.new()
    plot.window(xlim, ylim)
    abline(v = seq(-100, 100, 20), col = "white", lwd = 2)
    rect(0, w.l, height, w.r, col = "#01516c", border = "#7199a8", lwd = 1)

    # Lines and axis
    abline(v = 0, col = "#c8454e", lwd = 2)
    axis(3, axTicks(3), abs(axTicks(3)), lty = 0)
    axis(2, labels = mac$country, at = w.m, lty = 0)

    # Move outside of plot area
    par(xpd = TRUE)

    # Text misc.
    text(5, (w.l[base] + w.r[base]) / 2, "nil", font = 3)
    text(8, w.r[NN] + 2.3, "+")
    text(-8, w.r[NN] + 2.3, "-")

    # Create price boxes:
    rect(105, w.l, 125, w.r,
        col = "white", border = "#7199a8", lwd = 1)
    text(115, (w.r + w.l)/2, mac$price, cex = 0.8, col = "#393E46")

}

Which creates this:

alt text

like image 163
eyjo Avatar answered Oct 14 '22 13:10

eyjo


The latticeExtra package has a theme styled after The Economist magazine which should help as a start.

However, that uses lattice whereas all the kids these days clamor for ggplot2 ...

like image 36
Dirk Eddelbuettel Avatar answered Oct 14 '22 15:10

Dirk Eddelbuettel