Bar marking of individual bars

Is there an easy way to mark individual “blocks” in a “stacked” histogram, for example, the following. I would like the labels to be closer to the top of each block, but my last approach is that they somehow replace the texts for the USA and Mexico, as shown below.

example bar graph

Looking back at the solution, I only found approaches in which the y value for the text must be pre-computed from the outside, which, in addition to additional logic, leads to the problem of controlling the order in which the blocks are stacked ...
I also found this question https://stackoverflow.com/a/3126262/232832 where I got the idea of ​​using geom="text" in stat_bin (see code below)
Here is a snippet of code to illustrate my current approach. I'm not necessarily trying to fix this snippet, any common idiom for shortcuts to be displayed in bar charts! Edit: (in view of two answers this question has received so far)
I would like to emphasize that I would prefer solutions that do not involve a preliminary calculation of the y-position of the text .

 # sample data source df.StackData <- data.frame( QType = c("A4-1", "A4-1", "A4-1", "B3", "B3", "B3"), Country = c("Canada", "USA", "Mexico", "Canada", "USA", "Mexico"), NbOfCases = c(1000, 1320, 380, 400, 1000, 812), AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7), Comment = c("Can", "US", "Mex", "Can", "US", "Mex") ) 

and calling ggplot. It creates the graph shown above with an odd swap of labels (as well as an additional legend), although this problem with the legend is easy to take care of, I just noticed it when preparing this question).

 ggplot(data=df.StackData, aes(x=QType, y=NbOfCases, fill=Country))+ geom_bar(stat="identity", width=1) + stat_bin(geom="text", aes(label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust=1.5, size=3 ) ) 

My initial attempts added geom_text () to the graph as shown below, but of course the y value was wrong (the string texts are relative to the very bottom of the graph, and not this at the bottom of the individual blocks) ...

  ... + geom_text(mapping=aes(x=QType, y=NbOfCases, label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust=1.5), size=3) 
+4
source share
4 answers

Here is the solution. There are two things here. First, you must reorder levels of your data.frame in the same order as in your df.StackData data. Secondly, create another data.frame to calculate y-position by calculating the cumulative amounts of data.

 # reorder levels of factor to the same order as found in data df.StackData$Country <- factor(df.StackData$Country, levels=c("Canada", "USA", "Mexico"), ordered=TRUE) p <- ggplot(data=df.StackData, aes(x=QType, fill=Country)) p <- p + geom_bar(aes(weights=NbOfCases)) # compute corresponding y-axis positions by cumulative sum require(plyr) df <- ddply(df.StackData, .(QType), function(x) { x$NbOfCases <- cumsum(x$NbOfCases) x }) # then use geom_text with data = df (the newly created data) p + geom_text(data = df, aes(x=QType, y=NbOfCases, label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust=1.5), size=3) 

enter image description here

Edit: If you don't want to calculate y-pos yourself, you will have to use stat_bin . Just reorder the Country columns and it works:

 # data df.StackData <- data.frame( QType = c("A4-1", "A4-1", "A4-1", "B3", "B3", "B3"), Country = c("Canada", "USA", "Mexico", "Canada", "USA", "Mexico"), NbOfCases = c(1000, 1320, 380, 400, 1000, 812), AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7), Comment = c("Can", "US", "Mex", "Can", "US", "Mex") ) # just add this: reorder the level df.StackData$Country <- factor(df.StackData$Country, levels=c("Canada", "USA", "Mexico"), ordered=TRUE) # your code again using stat_bin (just changed the width to 0.75) ggplot(data=df.StackData, aes(x=QType, y=NbOfCases, fill=Country))+ geom_bar(stat="identity", width=.75) + stat_bin(geom="text", size=4, aes(label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust=1.5)) 

enter image description here

+2
source

Here is the solution

 df2 = ddply(df.StackData, .(QType), transform, pos = cumsum(NbOfCases) - 0.5 * NbOfCases) ggplot(data = df2, aes(x = QType, y = NbOfCases, fill = Country)) + geom_bar(stat = "identity") + geom_text(aes(y = pos, label = paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" )) ) 

Imgur

+2
source

Here's an alternative - because your factor will be sorted alphabetically by default, I suggest reordering your framework to fit that, rather than reordering your coefficient to fit the order of the data frame. In my opinion, this will allow a more general solution. The only reason you got a legend that you didn’t want was because you had the size inside aes - I fixed it below.

Use of your data:

 df.StackData <- with(df.StackData, df.StackData[order(Country),]) 

and you can just use your original solution with stat_bin . I tested it with a more sophisticated dataset to check if it works:

 df.StackData <- data.frame( QType = rep(c("A4-1","B3"), each = 6), Country = rep(c("Canada", "USA", "Mexico", "UK", "Sweden", "Australia"), times = 2), NbOfCases = c(1000, 1320, 380, 400, 1000, 812, 542, 531, 674, 328, 795, 721), AvgRate = c(17.2, 11.4, 44.21, 17.3, 15.3, 39.7, 21.1, 25.3, 24.1, 31.3, 38.4, 36.1), Comment = rep(c("Can", "US", "Mex", "UK", "Aus", "Swe"), times = 2) ) 

Without sorting:

 ggplot(data=df.StackData, aes(x=QType, y=NbOfCases, fill=Country))+ geom_bar(stat="identity", width=1) + stat_bin(geom="text", aes(label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust = 1),size=3) geom_text(aes(label = Comment), stat="identity") 

enter image description here

After sorting:

df.StackData <- with (df.StackData, df.StackData [order (country),])

enter image description here

+1
source

To remove an extra legend, you can use show_guide=FALSE . In your example:

 ggplot(data=df.StackData, aes(x=QType, y=NbOfCases, fill=Country))+ geom_bar(stat="identity", width=.75) + stat_bin(geom="text", size=4, aes(label=paste("R coef =", formatC(AvgRate, format="f", digits=3), "(", Comment, ")" ), vjust=1.5), show_guide=FALSE) 
+1
source

Source: https://habr.com/ru/post/1469355/


All Articles