tags:

views:

287

answers:

6

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!

+4  A: 

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

Dirk Eddelbuettel
Those crazy kids...
Shane
+1 for callin me a kid. that feels good. Will check latticeExtra though... actually never heard of the Extra
ran2
Call me an old pharte, but I still like base graphics and lattice.
Roman Luštrik
latticeExtra is largely by Felix Andrews who has done wonderful work with extension to lattice --- see his packages playwith and latticist. But as I bemoaned earlier, kids these days have eyes only for Hadley.
Dirk Eddelbuettel
+1  A: 
bigmacprice=rnorm(10)  

names(bigmacprice)=1:10

par(bg="lightblue")
barplot(sort(bigmacprice),
         horiz=T,
         legend="Bunfight!! \nBigmac index \nyadda \nyadda \nmmnnnkay ",
         args.legend = list(  x = "topleft",
                             bty="n"

                            ),
  col='darkblue'
)
This is not exactly a replicate... I'd use text() by the way instead of abusing the legend. If I run it (R2.11.1), the text floating over the bars. Don't think this is what OP had in mind...
Joris Meys
A: 

I know you asked for ggplot but I have no idea how this worked but wanted to do one for me (my way).

And so, I came upon this:

http://code.google.com/apis/visualization/documentation/reference.html#barformatter

Hope you find it interesting!

Good luck!

Trufa

Trufa
+2  A: 

There's a good overview of creating these charts with ggplot2 on the LearnR blog: http://learnr.wordpress.com/2009/06/01/ggplot2-positioning-of-barplot-category-labels/

Brandon Bertelsen
+2  A: 

I think the best (quickest, easiest) way to achieve precise typesetting of an R graphic is to use basic R functions to produce the main detail (use ggplot with geom_bar in this case, or base graphics barplot) and then save the plot to an SVG file. Open the SVG in your favourite editing package (Inkscape impresses me more every time I use it) and then do the final typesetting there.

You can then do things like grab a legend and move it around, delete elements, add text anywhere with any formatting in any font etc.

Spacedman
This contradicts reproducibility principle. You and others wouldn't be able to recreate your plot.
VitoshKa
Not sure about Inkscape but you can programmatically edit images using the GIMP. http://www.gimp.org/tutorials/Basic_Batch/
Richie Cotton
As evidenced by this question, The Economist's plot also violates the reproducibility principle. So to stay faithful to the original, the reproduction should also be unreproducible.
Matt Parker
Huh? We simply don't have their script. What makes you think this cannot be automated? That had been outed as R users (just like the NY Times graphics department).
Dirk Eddelbuettel
+1 for inkscape. I don't agree about reproducibility. Using Inkscape (or any other graphic software) to graphically enhance the plot does not prevent anyone to remake the plot (having the dataset of course). You could do the plot in yellow instead of blue, as long as you have the dataset the plot is reproducible.
nico
+10  A: 

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

eyjo
+1 Nice job, all with the base package too!
Brandon Bertelsen
+1 Spent some time aa?
VitoshKa
datayoda
Sweet. But it needs the white lines under the bars, which is tricky because barplot establishes the plot and puts the bars in and then you cant put things under them. Does barplot have a type='n' option so you can set the axes etc, then add the lines, then add the bars with an add=TRUE parameter? Or maybe the lines could be drawn as extended tick marks...
Spacedman
Can get round this by doing the barplot as normal, splatting the white lines over it, then doing barplot again but with add=TRUE parameter.
Spacedman
Major EXTRA-credit!
datayoda