Grouped Bar Chart on R Using Ggplot2

Grouped bar plot in ggplot

EDIT: Many years later

For a pure ggplot2 + utils::stack() solution, see the answer by @markus!


A somewhat verbose tidyverse solution, with all non-base packages explicitly stated so that you know where each function comes from:

library(magrittr) # needed for %>% if dplyr is not attached

"http://pastebin.com/raw.php?i=L8cEKcxS" %>%
utils::read.csv(sep = ",") %>%
tidyr::pivot_longer(cols = c(Food, Music, People.1),
names_to = "variable",
values_to = "value") %>%
dplyr::group_by(variable, value) %>%
dplyr::summarise(n = dplyr::n()) %>%
dplyr::mutate(value = factor(
value,
levels = c("Very Bad", "Bad", "Good", "Very Good"))
) %>%
ggplot2::ggplot(ggplot2::aes(variable, n)) +
ggplot2::geom_bar(ggplot2::aes(fill = value),
position = "dodge",
stat = "identity")

The original answer:

First you need to get the counts for each category, i.e. how many Bads and Goods and so on are there for each group (Food, Music, People). This would be done like so:

raw <- read.csv("http://pastebin.com/raw.php?i=L8cEKcxS",sep=",")
raw[,2]<-factor(raw[,2],levels=c("Very Bad","Bad","Good","Very Good"),ordered=FALSE)
raw[,3]<-factor(raw[,3],levels=c("Very Bad","Bad","Good","Very Good"),ordered=FALSE)
raw[,4]<-factor(raw[,4],levels=c("Very Bad","Bad","Good","Very Good"),ordered=FALSE)

raw=raw[,c(2,3,4)] # getting rid of the "people" variable as I see no use for it

freq=table(col(raw), as.matrix(raw)) # get the counts of each factor level

Then you need to create a data frame out of it, melt it and plot it:

Names=c("Food","Music","People")     # create list of names
data=data.frame(cbind(freq),Names) # combine them into a data frame
data=data[,c(5,3,1,2,4)] # sort columns

# melt the data frame for plotting
data.m <- melt(data, id.vars='Names')

# plot everything
ggplot(data.m, aes(Names, value)) +
geom_bar(aes(fill = variable), position = "dodge", stat="identity")

Is this what you're after?

Sample Image

To clarify a little bit, in ggplot multiple grouping bar you had a data frame that looked like this:

> head(df)
ID Type Annee X1PCE X2PCE X3PCE X4PCE X5PCE X6PCE
1 1 A 1980 450 338 154 36 13 9
2 2 A 2000 288 407 212 54 16 23
3 3 A 2020 196 434 246 68 19 36
4 4 B 1980 111 326 441 90 21 11
5 5 B 2000 63 298 443 133 42 21
6 6 B 2020 36 257 462 162 55 30

Since you have numerical values in columns 4-9, which would later be plotted on the y axis, this can be easily transformed with reshape and plotted.

For our current data set, we needed something similar, so we used freq=table(col(raw), as.matrix(raw)) to get this:

> data
Names Very.Bad Bad Good Very.Good
1 Food 7 6 5 2
2 Music 5 5 7 3
3 People 6 3 7 4

Just imagine you have Very.Bad, Bad, Good and so on instead of X1PCE, X2PCE, X3PCE. See the similarity? But we needed to create such structure first. Hence the freq=table(col(raw), as.matrix(raw)).

Make a grouped barplot from count value in ggplot?

Was able to answer my question thanks to @Jon Spring, closing the aes sooner made the difference!

bike_rides %>%  
group_by(member_casual, month_of_use) %>%
summarize(Count = n()) %>%
ggplot(aes(x=month_of_use, y=Count, fill=member_casual)) +
geom_bar(stat='identity', position= "dodge")

New Graph

Practice makes perfect!

ggplot2: grouped bar graph with groupby results as one bar and the total as second bar

Use a grouped summary to compute yes and total, pivot to long, and map the pivoted column to fill:

library(tidyverse)

df %>%
group_by(col2) %>%
summarize(
yes = sum(col3 == "yes"),
total = n()
) %>%
pivot_longer(
yes:total,
names_to = "response",
values_to = "n"
) %>%
mutate(response = fct_rev(response)) %>%
ggplot() +
geom_col(
aes(col2, n, fill = response),
position = "dodge"
) +
scale_y_continuous(limits = c(0, 3), expand = c(0, 0)) +
scale_fill_manual(values = c("#7570b3", "#1b9e77")) +
theme_classic()

Sample Image

Grouping bar chart by filtered rows (R)

The group aes() solves the problem. Therefore I had to group them with the group = column code.

How do I adjust my tibble to get a grouped bar chart in ggplot2?

You want to use tidyverse to put the data into a useable (and tidy) format, before trying to plot the data.

library(tidyverse)

data <-
data %>%
tidyr::pivot_longer(
cols = c(Views, Interactions, Comments),
names_to = "Section",
values_to = "values"
)

New format

head(data)
# A tibble: 6 × 5
Day Category Type Section values
<int> <chr> <chr> <chr> <int>
1 -3 SpaceForce Share Views 26
2 -3 SpaceForce Share Interactions 0
3 -3 SpaceForce Share Comments 0
4 -2 CyberSecurity Photo_1 Views 99
5 -2 CyberSecurity Photo_1 Interactions 0
6 -2 CyberSecurity Photo_1 Comments 0

Then, you can plot the grouped bar chart.

ggplot(data, aes(fill = Section, y = values, x = Day)) +
geom_bar(position = "dodge", stat = "identity")

Output (though difficult to see most because of the 1 really high value)
Sample Image

Or you could easily plot the Category rather than the day if needed too, by having x = Category instead of x = Day.
Sample Image

If you would like to change the order of the categories, then you can make Category a factor, which you can do without changing the dataframe.

# Create order for the categories. If you want to do it by the number of views, then you can create the list from your dataframe.
level_order <- data %>%
dplyr::filter(Section == "Views") %>%
dplyr::arrange(desc(values)) %>%
pull(Category) %>%
unique()

# Then, set category as a factor and include the ordered categories.
ggplot(data, aes(fill = Section, y = values, x = factor(Category, level = level_order))) +
geom_bar(position = "dodge", stat = "identity")

Sample Image

Grouped bar chart in ggplot

I believe you are looking for something like this:

library(ggplot2)

ggplot(df ) +
geom_col(aes(x = year, y = average_antibiotic, group=imd.quintile, fill=imd.quintile), position = "dodge" )

Sample Image



Related Topics



Leave a reply



Submit