My goal is to have the same bar widths on every facets. I have tried multiple ways but couldn't get it done. The bar widths in the 1st and 2nd facets are bigger than those in the 3rd facet in the example below. Anyone ran into this problem before? Suggestions are welcome!
library(ggplot2)
dat <- read.table(
text = "ID Value Day Order
AA 0.443 Day1 1
BB 0.110 Day1 2
DD 0.129 Day2 3
BB 0.076 Day2 4
DD 0.500 Day3 5
CC 0.143 Day3 6
AA 0.034 Day3 7",
header = TRUE)
dat
#> ID Value Day Order
#> 1 AA 0.443 Day1 1
#> 2 BB 0.110 Day1 2
#> 3 DD 0.129 Day2 3
#> 4 BB 0.076 Day2 4
#> 5 DD 0.500 Day3 5
#> 6 CC 0.143 Day3 6
#> 7 AA 0.034 Day3 7
ggplot(dat,
aes(Order, Value)) +
geom_col(aes(fill = ID),
position = position_dodge2(width = 0.5, preserve = "single")) +
facet_grid(. ~ Day) +
scale_x_continuous(
breaks = dat$Order,
labels = dat$ID)
Can we take it a step further for cases having more than one row of facets? Ideally, I would love to get all facets of equal size. If facets only have 1 or 2 bars, insert blank (Value = 0) bars to keep their size the same. I know it may be too much to ask for
library(dplyr)
library(ggplot2)
dat <- read.table(
text = "Exp ID Value Day Order
Ex1 AA 0.443 Day1 1
Ex1 BB 0.110 Day1 2
Ex1 DD 0.129 Day2 3
Ex1 BB 0.076 Day2 4
Ex1 DD 0.500 Day3 5
Ex1 CC 0.143 Day3 6
Ex1 AA 0.034 Day3 7
Ex2 BB 0.543 Day1 8
Ex2 AA 0.310 Day1 9
Ex2 CC 0.150 Day1 10
Ex2 DD 0.329 Day2 11
Ex2 BB 0.196 Day2 12
Ex2 AA 0.056 Day2 13
Ex2 BB 0.300 Day3 14
Ex2 CC 0.243 Day3 15
Ex2 DD 0.134 Day3 16",
header = TRUE)
## Try facet for 2 variables
ggplot(dat,
aes(Order, Value)) +
geom_col(aes(fill = ID),
width = 0.8,
position = position_dodge2(width = 0.8, preserve = "single")) +
facet_grid(Exp ~ Day,
scales= "free",
space = "free") +
scale_x_continuous(
breaks = dat$Order,
labels = dat$ID)
For the cowplot approach you could add empty rows to the groups that don't have three rows to force equal sized bars and facets.
For example, here I make a new variable order that is 1 to the max size of each Exp/Day group. Then I can use complete() from tidyr to add a row for any group with less than three observations. I hard-coded the max group size to 3 in complete() by using order = 1:3 (i.e., you need to know what the max group size is).
I set Value to 0 for any new rows and put in a blank for ID (I had to turn ID into a character vector for this). I finish by making a new Order variable with a unique value for every row based on the order of the dataset.
library(tidyr)
dat_complete = dat %>%
group_by(Exp, Day) %>%
mutate(order = 1:n(), ID = as.character(ID) ) %>%
complete(order = 1:3, fill = list(Value = 0, ID = "")) %>%
ungroup() %>%
mutate(Order = 1:n())
dat_complete
# A tibble: 18 x 6
Exp Day order ID Value Order
<fct> <fct> <int> <chr> <dbl> <int>
1 Ex1 Day1 1 AA 0.443 1
2 Ex1 Day1 2 BB 0.11 2
3 Ex1 Day1 3 "" 0 3
4 Ex1 Day2 1 DD 0.129 4
5 Ex1 Day2 2 BB 0.076 5
6 Ex1 Day2 3 "" 0 6
7 Ex1 Day3 1 DD 0.5 7
8 Ex1 Day3 2 CC 0.143 8
9 Ex1 Day3 3 AA 0.034 9
10 Ex2 Day1 1 BB 0.543 10
11 Ex2 Day1 2 AA 0.31 11
12 Ex2 Day1 3 CC 0.15 12
13 Ex2 Day2 1 DD 0.329 13
14 Ex2 Day2 2 BB 0.196 14
15 Ex2 Day2 3 AA 0.056 15
16 Ex2 Day3 1 BB 0.3 16
17 Ex2 Day3 2 CC 0.243 17
18 Ex2 Day3 3 DD 0.134 18
You'd have more work to do to control your colors to get rid of the empty ID and maybe do something about the extra tick marks, but your panels would all be the same width.
Note even if making a plot for one Exp at a time for use in cowplot you can use facet_grid() to add the facet label.