Max Candocia
Max Candocia

Reputation: 4386

How to use a custom-defined function to change a text label in geom_text()

I have some data, and I want to use some variables from stat_count() to label a bar plot.

This is what I want to do:

library(ggplot2)
library(scales)
percent_and_count <- function(pct, cnt){
  paste0(percent(pct), ' (', cnt, ')')
}

ggplot(aes(x=Type)) + 
 stat_count(aes(y=(..prop))) + 
 geom_text(aes(y=(..prop..), label=percent_and_count(..prop.., ..count))), 
  stat='count')

However, I get this error, since it can't find the function in what I assume is either some base packages or the data frame:

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

I get this error if I do percent(..prop..) as well, although it is fine with scales::percent(..prop..). I did not load my function from a package.

If all else fails, I can do

geom_text(aes(y=(..prop..), label=utils::getAnywhere('percent_and_count')$objs[[1]]((..prop..),(..count..))))

But this seems needlessly roundabout for what should be a stupidly simple task.

Upvotes: 0

Views: 484

Answers (1)

Maurits Evers
Maurits Evers

Reputation: 50668

You can use bquote and aes_:

# Sample data
set.seed(2017);
df <- data.frame(
    Type = sample(6, 100, replace = T)
);

library(ggplot2);
library(scales);

# Your custom function
percent_and_count <- function(pct, cnt){
  paste0(percent(pct), ' (', cnt, ')')
}

ggplot(df, aes(x = Type)) +
 stat_count(aes(y = ..prop..)) +
 geom_text(
     stat = "count",
     aes_(
         y = ~(..prop..), 
         label = bquote(.(percent_and_count)((..prop..), (..count..)))))

enter image description here

Explanation: bquote(.(percent_and_count)(...)) ensures that percent_and_count is found (as terms .(...) are evaluated in the parent environment). We then use aes_ to ensure that quoted expressions (either with ~ or bquote) are properly evaluated.

Still not pretty, but probably more straighforward than using utils::getAnywhere.

Upvotes: 1

Related Questions