6

I have created a stacked area plot with ggplot2 and added vertical lines at some positions on the x-axis.

I now want to name the sections that are separated by these vertical lines. An example of it could look like it is shown on the example plot. Other solutions are also welcome. I have a vector of breaks (x-axis) and a vector of the names for the intervals.

Code:

library(ggplot2)
d <- read.delim(...)
x_breaks = c(-3999,1,599,4076,7557,11556)

png(output, width=800, height=400)

ggplot(d, aes(x=p, y=c, group=Groups, fill=Groups)) +
geom_area(position="stack") +
opts(title="testtestest",
...) +
scale_x_continuous(expand=c(0,0), breaks=x_breaks) +
scale_y_continuous(expand=c(0,0)) +
geom_vline(xintercept=x_breaks[which(x_breaks != min(x_breaks) & x_breaks != max(x_breaks))])

dev.off()

How to name the sections seperated by the vertical lines?

Uwe
  • 41,420
  • 11
  • 90
  • 134
Matthias Munz
  • 3,583
  • 4
  • 30
  • 47

1 Answers1

6

Without data, it's a bit hard to reproduce your example (your breaks, etc). But the following should get you started.

One fairly straightforward solution is to use ggplot2's annotate() function to add text annotations to the plot panel midway between the vertical lines.

# Load packages
library (ggplot2)
library(grid)

# Some data
df = data.frame(x = 1:10, y = 1:10)

# Base plot
p <- ggplot(df, aes(x,y)) + geom_point() + 
  scale_x_continuous(limits = c(0, 11), expand = c(0,0)) +
  geom_vline(xintercept = 3) + geom_vline(xintercept = 7)

# Add the annotations
p + annotate("text", x = .5*(0+3), y = 11, label = "Part 1") +
     annotate("text", x = .5*(3+7), y = 11, label = "Part 2") +
     annotate("text", x = .5*(7+11), y = 11, label = "Part 3")

The result is:

enter image description here

Or a solution that is close to your example plot as far as the annotations are concerned. It uses annotation_custom() to draw lines and to position text outside the plot panel. Even though the annotations are drawn outside the plot panel, the positioning of the annotations is in terms of the data coordinates. The bottom margin in the base plot is widened to give room for the annotations. The solution requires code to override ggplot's clipping of plot elements to the plot panel.

Update opts is deprecated; using theme instead.

# Base plot
p <- ggplot(df, aes(x,y)) + geom_point() + 
  scale_x_continuous(limits = c(0, 11), expand = c(0,0)) +
  geom_vline(xintercept = 3) + geom_vline(xintercept = 7) +
  theme(plot.margin = unit(c(1,1,4,1), "lines"))

# Create the text Grobs
Text1 = textGrob("Part 1")
Text2 = textGrob("Part 2")
Text3 = textGrob("Part 3")

# Add the annotations
# Segment 1
p1 = p + 
    annotation_custom(grob = linesGrob(), xmin = 0, xmax = 0, ymin = -1, ymax = -.75) +
    annotation_custom(grob = linesGrob(), xmin = 0, xmax = 3, ymin = -1, ymax = -1) +
    annotation_custom(grob = linesGrob(), xmin = 3, xmax = 3, ymin = -1, ymax = -.75) +
    annotation_custom(grob = Text1,  xmin = 0, xmax = 3, ymin = -1.25, ymax = -1.25)

# Segment 2
p1 = p1 + 
    annotation_custom(grob = linesGrob(), xmin = 3, xmax = 7, ymin = -1, ymax = -1) +
    annotation_custom(grob = linesGrob(), xmin = 7, xmax = 7, ymin = -1, ymax = -.75) +
    annotation_custom(grob = Text2,   xmin = 3, xmax = 7, ymin = -1.25, ymax = -1.25) 

# Segment 3
p1 = p1 + 
    annotation_custom(grob = linesGrob(), xmin = 7, xmax = 11, ymin = -1, ymax = -1) +
    annotation_custom(grob = linesGrob(), xmin = 11, xmax = 11, ymin = -1, ymax = -.75) +
    annotation_custom(grob = Text3,  xmin = 7, xmax = 11, ymin = -1.25, ymax = -1.25)

# Code to override clipping
gt <- ggplot_gtable(ggplot_build(p1))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)

The result is:

enter image description here

Sandy Muspratt
  • 31,719
  • 12
  • 116
  • 122
  • This is exactly what I was looking for, thanks a lot. I took your second solution. I want to make y position of the `annotation_custom` dependent on the `ylim` of the plot (`0.25*(top_ylim - bottom_ylim)`). **Do you know how I can get the y limits?** – Matthias Munz Sep 01 '12 at 09:47
  • If I understand correctly: The maximum and minimum values can be obtained using the base R functions `max()` and `min()`. – Sandy Muspratt Sep 01 '12 at 21:19