Ggplot2 Bar Plot with Two Categorical Variables

ggplot2 bar plot with two categorical variables

Fruit <- c(rep("Apple",3),rep("Orange",5))
Bug <- c("worm","spider","spider","worm","worm","worm","worm","spider")

df <- data.frame(Fruit,Bug)

ggplot(df, aes(Fruit, ..count..)) + geom_bar(aes(fill = Bug), position = "dodge")

Sample Image

Double bar plot to compare two categorical variables

You could achieve your desired result by reshaping you data to long format. Using some fake random data:

library(ggplot2)
library(tidyr)

df_long <- df %>%
pivot_longer(c(A1, A2), names_to = "name", values_to = "value")

head(df_long)
#> # A tibble: 6 × 2
#> name value
#> <chr> <chr>
#> 1 A1 equal
#> 2 A2 equal
#> 3 A1 equal
#> 4 A2 less
#> 5 A1 equal
#> 6 A2 less

ggplot(df_long) +
geom_bar(aes(x = value, fill = name), position = "dodge") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

Sample Image

DATA

set.seed(123)
df <- data.frame(
A1 = sample(c("more", "less", "equal"), 100, replace = TRUE),
A2 = sample(c("more", "less", "equal"), 100, replace = TRUE)
)

R barplot of two categorical variables

The easiest way is to pre-process, since we have to calculate the percentages separately by gender. I use complete to make sure we have the zero percent bars explicitly in the data.frame, otherwise ggplot will ignore that bar and widen the other gender's bar.

library(dplyr)
library(tidyr)
df2 <- df %>%
group_by(gender, beverage) %>%
tally() %>%
complete(beverage, fill = list(n = 0)) %>%
mutate(percentage = n / sum(n) * 100)

ggplot(df2, aes(beverage, percentage, fill = gender)) +
geom_bar(stat = 'identity', position = 'dodge') +
theme_bw()

Sample Image

Or the other way around:

df3 <- df %>% 
group_by(beverage, gender) %>%
tally() %>%
complete(gender, fill = list(n = 0)) %>%
mutate(percentage = n / sum(n) * 100)

ggplot(df3, aes(beverage, percentage, fill = gender)) +
geom_bar(stat = 'identity', position = 'dodge') +
theme_bw()

Sample Image

How to use geom_bar and use two categorical variables on the x axis

What about adding facet_wrap and panel.spacing = unit(0, 'lines') to your plot?

ggplot(data)+
geom_bar(aes(y = estimate, x = code, fill = code), stat = "identity")+
geom_errorbar(aes(ymin = estimate - std.error, ymax = estimate + std.error, x = code))+
scale_fill_brewer(palette = "Set1", guide = "none")+
theme_bw()+
ylab("Specifc absorption")+
xlab("Oceanic province")+
ggtitle("Specific absorption") +
facet_wrap(~region, scales = 'free_x') +
theme(panel.spacing = unit(0, 'lines'))

Sample Image


Edit: updated to manually add vertical line and labels

Here is another option for adding the grouping to the bars. Lots of customization can be done with text size, position, color, font, etc.

ggplot(data)+
geom_bar(aes(y = estimate, x = code, fill = code), stat = "identity")+
geom_errorbar(aes(ymin = estimate - std.error, ymax = estimate + std.error, x = code))+
scale_fill_brewer(palette = "Set1", guide = "none")+
theme_bw()+
ylab("Specifc absorption")+
xlab("Oceanic province")+
ggtitle("Specific absorption") +
geom_vline(xintercept = c(4.5, 6.5)) +
annotate(geom = 'text', x = 2.5, y = .07, label = 'Polar') +
annotate(geom = 'text', x = 5.5, y = .07, label = 'Temperate') +
annotate(geom = 'text', x = 8, y = .07, label = 'Equitorial')

Sample Image

ggplot2 barplot for several categorical variables

You can try this. Hoping this can help.

library(reshape2)
library(ggplot2)
#Load your data
Data <- structure(list(ID = c(11L, 25L, 26L, 27L, 29L, 33L, 37L, 39L,
43L, 51L, 53L, 54L, 60L), Word = structure(c(3L, 3L, 2L, 2L,
3L, 1L, 1L, 3L, 3L, 1L, 3L, 3L, 3L), .Label = c("Avanzado", "Básico",
"Intermedio"), class = "factor"), Excel = structure(c(2L, 2L,
3L, 1L, 2L, 2L, 1L, 2L, 2L, 1L, 2L, 2L, 2L), .Label = c("Básico",
"Intermedio", "No la he utilizado"), class = "factor"), Power.Point = structure(c(3L,
3L, 2L, 2L, 3L, 1L, 3L, 4L, 3L, 3L, 3L, 2L, 3L), .Label = c("Avanzado",
"Básico", "Intermedio", "No la he utilizado"), class = "factor"),
Correo.electronico = structure(c(3L, 3L, 2L, 3L, 1L, 1L,
1L, 3L, 3L, 1L, 3L, 1L, 3L), .Label = c("Avanzado", "Básico",
"Intermedio"), class = "factor")), class = "data.frame", row.names = c(NA,
-13L))
#Melt data
Data.Melt <- melt(Data,id.vars = 'ID')
Data.Melt %>% group_by(variable,value) %>% summarise(N=n()) -> Dat1
#Plot
ggplot(Dat1,aes(x=variable,y=N,fill=value,label=N))+
geom_bar(position="stack", stat="identity")+
geom_text(size = 3, position = position_stack(vjust = 0.5))

Sample Image

Barplot with ggplot 2 of two categorical variable facet_wrap according a third variable displayng percentage

It may be easiest to do the data summary yourself so that you can create a column with the percentage labels you want. (Note that as is, I'm not sure what you want your percentages to show- in facet i, group b, there is a column that is nearly 90%, and two columns that are greater than or equal to 50%- is that intended?)

Libraries and your example data frame:

library(ggplot2)
library(dplyr)

test <- data.frame(
test1 = sample(letters[1:2], 100, replace = TRUE),
test2 = sample(letters[3:5], 100, replace = TRUE),
test3 = sample(letters[9:11],100, replace = TRUE )
)

First, group by all columns (note the order), then summarize to get the length of test2. Mutate to get a value for the column height and label-
here I've multiplied by 100 and rounded.

test.grouped <- test %>%
group_by(test1, test3, test2) %>%
summarize(t2.len = length(test2)) %>%
mutate(t2.prop = round(t2.len / sum(t2.len) * 100, 1))

> test.grouped
# A tibble: 18 x 5
# Groups: test1, test3 [6]
test1 test3 test2 t2.len t2.prop
<fctr> <fctr> <fctr> <int> <dbl>
1 a i c 4 30.8
2 a i d 5 38.5
3 a i e 4 30.8
4 a j c 3 20.0
5 a j d 8 53.3
...

Use the summarized data to build your plot, using geom_text to use the proportion column as the label:

ggplot(test.grouped, aes(x = test1, 
y = t2.prop,
fill = test2,
group = test2)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
geom_text(aes(label = paste(t2.prop, "%", sep = ""),
group = test2),
position = position_dodge(width = 0.9),
vjust = -0.8)+
facet_wrap(~ test3) +
scale_y_continuous("Percentage (%)") +
scale_x_discrete("") +
theme(plot.title = element_text(hjust = 0.5), panel.grid.major.x = element_blank())

Sample Image



Related Topics



Leave a reply



Submit