ggplot 次要 y 轴刻度基于 facet_wrap 或 grid_arrange 的数据
ggplot secondry y axis scale based on data with facet_wrap or grid_arrange
我的数据由时间序列上的 25 个部门组成,我想在折线图中绘制每个部门的工人数量(系列 1)和平均工资(系列 2),第二个 y 轴为工人数量的平均工资和主要 y 轴,然后将图表排列在网格上。
示例数据:
period
avg_wage
number_of_workers
sector
1990
2000
5000
construction
1991
2020
4970
construction
1992
2050
5050
construction
1990
1000
120
IT
1991
1100
400
IT
1992
1080
500
IT
1990
10000
900
hospital staff
1991
10200
980
hospital staff
1992
10400
1200
hospital staff
我尝试对网格使用 facet_wrap() 和 scale_y_continuous(sec.axis...) 如下:
#fake sample data for reference
dfa=data.frame(order=seq(1,100),workers=rnorm(1000,7),pay=rnorm(1000,3000,500),type="a") #1st sector
dfb=data.frame(order=seq(1,100),workers=rnorm(1000,25),pay=rnorm(1000,1000,500),type="b") #2nd sector
dfc=data.frame(order=seq(1,100),workers=rnorm(1000,400),pay=rnorm(1000,5000,500),type="c") #3rd sector
df=rbind(dfa,dfb,dfc)
colnames(df)=c(
"order", #shared x axis/time value
"workers", #time series 1 (y values for left side y axis)
"pay", #time series 2 (y values for left side y axis)
"type" #diffrent graphs to put on the grid
)
ggplotting 数据:
df=df %>% group_by(l=type) %>% mutate(coeff=max(pay)/max(workers)) %>% ungroup() #creating a coefficient to scale the secondry axis
plot=ggplot(data=df,aes(x=order))+
geom_line(aes(y=workers),linetype="dashed",color="red")+
geom_line(aes(y=pay/coeff)) +
scale_y_continuous(sec.axis=sec_axis(~.*coeff2,name="wage"))+
facet_wrap(~type,scale="free")
但不幸的是这不起作用因为你不能在函数sec_axis()中使用数据(这个例子甚至没有运行) .
我尝试的另一种方法是使用 for 循环和 grid.arrange():
plots=list()
for (i in (unique(df$type)))
{
singlesector=df[df$type==i,]
axiscoeff=df$coeff[1]
plot=ggplot(data=singlesector,aes(x=order))+
geom_line(aes(y=workers),linetype="dashed",color="red")+
geom_line(aes(y=pay/coeff)) + labs(title=i)+
scale_y_continuous(sec.axis=sec_axis(~.*axiscoeff,name="wage"))
plots[[i]]=plot
}
grid.arrange(grobs=plots)
但是这也不起作用因为ggplot不保存变量axiscoeff的各种值所以它将第一个值应用于所有图表。
看结果(右边坐标轴乱了,不符合红线的数据):
有什么办法可以做我想做的事吗?
我想也许可以直接将所有图分别保存为 png,而不是以其他方式加入它们,但这似乎是一个极端的解决方案,需要花费太多时间来弄清楚。
据我所知,问题在于您(重新)缩放数据的方式,即使用 max(pay) / max(workers)
重新缩放数据以使 pay
的最大值映射到workers
的最大值,但未考虑变量的不同范围或分布。
相反,您可以使用 scales::rescale
重新缩放数据,使 pay
的范围映射到 workers
.
的范围
除此之外,我还采用了一种不同的方法将这些图粘合在一起,该方法利用了 patchwork
。为此,我将绘图代码放在一个函数中,split
数据 type
,使用 lapply
循环拆分数据,最后使用 [=22= 将图粘合在一起].
注意:由于您的示例数据包含每个 order/type 的多个值,我略微更改了它以摆脱之字形线。
library(dplyr)
library(ggplot2)
library(patchwork)
library(scales)
df %>%
split(.$type) %>%
lapply(function(df) {
range_pay <- range(df$pay)
range_workers <- range(df$workers)
ggplot(data = df, aes(x = order)) +
geom_line(aes(y = workers), linetype = "dashed", color = "red") +
geom_line(aes(y = rescale(pay, range_workers, range_pay))) +
scale_y_continuous(sec.axis = sec_axis(~ rescale(.x, range_pay, range_workers), name = "wage")) +
facet_wrap(~type)
}) %>%
wrap_plots(ncol = 1)
数据
set.seed(123)
dfa <- data.frame(order = 1:100, workers = rnorm(100, 7), pay = rnorm(100, 3000, 500), type = "a") # 1st sector
dfb <- data.frame(order = 1:100, workers = rnorm(100, 25), pay = rnorm(100, 1000, 500), type = "b") # 2nd sector
dfc <- data.frame(order = 1:100, workers = rnorm(100, 400), pay = rnorm(100, 5000, 500), type = "c") # 3rd sector
df <- rbind(dfa, dfb, dfc)
names(df) <- c("order", "workers", "pay", "type")
我的数据由时间序列上的 25 个部门组成,我想在折线图中绘制每个部门的工人数量(系列 1)和平均工资(系列 2),第二个 y 轴为工人数量的平均工资和主要 y 轴,然后将图表排列在网格上。
示例数据:
period | avg_wage | number_of_workers | sector |
---|---|---|---|
1990 | 2000 | 5000 | construction |
1991 | 2020 | 4970 | construction |
1992 | 2050 | 5050 | construction |
1990 | 1000 | 120 | IT |
1991 | 1100 | 400 | IT |
1992 | 1080 | 500 | IT |
1990 | 10000 | 900 | hospital staff |
1991 | 10200 | 980 | hospital staff |
1992 | 10400 | 1200 | hospital staff |
我尝试对网格使用 facet_wrap() 和 scale_y_continuous(sec.axis...) 如下:
#fake sample data for reference
dfa=data.frame(order=seq(1,100),workers=rnorm(1000,7),pay=rnorm(1000,3000,500),type="a") #1st sector
dfb=data.frame(order=seq(1,100),workers=rnorm(1000,25),pay=rnorm(1000,1000,500),type="b") #2nd sector
dfc=data.frame(order=seq(1,100),workers=rnorm(1000,400),pay=rnorm(1000,5000,500),type="c") #3rd sector
df=rbind(dfa,dfb,dfc)
colnames(df)=c(
"order", #shared x axis/time value
"workers", #time series 1 (y values for left side y axis)
"pay", #time series 2 (y values for left side y axis)
"type" #diffrent graphs to put on the grid
)
ggplotting 数据:
df=df %>% group_by(l=type) %>% mutate(coeff=max(pay)/max(workers)) %>% ungroup() #creating a coefficient to scale the secondry axis
plot=ggplot(data=df,aes(x=order))+
geom_line(aes(y=workers),linetype="dashed",color="red")+
geom_line(aes(y=pay/coeff)) +
scale_y_continuous(sec.axis=sec_axis(~.*coeff2,name="wage"))+
facet_wrap(~type,scale="free")
但不幸的是这不起作用因为你不能在函数sec_axis()中使用数据(这个例子甚至没有运行) .
我尝试的另一种方法是使用 for 循环和 grid.arrange():
plots=list()
for (i in (unique(df$type)))
{
singlesector=df[df$type==i,]
axiscoeff=df$coeff[1]
plot=ggplot(data=singlesector,aes(x=order))+
geom_line(aes(y=workers),linetype="dashed",color="red")+
geom_line(aes(y=pay/coeff)) + labs(title=i)+
scale_y_continuous(sec.axis=sec_axis(~.*axiscoeff,name="wage"))
plots[[i]]=plot
}
grid.arrange(grobs=plots)
但是这也不起作用因为ggplot不保存变量axiscoeff的各种值所以它将第一个值应用于所有图表。
看结果(右边坐标轴乱了,不符合红线的数据):
有什么办法可以做我想做的事吗? 我想也许可以直接将所有图分别保存为 png,而不是以其他方式加入它们,但这似乎是一个极端的解决方案,需要花费太多时间来弄清楚。
据我所知,问题在于您(重新)缩放数据的方式,即使用 max(pay) / max(workers)
重新缩放数据以使 pay
的最大值映射到workers
的最大值,但未考虑变量的不同范围或分布。
相反,您可以使用 scales::rescale
重新缩放数据,使 pay
的范围映射到 workers
.
除此之外,我还采用了一种不同的方法将这些图粘合在一起,该方法利用了 patchwork
。为此,我将绘图代码放在一个函数中,split
数据 type
,使用 lapply
循环拆分数据,最后使用 [=22= 将图粘合在一起].
注意:由于您的示例数据包含每个 order/type 的多个值,我略微更改了它以摆脱之字形线。
library(dplyr)
library(ggplot2)
library(patchwork)
library(scales)
df %>%
split(.$type) %>%
lapply(function(df) {
range_pay <- range(df$pay)
range_workers <- range(df$workers)
ggplot(data = df, aes(x = order)) +
geom_line(aes(y = workers), linetype = "dashed", color = "red") +
geom_line(aes(y = rescale(pay, range_workers, range_pay))) +
scale_y_continuous(sec.axis = sec_axis(~ rescale(.x, range_pay, range_workers), name = "wage")) +
facet_wrap(~type)
}) %>%
wrap_plots(ncol = 1)
数据
set.seed(123)
dfa <- data.frame(order = 1:100, workers = rnorm(100, 7), pay = rnorm(100, 3000, 500), type = "a") # 1st sector
dfb <- data.frame(order = 1:100, workers = rnorm(100, 25), pay = rnorm(100, 1000, 500), type = "b") # 2nd sector
dfc <- data.frame(order = 1:100, workers = rnorm(100, 400), pay = rnorm(100, 5000, 500), type = "c") # 3rd sector
df <- rbind(dfa, dfb, dfc)
names(df) <- c("order", "workers", "pay", "type")