1

It's often the case I melt my dataframes to show multiple variables on one barplot. The goal is to create a geom_bar with one par for each variable, and one summary label for each bar.

For example, I'll do this:

mtcars$id<-rownames(mtcars)
tt<-melt(mtcars,id.vars = "id",measure.vars = c("cyl","vs","carb"))
ggplot(tt,aes(variable,value))+geom_bar(stat="identity")+
    geom_text(aes(label=value),color='blue')

The result is a barplot in which the label for each bar is repeated for each case (it seems): overlapping labels

What I want to have is one label for each bar, like this:

enter image description here

A common solution is to create aggregated values to place on the graph, like this:

aggr<-tt %>% group_by(variable) %>% summarise(aggrLABEL=mean(value))

ggplot(tt,aes(variable,value))+geom_bar(stat="identity")+
    geom_text(aes(label=aggr$aggrLABEL),color='blue')

or

ggplot(tt,aes(variable,value))+geom_bar(stat="identity")+
    geom_text(label=dplyr::distinct(tt,value),color='blue')

However, these attempts result in errors, respectively:

For solution 1: Error: Aesthetics must be either length 1 or the same as the data (96): label, x, y

For solution 2: Error in [<-.data.frame(*tmp*, aes_params, value = list(label = list( : replacement element 1 is a matrix/data frame of 7 rows, need 96

So, what to do? Setting geom_text to stat="identity" does not help either.

Ben
  • 1,113
  • 10
  • 26
  • It's not clear to me what you are asking. Can you draw your expected output? – Tung Oct 25 '18 at 20:00
  • @Tung I added more details and an image! Thanks for taking another look! – Ben Oct 26 '18 at 13:52
  • You should never use `$` inside `aes()`. Use the `data` argument for different data frames, e.g., `geom_text(data = aggr, aes(label = aggrLABEL),color='blue')`. It's this that causes the length mismatches - if you pull your x coords from `tt`, which has one length, and your labels from `aggr` which has a different length, it can mess things up. – Gregor Thomas Oct 26 '18 at 13:57
  • @Gregor Thanks! I really appreciate the insight on the mechanics of all this. However, if I use `ggplot(tt,aes(variable,value))+geom_bar(stat="identity")+ geom_text(data=aggr, aes(label=~aggrLABEL),color='blue')` I still have an error `Don't know how to automatically scale for object of type formula. Defaulting to continuous. Error in FUN(X[[i]], ...) : object 'value' not found` – Ben Oct 26 '18 at 14:56
  • You added in a `~`. Don't do that. `~` makes it a formula. `aes()` expects bare, unquoted column names, not formulas. – Gregor Thomas Oct 26 '18 at 14:57
  • @Gregor Without the t `~` the error says "object 'value' not found" – Ben Oct 26 '18 at 15:45
  • Looks like you've got a working answer. I'm not trying to solve this in the comments, just prevent future problems that using `$` (or `~`) inside `aes()` will cause. – Gregor Thomas Oct 26 '18 at 15:56

1 Answers1

2

What I would do is create another dataframe with the summary values of your columns. I would then refer to that dataframe in the geom_text line. Like this:

library(tidyverse) # need this for the %>%

tt_summary <- tt %>%
 group_by(variable) %>%
 summarize(total = sum(value))

ggplot(tt, aes(variable, value)) +
geom_col() +
geom_text(data = tt_summary, aes(label = total, y = total), nudge_y = 1) # using nudge_y bc it looks better.

enter image description here

Ben G
  • 4,148
  • 2
  • 22
  • 42