Creating a grouped barplot with two Y axes in R
How about this:
dat <- data.frame(Week = c(1, 2, 3, 4, 5, 6, 7, 8),
SPH = c(2.676, 2.660, 4.175, 2.134, 3.742, 1.395, 4.739, 2.756),
CPH = c(75.35, 29.58, 20.51, 80.43, 97.94, 85.39, 168.61, 142.19))
library(tidyr)
library(dplyr)
## Find minimum and maximum values for each variable
tmp <- dat %>%
summarise(across(c("SPH", "CPH"), ~list(min = min(.x), max=max(.x)))) %>%
unnest(everything())
## make mapping from CPH to SPH
m <- lm(SPH ~ CPH, data=tmp)
## make mapping from SPH to CPH
m_inv <- lm(CPH ~ SPH, data=tmp)
## transform CPH so it's on the same scale as SPH.
## to do this, you need to use the coefficients from model m above
dat <- dat %>%
mutate(CPH = coef(m)[1] + coef(m)[2]*CPH) %>%
## pivot the data so all plotting values are in a single column
pivot_longer(c("SPH", "CPH"),
names_to="var", values_to="vals") %>%
mutate(var = factor(var, levels=c("SPH", "CPH"),
labels=c("Sightings", "Clicks")))
ggplot(dat, aes(x=as.factor(Week), y=vals, fill=var)) +
geom_bar(position="dodge", stat="identity") +
## use model m_inv from above to identify the transformation from the tick values of SPH
## to the appropriate tick values of CPH
scale_y_continuous(sec.axis=sec_axis(trans = ~coef(m_inv)[1] + coef(m_inv)[2]*.x, name="Clicks/hour")) +
labs(y="Sightings/hour", x="Week", fill="") +
theme_bw() +
theme(legend.position="top")
Update - start both axes at zero
To start both axes at zero, you need to change have the values that are used in the linear map both start at zero. Here's an updated full example that does that:
dat <- data.frame(Week = c(1, 2, 3, 4, 5, 6, 7, 8),
SPH = c(2.676, 2.660, 4.175, 2.134, 3.742, 1.395, 4.739, 2.756),
CPH = c(75.35, 29.58, 20.51, 80.43, 97.94, 85.39, 168.61, 142.19))
library(tidyr)
library(dplyr)
## Find minimum and maximum values for each variable
tmp <- dat %>%
summarise(across(c("SPH", "CPH"), ~list(min = min(.x), max=max(.x)))) %>%
unnest(everything())
## set lower bound of each to zero
tmp$SPH[1] <- 0
tmp$CPH[1] <- 0
## make mapping from CPH to SPH
m <- lm(SPH ~ CPH, data=tmp)
## make mapping from SPH to CPH
m_inv <- lm(CPH ~ SPH, data=tmp)
## transform CPH so it's on the same scale as SPH.
## to do this, you need to use the coefficients from model m above
dat <- dat %>%
mutate(CPH = coef(m)[1] + coef(m)[2]*CPH) %>%
## pivot the data so all plotting values are in a single column
pivot_longer(c("SPH", "CPH"),
names_to="var", values_to="vals") %>%
mutate(var = factor(var, levels=c("SPH", "CPH"),
labels=c("Sightings", "Clicks")))
ggplot(dat, aes(x=as.factor(Week), y=vals, fill=var)) +
geom_bar(position="dodge", stat="identity") +
## use model m_inv from above to identify the transformation from the tick values of SPH
## to the appropriate tick values of CPH
scale_y_continuous(sec.axis=sec_axis(trans = ~coef(m_inv)[1] + coef(m_inv)[2]*.x, name="Clicks/hour")) +
labs(y="Sightings/hour", x="Week", fill="") +
theme_bw() +
theme(legend.position="top")
Plotting a bar chart with multiple groups
Styling always involves a bit of fiddling and trial (and sometimes error (;). But generally you could probably get quite close to your desired result like so:
library(ggplot2)
ggplot(example, aes(categorical_var, n)) +
geom_bar(position="dodge",stat="identity") +
# Add some more space between groups
scale_x_discrete(expand = expansion(add = .9)) +
# Make axis start at zero
scale_y_continuous(expand = expansion(mult = c(0, .05))) +
# Put facet label to bottom
facet_wrap(~treatment, strip.position = "bottom") +
theme_minimal() +
# Styling via various theme options
theme(panel.spacing.x = unit(0, "pt"),
strip.placement = "outside",
strip.background.x = element_blank(),
axis.line.x = element_line(size = .1),
panel.grid.major.y = element_line(linetype = "dotted"),
panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank())
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!
Create grouped barplot in R with ordered factor AND individual labels for each bar
We may use
library(gender)
library(dplyr)
library(ggplot2)
gender(as.character(pizza$person)) %>%
select(person = name, gender) %>%
left_join(pizza) %>%
arrange(gender != 'male') %>%
mutate(across(c(person, gender),
~ factor(., levels = unique(.)))) %>%
ggplot(aes(x = person, y = pizzas_eaten, fill = person)) +
geom_bar(stat = 'identity', position = 'dodge') +
facet_wrap(~ gender, scales = 'free_x') +
theme_bw()
-output
Creating a mirrored, grouped barplot?
Try this:
long.dat$value[long.dat$variable == "focal"] <- -long.dat$value[long.dat$variable == "focal"]
library(ggplot2)
gg <- ggplot(long.dat, aes(interaction(volatile, L1), value)) +
geom_bar(aes(fill = variable), color = "black", stat = "identity") +
scale_y_continuous(labels = abs) +
scale_fill_manual(values = c(control = "#00000000", focal = "blue")) +
coord_flip()
gg
I suspect that the order on the left axis (originally x
, but flipped to the left with coord_flip
) will be relevant to you. If the current isn't what you need and using interaction(L1, volatile)
instead does not give you the correct order, then you will need to combine them intelligently before ggplot(..)
, convert to a factor
, and control the levels=
so that they are in the order (and string-formatting) you need.
Most other aspects can be controlled via + theme(...)
, such as legend.position="top"
. I don't know what the asterisks in your demo image might be, but they can likely be added with geom_point
(making sure to negate those that should be on the left).
For instance, if you have a $star
variable that indicates there should be a star on each particular row,
set.seed(42)
long.dat$star <- sample(c(TRUE,FALSE), prob=c(0.2,0.8), size=nrow(long.dat), replace=TRUE)
head(long.dat)
# volatile variable value L1 star
# 1 hexenal3 focal -26 conc1 TRUE
# 2 trans2hexenal focal -27 conc1 TRUE
# 3 trans2hexenol focal -28 conc1 FALSE
# 4 ethyl2hexanol focal -28 conc1 TRUE
# 5 phenethylalcohol focal -31 conc1 FALSE
# 6 methylsalicylate focal -31 conc1 FALSE
then you can add it with a single geom_point
call (and adding the legend move):
gg +
geom_point(aes(y=value + 2*sign(value)), data = ~ subset(., star), pch = 8) +
theme(legend.position = "top")
Related Topics
R - Data Frame - Convert to Sparse Matrix
Unexpected Behaviour with Argument Defaults
Creating a More Continuous Color Palette in R, Ggplot2, Lattice, or Latticeextra
How to Simultaneously Apply Color/Shape/Size in a Scatter Plot Using Plotly
Search for Corresponding Node in a Regression Tree Using Rpart
Error When Exporting Dataframe to Text File in R
Dplyr: Grouping and Summarizing/Mutating Data with Rolling Time Windows
Continuous Color Bar with Separators Instead of Ticks
Equation Numbering in Rmarkdown - for Export to Word
Making Gsub Only Replace Entire Words
Object Not Found Error with Ggplot2
Apply a Summarise Condition to a Range of Columns When Using Dplyr Group_By
How to Merge Multiple Data.Frames and Sum and Average Columns at the Same Time in R
Tidyr Separate Only First N Instances
How Does R Handle Object in Function Call