My data are visualized in the package ggplot2
via bar plots with several (~10) facets. I want first to split these facets in several rows. I can use function facet_grid()
or facet_wrap()
for this. In the minimal example data here I build 8 facets in two rows (4x2). However I need to adjust scales for different facets, namely: first row contains data on small scale, and in the second row values are bigger. So I need to have same scale for all data in the first row to compare them along the row, and another scale for the second row.
Here is the minimal example and possible solutions.
#loading necessary libraries and example data
library(dplyr)
library(tidyr)
library(ggplot2)
trial.facets<-read.csv(text="period,xx,yy
A,2,3
B,1.5,2.5
C,3.2,0.5
D,2.5,1.5
E,11,13
F,16,14
G,8,5
H,5,4")
#arranging data to long format with omission of the "period" variable
trial.facets.tidied<-trial.facets %>% gather(key=newvar,value=newvalue,-period)
And now plotting itself:
#First variant
ggplot(trial.facets.tidied,aes(x=newvar,y=newvalue,position="dodge"))+geom_bar(stat ="identity") +facet_grid(.~period)
#Second variant:
ggplot(trial.facets.tidied,aes(x=newvar,y=newvalue,position="dodge"))+geom_bar(stat ="identity") +facet_wrap(~period,nrow=2,scales="free")
The results for the first and second variants are as follows:
In both examples we have either free scales for all graphs, or fixed for all graphs. Meanwhile the first row (first 4 facets) needs to be scaled somewhat to 5, and the second row - to 15.
As a solution to use facet_grid()
function I can add a fake variable "row" which specifies, to what row should the corresponding letter belong. The new dataset, trial.facets.row (three lines shown only) would look like as follows:
period,xx,yy,row
C,3.2,0.5,1
D,2.5,1.5,1
E,11,13,2
Then I can perform the same rearrangement into long format, omitting variables "period" and "row":
trial.facets.tidied.2<-trial.facets.row %>% gather(key=newvar,value=newvalue,-period,-row)
Then I arrange facets along variables "row" and "period" in the hope to use the option scales="free_y"
to adjust scales only across rows:
ggplot(trial.facets.tidied.2,aes(x=newvar,y=newvalue,position="dodge"))+geom_bar(stat ="identity") +facet_grid(row~period,scales="free_y")
and - surprise: the problem with scales is solved, however, I get two groups of empty bars, and whole data is again stretched across a long strip:
All discovered manual pages and handbooks (usually using the mpg and mtcars dataset) do not consider such situation of such unwanted or dummy data
I used a combination of your first method (facet_wrap
) & second method (leverage on dummy variable for different rows):
# create fake variable "row"
trial.facets.row <- trial.facets %>% mutate(row = ifelse(period %in% c("A", "B", "C", "D"), 1, 2))
# rearrange to long format
trial.facets.tidied.2<-trial.facets.row %>% gather(key=newvar,value=newvalue,-period,-row)
# specify the maximum height for each row
trial.facets.tidied.3<-trial.facets.tidied.2 %>%
group_by(row) %>%
mutate(max.height = max(newvalue)) %>%
ungroup()
ggplot(trial.facets.tidied.3,
aes(x=newvar, y=newvalue,position="dodge"))+
geom_bar(stat = "identity") +
geom_blank(aes(y=max.height)) + # add blank geom to force facets on the same row to the same height
facet_wrap(~period,nrow=2,scales="free")
Note: based on this reproducible example, I'm assuming that all your plots already share a common ymin at 0. If that's not the case, simply create another dummy variable for min.height & add another geom_blank
to your ggplot.
Looking over SO I encountered a solution which might be a bit tricky - from here
The idea is to create a second fake dataset which would plot a single point at each facet. This point will be drawn in the position, corresponding to the highest desired value for y scale in every case. So heights of scales can be manually adjusted for each facet. Here is the solution for the dataset in question. We want y scale (maximum y value) 5 for the first row, and 17 for the second row. So create
df3=data.frame(newvar = rep("xx",8),
period = c("A","B","C","D","E","F","G","H"),
newvalue = c(5,5,5,5,17,17,17,17))
And now superimpose the new data on our graph using geom_point() .
ggplot(trial.facets.tidied,aes(x=newvar,y=newvalue,position="dodge"))+
geom_bar(stat ="identity") +
facet_wrap(~period,nrow=2,scales="free_y")+
geom_point(data=df3,aes(x=newvar,y=newvalue),alpha=1)
Here what we get:
Here I intentionally draw this extra point to make things clear. Next we need to make it invisible, which can be achieved by setting alpha=0
instead of 1 in the last command.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With