Ben
Ben

Reputation: 1154

Method Needed to Create Annotation Function for ggplot

I am creating a plot with multiple annotations, so I wrote a function to simplify that process. The ggplot() below shows the laborious annotate() commands for one "Szarkowski". Since I'm going to add multiple segments and text, I created the af function (also shown below). However, I throw a "cannot add ggproto objects together" error when using the function.

How do I create my annotation function properly?

Data

df<-structure(list(
  Department = structure(c(8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L), .Label = c("Architecture & Design", "Architecture & Design - Image Archive", 
    "Drawings & Prints", "Film", "Fluxus Collection", "Media and Performance", "Painting & Sculpture", "Photography"), class = "factor"), 
  Year = c(1970, 1967, 1960, 1960, 1960, 1960, 1970, 1970, 1970, 1970, 1970), 
  Gender2 = c("Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female"), 
  Nationality2 = c(" American ", " American ", " American ", " American ", " American ", " American ", " American ", " American ", 
                               " American ", " American ", " American "), 
  YearDate = structure(c(20491200, -74203200, -295041600, -295041600, -295041600, -295041600, 20491200, 20491200, 20491200, 20491200, 20491200), class = c("POSIXct", "POSIXt"), tzone = ""), 
  American = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("American", "Not American"), class = "factor")), row.names = 5600:5610, class = "data.frame")

Here is my Annotation function:

af<-function(s_yr,e_yr,y_pos,lab){
  annotate(geom="point",x=as.POSIXct( as.Date(paste0(s_yr,"-01-01"))), y=y_pos,color='black',size=1)+
  annotate(geom="point",x=as.POSIXct( as.Date(paste0(e_yr,"-01-01"))), y=y_pos,color='black',size=1)+
  annotate(geom="segment",
       x=as.POSIXct( as.Date(paste0(s_yr,"-01-01"))), 
       xend=as.POSIXct( as.Date(paste0(e_yr,"-01-01"))),
       y=y_pos,yend=y_pos,color='black',size=1)+
  annotate(geom="text",x=as.POSIXct( as.Date(s_yr("-01-01"))), y=y_pos+20,color='black',size=3,label=lab)    }

Here is my ggplot() command, with the annotation function commented out

df %>%
ggplot(aes(YearDate,fill=Gender2))+geom_bar()+
  scale_fill_calc()+
  xlab("Date")+ylab("Count")+
  #Szarkowski annotation -- this hard coding works fine
  annotate(geom="point",x=as.POSIXct( as.Date("1962-01-01")), y=600,color='black',size=1)+
  annotate(geom="point",x=as.POSIXct( as.Date("1991-01-01")), y=600,color='black',size=1)+
  annotate(geom="segment",
           x=as.POSIXct( as.Date("1962-01-01")), 
           xend=as.POSIXct( as.Date("1991-01-01")),
       y=600,yend=600,color='black',size=1)+
  annotate(geom="text",x=as.POSIXct( as.Date("1978-01-01")), y=620,color='black',size=3,label="Szarkowski")+
  # cannot add `ggproto` objects together
  # af(1970,1990,777,"FakeLabel") +   # this line throws an error; how to fix `af` function?
  theme_minimal()

Upvotes: 3

Views: 255

Answers (1)

teunbrand
teunbrand

Reputation: 38063

RE: comments

Here is what I mean exactly. Remove all the +es from the af() function and instead put all the annotations in a list. Putting components in a list does not only work for annotations, but can be convenient for recycling any number of plot components for multiple plots. This is due to the ggplot2:::ggplot_add.list() method that implicitly + es all the list elements to the plot.

library(ggplot2)

df<-structure(list(
  Department = structure(c(8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L), .Label = c("Architecture & Design", "Architecture & Design - Image Archive", 
    "Drawings & Prints", "Film", "Fluxus Collection", "Media and Performance", "Painting & Sculpture", "Photography"), class = "factor"), 
  Year = c(1970, 1967, 1960, 1960, 1960, 1960, 1970, 1970, 1970, 1970, 1970), 
  Gender2 = c("Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female", "Female"), 
  Nationality2 = c(" American ", " American ", " American ", " American ", " American ", " American ", " American ", " American ", 
                               " American ", " American ", " American "), 
  YearDate = structure(c(20491200, -74203200, -295041600, -295041600, -295041600, -295041600, 20491200, 20491200, 20491200, 20491200, 20491200), class = c("POSIXct", "POSIXt"), tzone = ""), 
  American = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("American", "Not American"), class = "factor")), row.names = 5600:5610, class = "data.frame")

af<-function(s_yr,e_yr,y_pos,lab) {
  list(annotate(geom="point",
                x=as.POSIXct( as.Date(paste0(s_yr,"-01-01"))), 
                y=y_pos,color='black',size=1),
       annotate(geom="point",
                x=as.POSIXct( as.Date(paste0(e_yr,"-01-01"))), 
                y=y_pos,color='black',size=1),
       annotate(geom="segment",
                x=as.POSIXct( as.Date(paste0(s_yr,"-01-01"))), 
                xend=as.POSIXct( as.Date(paste0(e_yr,"-01-01"))),
                y=y_pos,yend=y_pos,color='black',size=1),
       annotate(geom="text",x=as.POSIXct( as.Date(paste0(s_yr, "-01-01"))), 
                y=y_pos+20,color='black',size=3,label=lab)   
  )
}

ggplot(df, aes(YearDate,fill=Gender2))+geom_bar()+
  # scale_fill_calc()+
  xlab("Date")+ylab("Count")+
  #Szarkowski annotation -- this hard coding works fine
  annotate(geom="point",x=as.POSIXct( as.Date("1962-01-01")), y=600,color='black',size=1)+
  annotate(geom="point",x=as.POSIXct( as.Date("1991-01-01")), y=600,color='black',size=1)+
  annotate(geom="segment",
           x=as.POSIXct( as.Date("1962-01-01")), 
           xend=as.POSIXct( as.Date("1991-01-01")),
           y=600,yend=600,color='black',size=1)+
  annotate(geom="text",x=as.POSIXct( as.Date("1978-01-01")), y=620,color='black',size=3,label="Szarkowski")+
  # cannot add `ggproto` objects together
  af(1970,1990,777,"FakeLabel") +
  theme_minimal()

Created on 2021-08-26 by the reprex package (v1.0.0)

Upvotes: 5

Related Questions