4

I'm looking to replicate the design of the first plot seen in this post:

http://stats.blogoverflow.com/2011/12/andyw-says-small-multiples-are-the-most-underused-data-visualization/

This was taken from [1], but in that book there is no code shown for the figure.

This figure in the link has no legend, and instead shows the labels 'IN', 'MO', ect. in a staggered fashion positioned at the height of the respective line they represent. I know how to make plots using ggplot2, but the specific issue I'm having is writing code to make the labels on the right side of the figure like that. Could someone demonstrate how to do this?

1: Carr, Daniel & Linda Pickle. 2009. Visualizing Data Patterns with Micromaps. Boca Rotan, FL. CRC Press.

abruh
  • 81
  • 6
  • 1
    you can also see this for annotating outside the plotting area in ggplot2: http://stackoverflow.com/questions/12409960/ggplot2-annotate-outside-of-plot – Djork Mar 09 '17 at 06:28

2 Answers2

4

This is no easy task, especially to do programmatically. It involves working with grobs, nothing hard, but usually done manually on finished products, rather than generated procedurally.

Data

df <- read.table(text = 'Samples  Day.1 Day.2 Day.3  Day.4
Seradigma335  1.2875 1.350 1.850 1.6125
Seradigma322  0.9375 2.400 1.487 1.8125
Sigma         1.1250 1.962 1.237 2.0500
Shapiro_red   0.7750 1.575 1.362 1.0125
Shapiro_w/red 0.7750 1.837 0.975 0.8250', header = T)

(taken from another question here on SO)

Code

library(tidyr)
library(ggplot2)

tidy_df <- df %>% 
  gather('Day','Value', -Samples)

Simple plot

g <- ggplot(tidy_df) +
  geom_line(aes(Day, Value, group = Samples), show.legend = F) +
  scale_x_discrete(expand = c(.02,0)) +
  scale_y_continuous(limits = c(0,3)) +
  theme_grey() +
  theme(plot.margin = unit(c(0,.2,0,0), 'npc'),
        panel.border = element_rect(color = 'black', fill = NA),
        axis.ticks = element_blank()
        ) 

enter image description here Note the right margin (set with plot.margin = unit(c(0,.2,0,0), 'npc'))

Labels

library(cowplot)

g <- g +
  draw_label(label = df$Samples[1], x = 4.1, y = df$Day.4[1], hjust = 0) +
  draw_label(label = df$Samples[2], x = 4.1, y = df$Day.4[2], hjust = 0) +
  draw_label(label = df$Samples[3], x = 4.1, y = df$Day.4[3], hjust = 0) +
  draw_label(label = df$Samples[4], x = 4.1, y = df$Day.4[4], hjust = 0) +
  draw_label(label = df$Samples[5], x = 4.1, y = df$Day.4[5], hjust = 0)

We added the labels directly to the plot (as opposed to a grob, see documentation), with an x of 4.1, so it's actually just outside the panel (Day.4 has an x of 4) and covered by the margin (it's called clipping).

Remove clipping

# transform to grob
gt <- ggplotGrob(g)

# set panel's clipping to off
gt$layout$clip[gt$layout$name == "panel"] <- "off"

# draw the grob
ggdraw(gt)

enter image description here

Notes

We can kind of speed up the label creation with a for loop:

for (i in 1:nrow(df)) {
  g <- g + draw_label(label = df$Samples[i], x = 4.1, y = df$Day.4[i], hjust = 0)
}

But we can't really map to vars as we are used to with aesthetics.

As I said at the beginning these methods require quite a bit of work to find the right balance and positioning, that can't certainly be expected for a quick plot, but if something has to be published it may be worth.

GGamba
  • 13,140
  • 3
  • 38
  • 47
2

You can use geom_label with the nudge_x argument like this:

library(data.table) # I always use data.table but not required
library(ggplot2)

a <- c(1:10)
b <- c(seq(1,20,2))
c <- c(seq(1,30,3))
d <- c(1:10)

aa <- data.table(a,b,c,d)

ggplot(aa)+
  geom_line(aes(a,b))+
  geom_line(aes(a,c))+
  geom_line(aes(a,d))+
  geom_label(aes(10,10), label = "line 1", nudge_x = 1)+
  geom_label(aes(10,19), label = "line 2", nudge_x = 1)+
  geom_label(aes(10,29), label = "line 3", nudge_x = 1)

You can directly input the ordered pair that corresponds to the desired location of your label. The plot looks like this:

enter image description here

Dodge
  • 3,219
  • 3
  • 19
  • 38