Cami Vinz
Cami Vinz

Reputation: 33

How do I add counts to a stacked bar graph?

Here is my graph so far:

counts <- table(all_study$study, all_study$time_of_day_num)
barplot(counts, main="Distribution of Enrollment Time by Study for 24-25",
        col=c("blue","red","green","yellow","orange"),
        ylab= "Count",  names.arg=c("Night", "Evening", "Day"))
legend(0.2,70, legend=c("MATIC","TCD-2","TROOP","Lublin","Microbiome"), 
       fill=c("orange","yellow","green","red","blue"), cex=0.75)

And here is what the graph looks like:

out

I am trying to figure out how to place the count of each study under each type of day. For example, it looks like there is about 25 Microbiomes under Night and 2 TROOP under Night. So I want the number 25 placed in the center of the blue bar for night and 2 squeezed into the green bar for night.

I have tried text() and things like stat='count' and more.

Upvotes: 3

Views: 85

Answers (2)

Friede
Friede

Reputation: 7979

We can calclate the middle heights ym of each stacked bar with cumsum().

This approach adds 'white' labels. If you do not like it, just remove rect(), use a different colour palette or adjust the opacity in hcl.colors() via it's alpha-argument.

 nr = nrow(counts2)
 b = barplot(counts2, col=hcl.colors(n=nr), ylab='Count', 
             legend.text=row.names(counts2),
             main='Distribution of Enrollment Time by Study for 24-25', 
             args.legend=list(x=4L, y=-7L, horiz=TRUE))
 ym = apply(counts2, 2L, cumsum) - counts2 / 2L
 rect(b-.07, t(ym)-1L, b+.07, t(ym)+1L, col='white')
 text(rep(b, each=nr), ym, labels=t(counts2))

Please adapt the xy-coords in args.legend of barplot() and rect() according to your needs.

Short-cut version

where the qualitative colour palette 'Dark 2' is used.

b = barplot(counts2, col=hcl.colors(n=nrow(counts2)))
ym = apply(counts2, 2L, cumsum) - counts2 / 2L
rect(b-.07, t(ym)-1L, b+.07, t(ym)+1L, col='white')
text(rep(b, each=nrow(counts2)), ym, labels=t(counts2))

Running both nrow(counts2) and t(ym) twice should be tolierable overhead here.


Data

User jay.sf's counts modified to match OP's data in dimension.

counts2 = structure(c(5, 18, 11, 5, 6, 6, 3, 6, 12, 10, 14, 6, 11, 6, 8), dim = c(5L, 3L), dimnames = list(c("MATIC", "TCD-2", "TROOP", "Lublin", "Microbiome"), c("Night", "Evening", "Day")))
> counts2
#>            Night Evening Day
#> MATIC          5       6  14
#> TCD-2         18       3   6
#> TROOP         11       6  11
#> Lublin         5      12   6
#> Microbiome     6      10   8

Upvotes: 0

jay.sf
jay.sf

Reputation: 73562

You could write an ymids() function, that calculates a cumulative sum, where the new element is always halved, i.e. x1/2, x1 + x2/2, x1 + x2 + x3/2, ... .

> ymids <- \(x) {
+   r <- numeric(length(x))
+   for (i in seq_len(length(x))) {
+     if (i == 1) {
+       r[i] <- x[i]/2
+     } else {
+       r[i] <- sum(x[seq_len(i - 1)]) + x[i]/2
+     }
+   }
+   r
+ }
> b <- barplot(counts, col=hcl.colors(4, alpha=.5))
> text(b, t(apply(counts, 2, ymids)), labels=t(counts))

enter image description here

If you really want these grey labels you can invent sth with rect, but IMO it would just clutter the plot and adds no useful information.


Data:

> dput(counts)
structure(c(5L, 18L, 11L, 5L, 6L, 3L, 6L, 12L, 14L, 6L, 11L, 
6L), dim = 4:3)

Upvotes: 2

Related Questions