61

I would like to add a table of the coordinates of highlighted site in a ggplot.

Using a previous question as example data:

set.seed(1)
mydata <- data.frame(a=1:50, b=rnorm(50))
ggplot(mydata,aes(x=a,y=b)) + 
    geom_point(colour="blue") + 
    geom_point(data=mydata[10:13, ], aes(x=a, y=b), colour="red", size=5)

enter image description here

I would like to add the following table to the lower right-hand corner of the plot within the plotting region. Any advice?

table<-cbind(sites=c("site 1","site 2","site 3","site 4"),mydata[10:13,])
table

    sites  a          b
    site 1 10 -0.3053884
    site 2 11  1.5117812
    site 3 12  0.3898432
    site 4 13 -0.6212406
Community
  • 1
  • 1
Elizabeth
  • 6,391
  • 17
  • 62
  • 90

4 Answers4

98

You can use ggplot2's annotation_custom with a tableGrob from the gridExtra package.

library(ggplot2)
library(gridExtra)
set.seed(1)
mydata <- data.frame(a=1:50, b=rnorm(50))
mytable <- cbind(sites=c("site 1","site 2","site 3","site 4"),mydata[10:13,])
k <- ggplot(mydata,aes(x=a,y=b)) + 
  geom_point(colour="blue") + 
  geom_point(data=mydata[10:13, ], aes(x=a, y=b), colour="red", size=5) + 
  annotation_custom(tableGrob(mytable), xmin=35, xmax=50, ymin=-2.5, ymax=-1)

enter image description here

Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • Nice. I'd chop at least four of the decimals from `b` though, unless you really care about 1 part in 10,000 precision (hint: you don't unless flying to Mars). – Spacedman Sep 07 '12 at 13:42
  • @mplourde Thank you! This is a very nice and straight forward solution. To make the table stand out better is it possible to put a frame around it? – Elizabeth Sep 07 '12 at 14:32
  • 1
    take a look at `?tableGrob` to see the aesthetics you can control. Using `show.box=TRUE` will frame the cells. – Matthew Plourde Sep 07 '12 at 14:36
  • 6
    control over aesthetics has changed in the last release, see [the vignette](https://github.com/baptiste/gridextra/wiki/tableGrob) for the various new options. – baptiste Jul 31 '15 at 22:19
  • 2
    is it possible to remove the row numbers while displaying it ? – user3206440 Jan 29 '17 at 02:07
  • is it possible to specify relative positioning , rather than absolute ? – user3206440 Jan 29 '17 at 02:07
  • @user3206440 I don't believe so. You can use `Inf` and `-Inf` to push it to the extremities or the center, but it will fall outside of the plot region. – Matthew Plourde Jan 30 '17 at 14:20
23

With the release of 'ggplot2' 3.0.0 and 'ggpmisc' 0.3.0 a new simpler answer is possible:

library(ggplot2)
library(ggpmisc)

set.seed(1)
mydata <- data.frame(a = 1:50, b = rnorm(50))
table <- cbind(sites=c("site 1", "site 2", "site 3", "site 4"), mydata[10:13, ])

ggplot(mydata, aes(x = a, y = b)) + 
  geom_point(colour = "blue") + 
  geom_point(data = mydata[10:13, ], aes(x = a, y = b), colour = "red", size = 5) +
  annotate(geom = "table", x = 37, y = -0.8, label = list(table), 
           vjust = 1, hjust = 0)

'ggplot2' 3.0.0 fully supports tibbles (see release announcement) making it possible to map a list of data frames to the label aesthetic. The new geom_table() in package 'ggpmisc 0.3.0' takes advantage of this, making the addition of tables with a syntax similar to that of geom_label() possible (see documentation). Here seemed most appropriate to add the table as an annotation, but of course geom_table() can also be used directly, as other ggplot geometries.

enter image description here

Pedro J. Aphalo
  • 5,796
  • 1
  • 22
  • 23
13

@user3206440, @Punintended An easy way of removing row numbers exists: add rows = NULL to the call to tableGrob.

library(ggplot2)
library(gridExtra)
set.seed(1)
mydata <- data.frame(a=1:50, b=rnorm(50))
mytable <- 
   cbind(sites=c("site 1","site 2","site 3","site 4"), mydata[10:13,])
k <- ggplot(mydata,aes(x=a,y=b)) + 
  geom_point(colour="blue") + 
  geom_point(data=mydata[10:13, ], aes(x=a, y=b), colour="red", size=5) + 
  annotation_custom(tableGrob(mytable, rows=NULL), 
                    xmin=35, xmax=50, ymin=-2.5, ymax=-1)

Plot image

Please see the gridExtra Wiki.

Pedro J. Aphalo
  • 5,796
  • 1
  • 22
  • 23
1

@user3206440: I found a work-around that removes row numbers. I formatted my data as a matrix, assigned column names, then had tableGrob call that directly. Whenever I had tableGrob call it as a data frame, the row name persisted.

Below is an example. I'm sure there's an easier way to deal with the chisq.test output

chivalues <- chisq.test(chitable)
chidf <- matrix(c(unlist(c(round(as.numeric(chivalues[1]), 2),
                    chivalues[2], round(as.numeric(chivalues[3]), 5), numcells))),
                   nrow = 1, ncol = 4, byrow = FALSE)
colnames(chidf) <- c("Chi-Squared", "DF", "P Value", "Total Cells")

And then later...

annotation_custom(tableGrob(chidf), xmin=2, xmax=6, ymin=700, ymax=800)
Punintended
  • 727
  • 3
  • 7