ggplot2:为条形图的构面布局中的行指定不同的比例
ggplot2: specifying different scales for rows in facet layout for bar plots
我的数据在包 ggplot2
中通过具有多个 (~10) 个方面的条形图可视化。我想首先将这些方面分成几行。我可以为此使用函数 facet_grid()
或 facet_wrap()
。在这里的最小示例数据中,我在两行 (4x2) 中构建了 8 个面。但是我需要为不同的方面调整比例,即:第一行包含小比例的数据,第二行的值更大。所以我需要对第一行中的所有数据使用相同的比例以沿行比较它们,并为第二行使用另一个比例。
这是最小示例和可能的解决方案。
#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)
现在正在密谋:
#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")
第一个和第二个变体的结果如下:
在这两个示例中,我们要么为所有图形设置了自由标度,要么为所有图形设置了固定标度。同时,第一行(前 4 个方面)需要缩放到 5,第二行 - 到 15。
作为使用 facet_grid()
函数的解决方案,我可以添加一个假变量 "row" 来指定相应字母应属于哪一行。新数据集 trial.facets.row(仅显示三行)如下所示:
period,xx,yy,row
C,3.2,0.5,1
D,2.5,1.5,1
E,11,13,2
然后我可以对长格式执行相同的重新排列,省略变量 "period" 和 "row":
trial.facets.tidied.2<-trial.facets.row %>% gather(key=newvar,value=newvalue,-period,-row)
然后我沿着变量 "row" 和 "period" 排列分面,希望使用选项 scales="free_y"
仅跨行调整比例:
ggplot(trial.facets.tidied.2,aes(x=newvar,y=newvalue,position="dodge"))+geom_bar(stat ="identity") +facet_grid(row~period,scales="free_y")
而且 - 惊喜:比例尺的问题已经解决,但是,我得到了两组空条,并且整个数据再次被拉伸成一条长条:
所有发现的手册页和手册(通常使用 mpg 和 mtcars 数据集)都没有考虑这种不需要的或虚拟数据的情况
我结合使用了您的第一种方法 (facet_wrap
) 和第二种方法(对不同行的虚拟变量的杠杆作用):
# 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")
注意:基于这个可重现的例子,我假设你所有的地块都已经在 0 处共享一个公共 ymin。如果不是这种情况,只需为 min.height 创建另一个虚拟变量并添加另一个 geom_blank
到你的 ggplot。
查看 SO 我遇到了一个可能有点棘手的解决方案 -
我们的想法是创建第二个假数据集,在每个面上绘制一个点。在每种情况下,该点将绘制在对应于 y 比例的最高期望值的位置。因此,可以为每个方面手动调整比例高度。这是相关数据集的解决方案。我们希望第一行的 y 比例(最大 y 值)为 5,第二行为 17。所以创造
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))
现在使用 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)
这是我们得到的:
这里我特意多画了一个点来说明一下。接下来我们需要让它不可见,这可以通过在最后一个命令中设置 alpha=0
而不是 1 来实现。
这种方法在每行的最大值处绘制一条不可见的线
#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")
# define desired number of columns
n_col <- 4
#assign a row number - mmnsodulo number of colu
trial.facets$row <- seq(0, nrow(trial.facets)-1) %/% n_col
# determine the max by row, and round up to nearest multiple of 5
# join back to original
trial.facets.max <- trial.facets %>%
group_by(row) %>%
summarize(maxvalue = (1 + max(xx, yy) %/% 5) * 5 )
trial.facets <- trial.facets %>% inner_join(trial.facets.max)
# make long format carrying period, row and maxvalue
trial.facets.tidied<-trial.facets %>% gather(key=newvar,value=newvalue,-period,-row,-maxvalue)
# plot an invisible line at the max
ggplot(trial.facets.tidied,aes(x=newvar,y=newvalue,position="dodge"))+
geom_bar(stat ="identity") +
geom_hline(aes(yintercept=maxvalue), alpha = 0) +
facet_wrap(~period,ncol=n_col,scales="free")
我的数据在包 ggplot2
中通过具有多个 (~10) 个方面的条形图可视化。我想首先将这些方面分成几行。我可以为此使用函数 facet_grid()
或 facet_wrap()
。在这里的最小示例数据中,我在两行 (4x2) 中构建了 8 个面。但是我需要为不同的方面调整比例,即:第一行包含小比例的数据,第二行的值更大。所以我需要对第一行中的所有数据使用相同的比例以沿行比较它们,并为第二行使用另一个比例。
这是最小示例和可能的解决方案。
#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)
现在正在密谋:
#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")
第一个和第二个变体的结果如下:
在这两个示例中,我们要么为所有图形设置了自由标度,要么为所有图形设置了固定标度。同时,第一行(前 4 个方面)需要缩放到 5,第二行 - 到 15。
作为使用 facet_grid()
函数的解决方案,我可以添加一个假变量 "row" 来指定相应字母应属于哪一行。新数据集 trial.facets.row(仅显示三行)如下所示:
period,xx,yy,row
C,3.2,0.5,1
D,2.5,1.5,1
E,11,13,2
然后我可以对长格式执行相同的重新排列,省略变量 "period" 和 "row":
trial.facets.tidied.2<-trial.facets.row %>% gather(key=newvar,value=newvalue,-period,-row)
然后我沿着变量 "row" 和 "period" 排列分面,希望使用选项 scales="free_y"
仅跨行调整比例:
ggplot(trial.facets.tidied.2,aes(x=newvar,y=newvalue,position="dodge"))+geom_bar(stat ="identity") +facet_grid(row~period,scales="free_y")
而且 - 惊喜:比例尺的问题已经解决,但是,我得到了两组空条,并且整个数据再次被拉伸成一条长条:
所有发现的手册页和手册(通常使用 mpg 和 mtcars 数据集)都没有考虑这种不需要的或虚拟数据的情况
我结合使用了您的第一种方法 (facet_wrap
) 和第二种方法(对不同行的虚拟变量的杠杆作用):
# 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")
注意:基于这个可重现的例子,我假设你所有的地块都已经在 0 处共享一个公共 ymin。如果不是这种情况,只需为 min.height 创建另一个虚拟变量并添加另一个 geom_blank
到你的 ggplot。
查看 SO 我遇到了一个可能有点棘手的解决方案 -
我们的想法是创建第二个假数据集,在每个面上绘制一个点。在每种情况下,该点将绘制在对应于 y 比例的最高期望值的位置。因此,可以为每个方面手动调整比例高度。这是相关数据集的解决方案。我们希望第一行的 y 比例(最大 y 值)为 5,第二行为 17。所以创造
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))
现在使用 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)
这是我们得到的:
这里我特意多画了一个点来说明一下。接下来我们需要让它不可见,这可以通过在最后一个命令中设置 alpha=0
而不是 1 来实现。
这种方法在每行的最大值处绘制一条不可见的线
#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")
# define desired number of columns
n_col <- 4
#assign a row number - mmnsodulo number of colu
trial.facets$row <- seq(0, nrow(trial.facets)-1) %/% n_col
# determine the max by row, and round up to nearest multiple of 5
# join back to original
trial.facets.max <- trial.facets %>%
group_by(row) %>%
summarize(maxvalue = (1 + max(xx, yy) %/% 5) * 5 )
trial.facets <- trial.facets %>% inner_join(trial.facets.max)
# make long format carrying period, row and maxvalue
trial.facets.tidied<-trial.facets %>% gather(key=newvar,value=newvalue,-period,-row,-maxvalue)
# plot an invisible line at the max
ggplot(trial.facets.tidied,aes(x=newvar,y=newvalue,position="dodge"))+
geom_bar(stat ="identity") +
geom_hline(aes(yintercept=maxvalue), alpha = 0) +
facet_wrap(~period,ncol=n_col,scales="free")