Reputation: 23
I have the following data frame
A <- c(2020, 2020, 2020, 2021, 2021, 2021)
B <- c("category 1", "category 2", "category 3", "category 1", "category 2", "category 3")
C <- c(7, 10, 5, 11, 8, 7)
data <- data.frame(A, B, C)
names(data) <- c("yeat", "categories", "value")
How can I plot a horizontal bar chart, that will look like this (i.e., the categories are sorted by their values for each year):
Upvotes: 2
Views: 379
Reputation: 12410
How about using r-plotly as the plotting library?
library(plotly)
library(dplyr)
#your sample data
A <- c(2020, 2020, 2020, 2021, 2021, 2021)
B <- c("category 1", "category 2", "category 3", "category 1", "category 2", "category 3")
C <- c(7, 10, 5, 11, 8, 7)
data <- data.frame(A, B, C)
names(data) <- c("year", "categories", "value")
#subplotting function
sub_plotting <- . %>%
#create horizontal bar chart with custom colors and size
plot_ly(x = ~value, y = ~categories,
type="bar", orientation="horizontal",
color = ~categories, colors = c('#3C79A7', '#8ECBE9', '#FB4C58'),
width = 1500, height = 300) %>%
#add title to subplot
add_annotations(text = ~year,
x = 0.5, y = 0.98,
xref = "paper", yref = "paper",
xanchor = "center", yanchor = "bottom",
showarrow = FALSE,
font = list(size = 25)) %>%
#and sort values
layout(yaxis=list('categoryorder'='total ascending'), showlegend=FALSE)
#apply this to grouped data
fig <- data %>%
group_by(year) %>%
do(p = sub_plotting(.)) %>%
subplot()
print(fig)
The definitions of the custom colors are shamelessly stolen from this answer.
Upvotes: 0
Reputation: 72758
Use barplot
in an lapply
. split
the data by year
and plot the value
s according to their order
. We also give the bars col=
ors according to this scheme as well as labels using mtext
.
Colors and labels may be conveniently stored in a matrix m
with row names by categories that we can easily match later.
(m <- matrix(c('#3C79A7', '#8ECBE9', '#FB4C58',
"Category 1", "Category 2", "Category 3"), 3, 2,
dimnames=list(sort(unique(data$categories)), NULL)))
# [,1] [,2]
# category 1 "#3C79A7" "Category 1"
# category 2 "#8ECBE9" "Category 2"
# category 3 "#FB4C58" "Category 3"
S <- split(data, data$year)
op <- par(mfrow=c(1, 2), mar=c(2, 6, 4, 2)) ## par: 2 plots, expand margins
lapply(names(S), \(x) {
s <- S[[x]]
u <- order(s$value)
barplot(s$value[u], horiz=TRUE, col=m[s$categories[u], 1], border=NA,
main=x[1], xaxt='n', yaxt='n', ylab='')
mtext(m[s$categories[u], 2], 2, 1, at=seq_len(nrow(s)), las=2)
})
par(op) ## reset pars
Data:
data <- structure(list(year = c(2020, 2020, 2020, 2021, 2021, 2021),
categories = c("category 1", "category 2", "category 3",
"category 1", "category 2", "category 3"), value = c(7, 10,
5, 11, 8, 7)), class = "data.frame", row.names = c(NA, -6L
))
Upvotes: 2
Reputation: 41265
You can use this code:
library(tidyverse)
library(forcats)
library(patchwork)
A <- c(2020, 2020, 2020, 2021, 2021, 2021)
B <- c("category 1", "category 2", "category 3", "category 1", "category 2", "category 3")
C <- c(7, 10, 5, 11, 8, 7)
data <- data.frame(A, B, C)
names(data) <- c("yeat", "categories", "value")
p1 <- data %>%
filter(yeat == 2020) %>%
mutate(categories = fct_reorder(categories, value)) %>%
ggplot(aes(x = categories, y = value)) +
geom_col() +
xlab("Categories") +
ylab("") +
ggtitle("2020") +
coord_flip() +
theme(legend.position = "none")
p2 <- data %>%
filter(yeat == 2021) %>%
mutate(categories = fct_reorder(categories, value)) %>%
ggplot(aes(x = categories, y = value)) +
geom_col() +
xlab("Categories") +
ylab("") +
ggtitle("2021") +
coord_flip() +
theme(legend.position = "none")
p1 + p2
Output:
Upvotes: 0