Ggplot2 text function

I am trying to add group count numbers to my graph. I keep getting the error message "stat_count() must only have an x or y aesthetic.'" Can anyone help? My code snippet is below. Thanks!

activ4_all%>%
ggplot(aes(x=StudyDay, y=VL, fill=death)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = after_stat(count)), stat='count', position = position_fill(vjust = 0.0)) +
theme_classic() +
geom_boxplot(width=0.5, outlier.size=0.2, notch=FALSE, alpha=0.6) +
geom_point(position=position_jitterdodge(dodge.width=0.5), size=1) +
labs(y="Plasma SARS-CoV-2 RNA (log cps/ml)", x="Study Day", title="Plasma RNA - Mortality") +
theme_pubr() +
scale_fill_manual(values=c("1"="black", "0"="seagreen")) +
theme(plot.title=element_text(hjust=0.5), legend.position=c(0.9,0.9), axis.text.x=element_text(colour="black", size=12, face="bold")) +
stat_summary(fun=median, geom="line", aes(group=death), position=position_dodge(0.8), color=c("#8A8A8A"), linetype=2) +
scale_y_continuous(trans=log10_trans(), labels=trans_format("log10", math_format(10^.x)))

I invented some data and I can reproduce your error and then eliminate it by setting inherit.aes = FALSE so geom_text does not get the x and y aesthetics from ggplot().
Without seeing you data, it's hard to give more specific advise.

activ4_all <- data.frame(StudyDay = c("A","A","B","B"),
                         VL = c(4,6,5,7),
                         death = c("Y","N", "Y","N"))
library(ggplot2)
activ4_all |> 
  ggplot(aes(x=StudyDay, y=VL, fill=death)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(label = after_stat(count)), 
            stat='count', position = position_fill(vjust = 0.0)) +
  theme_classic() 
#> Error in `geom_text()`:
#> ! Problem while computing stat.
#> ℹ Error occurred in the 2nd layer.
#> Caused by error in `setup_params()`:
#> ! `stat_count()` must only have an x or y aesthetic.
#> Backtrace:
#>      ▆
#>   1. ├─base::tryCatch(...)
#>   2. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>   3. │   ├─base (local) tryCatchOne(...)
#>   4. │   │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>   5. │   └─base (local) tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
#>   6. │     └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>   7. │       └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>   8. ├─base::withCallingHandlers(...)
#>   9. ├─base::saveRDS(...)
#>  10. ├─base::do.call(...)
#>  11. ├─base (local) `<fn>`(...)
#>  12. └─global `<fn>`(input = base::quote("lucid-carp_reprex.R"))
#>  13.   └─rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")
#>  14.     └─knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
#>  15.       └─knitr:::process_file(text, output)
#>  16.         ├─base::withCallingHandlers(...)
#>  17.         ├─base::withCallingHandlers(...)
#>  18.         ├─knitr:::process_group(group)
#>  19.         └─knitr:::process_group.block(group)
#>  20.           └─knitr:::call_block(x)
#>  21.             └─knitr:::block_exec(params)
#>  22.               └─knitr:::eng_r(options)
#>  23.                 ├─knitr:::in_input_dir(...)
#>  24.                 │ └─knitr:::in_dir(input_dir(), expr)
#>  25.                 └─knitr (local) evaluate(...)
#>  26.                   └─evaluate::evaluate(...)
#>  27.                     └─evaluate:::evaluate_call(...)
#>  28.                       ├─evaluate (local) handle(...)
#>  29.                       │ └─base::try(f, silent = TRUE)
#>  30.                       │   └─base::tryCatch(...)
#>  31.                       │     └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>  32.                       │       └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>  33.                       │         └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>  34.                       ├─base::withCallingHandlers(...)
#>  35.                       ├─base::withVisible(value_fun(ev$value, ev$visible))
#>  36.                       └─knitr (local) value_fun(ev$value, ev$visible)
#>  37.                         └─knitr (local) fun(x, options = options)
#>  38.                           ├─base::withVisible(knit_print(x, ...))
#>  39.                           ├─knitr::knit_print(x, ...)
#>  40.                           └─knitr:::knit_print.default(x, ...)
#>  41.                             └─evaluate (local) normal_print(x)
#>  42.                               ├─base::print(x)
#>  43.                               └─ggplot2:::print.ggplot(x)
#>  44.                                 ├─ggplot2::ggplot_build(x)
#>  45.                                 └─ggplot2:::ggplot_build.ggplot(x)
#>  46.                                   └─ggplot2:::by_layer(...)
#>  47.                                     ├─rlang::try_fetch(...)
#>  48.                                     │ ├─base::tryCatch(...)
#>  49.                                     │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>  50.                                     │ │   └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>  51.                                     │ │     └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>  52.                                     │ └─base::withCallingHandlers(...)
#>  53.                                     └─ggplot2 (local) f(l = layers[[i]], d = data[[i]])
#>  54.                                       └─l$compute_statistic(d, layout)
#>  55.                                         └─ggplot2 (local) compute_statistic(..., self = self)
#>  56.                                           └─self$stat$setup_params(data, self$stat_params)
#>  57.                                             └─ggplot2 (local) setup_params(..., self = self)
#>  58.                                               └─cli::cli_abort("{.fn {snake_class(self)}} must only have an {.field x} {.emph or} {.field y} aesthetic.")
#>  59.                                                 └─rlang::abort(...)

activ4_all |> 
  ggplot(aes(x=StudyDay, y=VL, fill=death)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(x = StudyDay, label = after_stat(count)), 
            stat='count', position = position_fill(vjust = 0.0), 
            inherit.aes = FALSE) +
  theme_classic() 

Created on 2024-02-11 with reprex v2.0.2

This solved the problem, but now I'm not sure how to direct the code to display "n=x" for each bar? When I run the code with my data, the number displayed is the total for all observations per Study Day. Thanks for any advice on this!

If you want to display the n of each group, you need to add a group to geom_text() and set its position to match the dodge of geom_bar().

activ4_all <- data.frame(StudyDay = c("A","A","B","B"),
                         VL = c(4,6,5,7),
                         death = c("Y","N", "Y","N"))
library(ggplot2)


activ4_all |> 
  ggplot(aes(x=StudyDay, y=VL, fill=death)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(x = StudyDay, label = paste("n =", after_stat(count)), 
                group = death), 
            stat='count', position = position_dodge(width = 0.8),
            inherit.aes = FALSE) +
  theme_classic() 

Created on 2024-02-11 with reprex v2.0.2