Reputation: 2481
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:
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
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
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