Dr. Mike
Dr. Mike

Reputation: 2481

Why does my user supplied label in geom_text in ggplot2 generate an error?

First some background. I'm trying to create a waterfall plot using ggplot2. I have written the following function that does the trick. However, I have a small issue when trying to provide a user supplied formatting function for the geom_text label.

plotIt<-function()
{
  require(ggplot2)
  require(scales)

  # Define formatting functions
  formatter<-function(x, ...) format(x, big.mark = ' ', trim = TRUE, scientific = FALSE, ...)
  strwr<-function(x) gsub(" ", "\n", x)

  # Build data frame to plot
  mydf<-structure(list(Description = structure(1:6, .Label = LETTERS[1:6], class = "factor"), 
                       change = c(0.86, 0.14, 0.08, -0.05, -0.03, 1.00), 
                       id = 1:6, 
                       end = c(0.86, 1.00, 1.08, 1.03, 1.00, 0.00), 
                       start = c(0, 0.86, 1.00, 1.08, 1.03, 1.00), 
                       type = structure(c(2L, 2L, 2L, 1L, 1L, 2L), .Label = c("Neg", "Pos"), class = "factor")), 
                  .Names = c("Description", "change", "id", "end", "start", "type"), 
                  row.names = LETTERS[1:6], class = "data.frame")

  # Plot it
  ggplot(mydf, aes(Description, fill = type)) + 
    geom_rect(aes(x = Description, xmin = id - 0.45, xmax = id + 0.45, ymin = end, ymax = start)) + 
    scale_y_continuous(labels = formatter) +
    scale_x_discrete("", breaks = levels(mydf$Description), labels = strwr(levels(mydf$Description))) +
    geom_text(aes(x = id, y = end, label = formatter(change)), vjust = 1, size = 3)
}

Calling this function generates the following error message:

Error in eval(expr, envir, enclos) : could not find function "formatter"

The culprit is the label = formatter(change) code in the last row geom_text. If I replace it with label = comma(change) everything works fine. The "comma" function comes from the scales package. So in short:

geom_text(aes(x = id, y = end, label = comma(change)), vjust = 1, size = 3)

works but

geom_text(aes(x = id, y = end, label = formatter(change)), vjust = 1, size = 3)

does not.

The output looks like this: Waterfall plot

Why doesn't geom_text accept my own formatting function? I'm sure it's something simple but I cannot see it.

Upvotes: 2

Views: 2901

Answers (2)

user2030503
user2030503

Reputation: 3104

You may also use the waterfall package. Here's a brief example showing the functionality. I think you wont have to care so much about the formatting.

Upvotes: 0

alexwhan
alexwhan

Reputation: 16026

I think this is an issue with the environment in the ggplot call. If you add environment = environment(), it works:

  ggplot(mydf, aes(Description, fill = type), environment = environment()) + 
    geom_rect(aes(x = Description, xmin = id - 0.45, xmax = id + 0.45, ymin = end, ymax = start)) + 
    scale_y_continuous(labels = formatter) +
    scale_x_discrete("", breaks = levels(mydf$Description), labels = strwr(levels(mydf$Description))) +
    geom_text(aes(x = id, y = end, label = formatter(change)), vjust = 1, size = 3)

As I understand it, this is because the function from scales is available in the global environment, but since you're defining formatter inside the function plotIt(), it is not available.

You can see this by the fact that if you run your code outside a defined function (start from inside your curly brackets), it all works. That is because this puts formatter in the global environment.

As a bit more explanation, you're error message is: Error in eval(expr, envir, enclos) : could not find function "formatter". If you look at the base function eval(), the default envir argument is parent.frame(). If you look at the output from environment(), you see it's <environment: R_GlobalEnv>. So when eval() operates, this tells it to look in the right place.

Upvotes: 2

Related Questions