我需要在一个图表中绘制一个显示计数的柱状图和一个显示率的折线图,我可以分别做这两个,但当我把它们放在一起时,我的第一层(即geom_bar)的比例被第二层(即geom_line)重叠。
我可以将geom_line的轴向右移动吗?
我需要在一个图表中绘制一个显示计数的柱状图和一个显示率的折线图,我可以分别做这两个,但当我把它们放在一起时,我的第一层(即geom_bar)的比例被第二层(即geom_line)重叠。
我可以将geom_line的轴向右移动吗?
这在ggplot2中是不可能的,因为我认为具有单独y尺度的图(不是相互转换的y尺度)从根本上是有缺陷的。一些问题:
The are not invertible: given a point on the plot space, you can not uniquely map it back to a point in the data space. They are relatively hard to read correctly compared to other options. See A Study on Dual-Scale Data Charts by Petra Isenberg, Anastasia Bezerianos, Pierre Dragicevic, and Jean-Daniel Fekete for details. They are easily manipulated to mislead: there is no unique way to specify the relative scales of the axes, leaving them open to manipulation. Two examples from the Junkcharts blog: one, two They are arbitrary: why have only 2 scales, not 3, 4 or ten?
你也可能想要阅读Stephen Few关于双缩放轴在图形中的主题的冗长讨论,它们是最好的解决方案吗?
有时客户想要两个y刻度。给他们“有缺陷”的演讲通常是毫无意义的。但是我喜欢ggplot2坚持以正确的方式做事。我确信ggplot实际上是在向普通用户传授正确的可视化技术。
也许你可以使用面形和无比例来比较两个数据序列?看这里:https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page
下面的文章帮助我将ggplot2生成的两个图合并到单行上:
一页上的多个图(ggplot2)由Cookbook for R
下面是代码在这种情况下的样子:
p1 <-
ggplot() + aes(mns)+ geom_histogram(aes(y=..density..), binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1) + geom_density(alpha=.2)
p2 <-
ggplot() + aes(mns)+ geom_histogram( binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1)
multiplot(p1,p2,cols=2)
Kohske大约在3年前提供了解决这一挑战的技术骨干。在Stackoverflow [id: 18989001, 29235405, 21026598]的几个实例中已经讨论过这个主题及其解决方案的技术细节。因此,我将只提供一个特定的变化和一些解释性演练,使用上述解决方案。
让我们假设我们确实在组G1中有一些数据y1,而组G2中的一些数据y2以某种方式相关,例如范围/比例转换或添加了一些噪声。我们想把数据画在一张图上,左边是y1右边是y2。
df <- data.frame(item=LETTERS[1:n], y1=c(-0.8684, 4.2242, -0.3181, 0.5797, -0.4875), y2=c(-5.719, 205.184, 4.781, 41.952, 9.911 )) # made up!
> df
item y1 y2
1 A -0.8684 -19.154567
2 B 4.2242 219.092499
3 C -0.3181 18.849686
4 D 0.5797 46.945161
5 E -0.4875 -4.721973
如果我们现在把数据画在一起
ggplot(data=df, aes(label=item)) +
theme_bw() +
geom_segment(aes(x='G1', xend='G2', y=y1, yend=y2), color='grey')+
geom_text(aes(x='G1', y=y1), color='blue') +
geom_text(aes(x='G2', y=y2), color='red') +
theme(legend.position='none', panel.grid=element_blank())
它并没有很好地对齐,因为小尺度y1明显被大尺度y2折叠了。
这里应对挑战的技巧是在技术上根据第一个尺度y1绘制两个数据集,但根据二级轴报告第二个数据集,并使用标签显示原始尺度y2。
因此,我们构建了第一个辅助函数CalcFudgeAxis,它计算并收集要显示的新轴的特征。这个函数可以被修改成任意的形式(这个函数只是将y2映射到y1的范围上)。
CalcFudgeAxis = function( y1, y2=y1) {
Cast2To1 = function(x) ((ylim1[2]-ylim1[1])/(ylim2[2]-ylim2[1])*x) # x gets mapped to range of ylim2
ylim1 <- c(min(y1),max(y1))
ylim2 <- c(min(y2),max(y2))
yf <- Cast2To1(y2)
labelsyf <- pretty(y2)
return(list(
yf=yf,
labels=labelsyf,
breaks=Cast2To1(labelsyf)
))
}
什么产生了一些:
> FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )
> FudgeAxis
$yf
[1] -0.4094344 4.6831656 0.4029175 1.0034664 -0.1009335
$labels
[1] -50 0 50 100 150 200 250
$breaks
[1] -1.068764 0.000000 1.068764 2.137529 3.206293 4.275058 5.343822
> cbind(df, FudgeAxis$yf)
item y1 y2 FudgeAxis$yf
1 A -0.8684 -19.154567 -0.4094344
2 B 4.2242 219.092499 4.6831656
3 C -0.3181 18.849686 0.4029175
4 D 0.5797 46.945161 1.0034664
5 E -0.4875 -4.721973 -0.1009335
现在我将Kohske的解决方案包装在第二个辅助函数PlotWithFudgeAxis中(我们将ggplot对象和新轴的辅助对象放入其中):
library(gtable)
library(grid)
PlotWithFudgeAxis = function( plot1, FudgeAxis) {
# based on: https://rpubs.com/kohske/dual_axis_in_ggplot2
plot2 <- plot1 + with(FudgeAxis, scale_y_continuous( breaks=breaks, labels=labels))
#extract gtable
g1<-ggplot_gtable(ggplot_build(plot1))
g2<-ggplot_gtable(ggplot_build(plot2))
#overlap the panel of the 2nd plot on that of the 1st plot
pp<-c(subset(g1$layout, name=="panel", se=t:r))
g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,pp$l)
ia <- which(g2$layout$name == "axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
grid.draw(g)
}
现在可以将所有内容放在一起:下面的代码显示了建议的解决方案如何在日常环境中使用。plot调用现在不再绘制原始数据y2,而是一个克隆版本yf(保存在预先计算的辅助对象FudgeAxis中),它以y1的规模运行。然后使用Kohske的辅助函数PlotWithFudgeAxis操作原始ggplot对象,以添加第二个轴,保留y2的刻度。它的情节和被操纵的情节一样。
FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )
tmpPlot <- ggplot(data=df, aes(label=item)) +
theme_bw() +
geom_segment(aes(x='G1', xend='G2', y=y1, yend=FudgeAxis$yf), color='grey')+
geom_text(aes(x='G1', y=y1), color='blue') +
geom_text(aes(x='G2', y=FudgeAxis$yf), color='red') +
theme(legend.position='none', panel.grid=element_blank())
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
现在它有两个轴,左边是y1右边是y2
Above solution is, to put it straight, a limited shaky hack. As it plays with the ggplot kernel it will throw some warnings that we exchange post-the-fact scales, etc. It has to be handled with care and may produce some undesired behaviour in another setting. As well one may need to fiddle around with the helper functions to get the layout as desired. The placement of the legend is such an issue (it would be placed between the panel and the new axis; this is why I droped it). The scaling / alignment of the 2 axis is as well a bit challenging: The code above works nicely when both scales contain the "0", else one axis gets shifted. So definetly with some opportunities to improve...
如果on想要保存图片,就必须将调用包装成设备打开/关闭:
png(...)
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
dev.off()
从ggplot2 2.2.0开始,您可以添加如下的辅助轴(取自ggplot2 2.2.0公告):
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
scale_y_continuous(
"mpg (US)",
sec.axis = sec_axis(~ . * 1.20, name = "mpg (UK)")
)
Hadley的回答参考了Stephen Few的报告《双缩放轴在图中是最好的解决方案吗?》
我不知道OP中的“counts”和“rate”是什么意思,但快速搜索会给我counts和Rates,所以我得到了一些关于北美登山事故的数据:
Years<-c("1998","1999","2000","2001","2002","2003","2004")
Persons.Involved<-c(281,248,301,276,295,231,311)
Fatalities<-c(20,17,24,16,34,18,35)
rate=100*Fatalities/Persons.Involved
df<-data.frame(Years=Years,Persons.Involved=Persons.Involved,Fatalities=Fatalities,rate=rate)
print(df,row.names = FALSE)
Years Persons.Involved Fatalities rate
1998 281 20 7.117438
1999 248 17 6.854839
2000 301 24 7.973422
2001 276 16 5.797101
2002 295 34 11.525424
2003 231 18 7.792208
2004 311 35 11.254019
然后,我尝试按照Few在上述报告第7页建议的那样绘制图表(并按照OP的要求将计数绘制为柱状图,将率绘制为折线图):
The other less obvious solution, which works only for time series, is to convert all sets of values to a common quantitative scale by displaying percentage differences between each value and a reference (or index) value. For instance, select a particular point in time, such as the first interval that appears in the graph, and express each subsequent value as the percentage difference between it and the initial value. This is done by dividing the value at each point in time by the value for the initial point in time and then multiplying it by 100 to convert the rate to a percentage, as illustrated below.
df2<-df
df2$Persons.Involved <- 100*df$Persons.Involved/df$Persons.Involved[1]
df2$rate <- 100*df$rate/df$rate[1]
plot(ggplot(df2)+
geom_bar(aes(x=Years,weight=Persons.Involved))+
geom_line(aes(x=Years,y=rate,group=1))+
theme(text = element_text(size=30))
)
这就是结果:
但我不是很喜欢它,我不能轻易地给它加上一个传奇……
1 威廉森,杰德,等人。2005年北美登山事故。The Mountaineers Books, 2005。
对我来说,棘手的部分是计算出两个轴之间的变换函数。我用的是我的curvefit。
> dput(combined_80_8192 %>% filter (time > 270, time < 280))
structure(list(run = c(268L, 268L, 268L, 268L, 268L, 268L, 268L,
268L, 268L, 268L, 263L, 263L, 263L, 263L, 263L, 263L, 263L, 263L,
263L, 263L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L,
269L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L,
267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 265L,
265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 266L, 266L,
266L, 266L, 266L, 266L, 266L, 266L, 266L, 266L, 262L, 262L, 262L,
262L, 262L, 262L, 262L, 262L, 262L, 262L, 264L, 264L, 264L, 264L,
264L, 264L, 264L, 264L, 264L, 264L, 260L, 260L, 260L, 260L, 260L,
260L, 260L, 260L, 260L, 260L), repetition = c(8L, 8L, 8L, 8L,
8L, 8L, 8L, 8L, 8L, 8L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L,
9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 5L, 5L,
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,
6L, 6L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L,
4L, 4L, 4L, 4L, 4L, 4L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
), module = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "scenario.node[0].nicVLCTail.phyVLC", class = "factor"),
configname = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L), .Label = "Road-Vlc", class = "factor"), packetByteLength = c(8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L,
8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L
), numVehicles = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L
), dDistance = c(80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L,
80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L), time = c(270.166006903445,
271.173853699836, 272.175873251122, 273.177524313334, 274.182946177105,
275.188959464989, 276.189675339937, 277.198250244799, 278.204619457189,
279.212562800009, 270.164199199177, 271.168527215152, 272.173072994958,
273.179210429715, 274.184351047337, 275.18980754378, 276.194816792995,
277.198598277809, 278.202398083519, 279.210634593917, 270.210674322891,
271.212395107473, 272.218871923292, 273.219060500457, 274.220486359614,
275.22401452372, 276.229646658839, 277.231060448138, 278.240407241942,
279.2437126347, 270.283554249858, 271.293168593832, 272.298574288769,
273.304413221348, 274.306272082517, 275.309023049011, 276.317805897347,
277.324403550028, 278.332855848701, 279.334046374594, 270.118608539613,
271.127947700074, 272.133887145863, 273.135726000491, 274.135994529981,
275.136563912708, 276.140120735361, 277.144298344151, 278.146885137621,
279.147552358659, 270.206015567272, 271.214618077209, 272.216566814903,
273.225435592582, 274.234014573683, 275.242949179958, 276.248417809711,
277.248800670023, 278.249750333404, 279.252926560188, 270.217182684494,
271.218357511397, 272.224698488895, 273.231112784327, 274.238740508457,
275.242715184122, 276.249053562718, 277.250325509798, 278.258488063493,
279.261141590137, 270.282904173953, 271.284689544638, 272.294220723234,
273.299749415592, 274.30628880553, 275.312075103126, 276.31579134717,
277.321905523606, 278.326305136748, 279.333056502253, 270.258991527456,
271.260224091407, 272.270076810133, 273.27052037648, 274.274119348094,
275.280808254502, 276.286353887245, 277.287064312339, 278.294444793276,
279.296772014594, 270.333066283904, 271.33877455992, 272.345842319903,
273.350858180493, 274.353972278505, 275.360454510107, 276.365088896161,
277.369166956941, 278.372571708911, 279.38017503079), distanceToTx = c(80.255266401689,
80.156059067023, 79.98823695539, 79.826647129071, 79.76678667135,
79.788239825292, 79.734539327997, 79.74766421514, 79.801243848241,
79.765920888341, 80.255266401689, 80.15850240049, 79.98823695539,
79.826647129071, 79.76678667135, 79.788239825292, 79.735078924078,
79.74766421514, 79.801243848241, 79.764622734914, 80.251248121732,
80.146436869316, 79.984682320466, 79.82292012342, 79.761908518748,
79.796988776281, 79.736920997657, 79.745038376718, 79.802638836686,
79.770029970452, 80.243475525691, 80.127918207499, 79.978303140866,
79.816259117883, 79.749322030693, 79.809916018889, 79.744456560867,
79.738655068783, 79.788697533211, 79.784288359619, 80.260412958482,
80.168426829066, 79.992034911214, 79.830845773284, 79.7756751763,
79.778156038931, 79.732399593756, 79.752769548846, 79.799967731078,
79.757585110481, 80.251248121732, 80.146436869316, 79.984682320466,
79.822062073459, 79.75884601899, 79.801590491435, 79.738335109094,
79.74347007248, 79.803215965043, 79.771471198955, 80.250257298678,
80.146436869316, 79.983831684476, 79.822062073459, 79.75884601899,
79.801590491435, 79.738335109094, 79.74347007248, 79.803849157574,
79.771471198955, 80.243475525691, 80.130180105198, 79.978303140866,
79.816881283718, 79.749322030693, 79.80984572883, 79.744456560867,
79.738655068783, 79.790548644175, 79.784288359619, 80.246349000313,
80.137056554491, 79.980581246037, 79.818924707937, 79.753176142361,
79.808777040341, 79.741609845588, 79.740770913572, 79.796316397253,
79.777593733292, 80.238796415443, 80.119021911134, 79.974810568944,
79.814065350562, 79.743657315504, 79.810146783217, 79.749945098869,
79.737122584544, 79.781650522348, 79.791554933936), headerNoError = c(0.99999999989702,
0.9999999999981, 0.99999999999946, 0.9999999928026, 0.99999873265475,
0.77080141574964, 0.99007491438593, 0.99994396605059, 0.45588747062284,
0.93484381262491, 0.99999999989702, 0.99999999999816, 0.99999999999946,
0.9999999928026, 0.99999873265475, 0.77080141574964, 0.99008458785106,
0.99994396605059, 0.45588747062284, 0.93480223051707, 0.99999999989735,
0.99999999999789, 0.99999999999946, 0.99999999287551, 0.99999876302649,
0.46903147501117, 0.98835168988253, 0.99994427085086, 0.45235035271542,
0.93496741877335, 0.99999999989803, 0.99999999999781, 0.99999999999948,
0.99999999318224, 0.99994254156311, 0.46891362282273, 0.93382613917348,
0.99994594904099, 0.93002915596843, 0.93569767251247, 0.99999999989658,
0.99999999998074, 0.99999999999946, 0.99999999272802, 0.99999871586781,
0.76935240919896, 0.99002587758346, 0.99999881589732, 0.46179415706093,
0.93417422376389, 0.99999999989735, 0.99999999999789, 0.99999999999946,
0.99999999289347, 0.99999876940486, 0.46930769326427, 0.98837353639905,
0.99994447154714, 0.16313586712094, 0.93500824170148, 0.99999999989744,
0.99999999999789, 0.99999999999946, 0.99999999289347, 0.99999876940486,
0.46930769326427, 0.98837353639905, 0.99994447154714, 0.16330039178981,
0.93500824170148, 0.99999999989803, 0.99999999999781, 0.99999999999948,
0.99999999316541, 0.99994254156311, 0.46794586553266, 0.93382613917348,
0.99994594904099, 0.9303627789484, 0.93569767251247, 0.99999999989778,
0.9999999999978, 0.99999999999948, 0.99999999311433, 0.99999878195152,
0.47101897739483, 0.93368891853679, 0.99994556595217, 0.7571113417265,
0.93553999975802, 0.99999999998191, 0.99999999999784, 0.99999999999971,
0.99999891129658, 0.99994309267792, 0.46510628979591, 0.93442584181035,
0.99894450514543, 0.99890078483692, 0.76933812306423), receivedPower_dbm = c(-93.023492290586,
-92.388378035287, -92.205716340607, -93.816400586752, -95.023489422885,
-100.86308557253, -98.464763536915, -96.175707680373, -102.06189538385,
-99.716653422746, -93.023492290586, -92.384760627397, -92.205716340607,
-93.816400586752, -95.023489422885, -100.86308557253, -98.464201120719,
-96.175707680373, -102.06189538385, -99.717150021506, -93.022927803442,
-92.404017215549, -92.204561341714, -93.814319484729, -95.016990717792,
-102.01669022332, -98.558088145955, -96.173817001483, -102.07406915124,
-99.71517574876, -93.021813165972, -92.409586309743, -92.20229160243,
-93.805335867418, -96.184419849593, -102.01709540787, -99.728735187547,
-96.163233028048, -99.772547164798, -99.706399753853, -93.024204617071,
-92.745813384859, -92.206884754512, -93.818508150122, -95.027018807793,
-100.87000577258, -98.467607232407, -95.005311380324, -102.04157607608,
-99.724619517, -93.022927803442, -92.404017215549, -92.204561341714,
-93.813803344588, -95.015606885523, -102.0157405687, -98.556982278361,
-96.172566862738, -103.21871579865, -99.714687230796, -93.022787428238,
-92.404017215549, -92.204274688493, -93.813803344588, -95.015606885523,
-102.0157405687, -98.556982278361, -96.172566862738, -103.21784988098,
-99.714687230796, -93.021813165972, -92.409950613665, -92.20229160243,
-93.805838770576, -96.184419849593, -102.02042267497, -99.728735187547,
-96.163233028048, -99.768774335378, -99.706399753853, -93.022228914406,
-92.411048503835, -92.203136463155, -93.807357409082, -95.012865008237,
-102.00985717796, -99.730352912911, -96.165675535906, -100.92744056572,
-99.708301333236, -92.735781110993, -92.408137395049, -92.119533319039,
-94.982938427575, -96.181073124017, -102.03018610927, -99.721633629806,
-97.32940323644, -97.347613268692, -100.87007386786), snr = c(49.848348091678,
57.698190927109, 60.17669971462, 41.529809724535, 31.452202106925,
8.1976890851341, 14.240447804094, 24.122884195464, 6.2202875499406,
10.674183333671, 49.848348091678, 57.746270018264, 60.17669971462,
41.529809724535, 31.452202106925, 8.1976890851341, 14.242292077376,
24.122884195464, 6.2202875499406, 10.672962852322, 49.854827699773,
57.49079026127, 60.192705735317, 41.549715223147, 31.499301851462,
6.2853718719014, 13.937702343688, 24.133388256416, 6.2028757927148,
10.677815810561, 49.867624820879, 57.417115267867, 60.224172277442,
41.635752021705, 24.074540962859, 6.2847854917092, 10.644529778044,
24.19227425387, 10.537686730745, 10.699414795917, 49.84017267426,
53.139646558768, 60.160512118809, 41.509660845114, 31.42665220053,
8.1846370024428, 14.231126423354, 31.584125885363, 6.2494585568733,
10.654622041348, 49.854827699773, 57.49079026127, 60.192705735317,
41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322,
24.140336174865, 4.765718874642, 10.679016976694, 49.856439162736,
57.49079026127, 60.196678846453, 41.55465351989, 31.509340361646,
6.2867464196657, 13.941251828322, 24.140336174865, 4.7666691818074,
10.679016976694, 49.867624820879, 57.412299088098, 60.224172277442,
41.630930975211, 24.074540962859, 6.279972363168, 10.644529778044,
24.19227425387, 10.546845071479, 10.699414795917, 49.862851240855,
57.397787176282, 60.212457625018, 41.61637603957, 31.529239767749,
6.2952688513108, 10.640565481982, 24.178672145334, 8.0771089950663,
10.694731030907, 53.262541905639, 57.43627424514, 61.382796189332,
31.747253311549, 24.093100244121, 6.2658701281075, 10.661949889074,
18.495227442305, 18.417839037171, 8.1845086722809), frameId = c(15051,
15106, 15165, 15220, 15279, 15330, 15385, 15452, 15511, 15566,
15019, 15074, 15129, 15184, 15239, 15298, 15353, 15412, 15471,
15526, 14947, 14994, 15057, 15112, 15171, 15226, 15281, 15332,
15391, 15442, 14971, 15030, 15085, 15144, 15203, 15262, 15321,
15380, 15435, 15490, 14915, 14978, 15033, 15092, 15147, 15198,
15257, 15312, 15371, 15430, 14975, 15034, 15089, 15140, 15195,
15254, 15313, 15368, 15427, 15478, 14987, 15046, 15105, 15160,
15215, 15274, 15329, 15384, 15447, 15506, 14943, 15002, 15061,
15116, 15171, 15230, 15285, 15344, 15399, 15454, 14971, 15026,
15081, 15136, 15195, 15258, 15313, 15368, 15423, 15478, 15039,
15094, 15149, 15204, 15263, 15314, 15369, 15428, 15487, 15546
), packetOkSinr = c(0.99999999314881, 0.9999999998736, 0.99999999996428,
0.99999952114066, 0.99991568416005, 3.00628034688444e-08,
0.51497487795954, 0.99627877136019, 0, 0.011303253101957,
0.99999999314881, 0.99999999987726, 0.99999999996428, 0.99999952114066,
0.99991568416005, 3.00628034688444e-08, 0.51530974419663,
0.99627877136019, 0, 0.011269851265775, 0.9999999931708,
0.99999999985986, 0.99999999996428, 0.99999952599145, 0.99991770469509,
0, 0.45861812482641, 0.99629897628155, 0, 0.011403119534097,
0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954639936,
0.99618434878558, 0, 0.010513119213425, 0.99641022914441,
0.00801687746446111, 0.012011103529927, 0.9999999931195,
0.99999999871861, 0.99999999996428, 0.99999951617905, 0.99991456738049,
2.6525298291169e-08, 0.51328066587104, 0.9999212220316, 0,
0.010777054258914, 0.9999999931708, 0.99999999985986, 0.99999999996428,
0.99999952718674, 0.99991812902805, 0, 0.45929307038653,
0.99631228046814, 0, 0.011436292559188, 0.99999999317629,
0.99999999985986, 0.99999999996428, 0.99999952718674, 0.99991812902805,
0, 0.45929307038653, 0.99631228046814, 0, 0.011436292559188,
0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954527918,
0.99618434878558, 0, 0.010513119213425, 0.99641022914441,
0.00821047996950475, 0.012011103529927, 0.99999999319919,
0.99999999985345, 0.99999999996519, 0.99999954188106, 0.99991896371849,
0, 0.010410830482692, 0.996384831822, 9.12484388049251e-09,
0.011877185067536, 0.99999999879646, 0.9999999998562, 0.99999999998077,
0.99992756868677, 0.9962208785486, 0, 0.010971897073662,
0.93214999078663, 0.92943956665979, 2.64925478221656e-08),
snir = c(49.848348091678, 57.698190927109, 60.17669971462,
41.529809724535, 31.452202106925, 8.1976890851341, 14.240447804094,
24.122884195464, 6.2202875499406, 10.674183333671, 49.848348091678,
57.746270018264, 60.17669971462, 41.529809724535, 31.452202106925,
8.1976890851341, 14.242292077376, 24.122884195464, 6.2202875499406,
10.672962852322, 49.854827699773, 57.49079026127, 60.192705735317,
41.549715223147, 31.499301851462, 6.2853718719014, 13.937702343688,
24.133388256416, 6.2028757927148, 10.677815810561, 49.867624820879,
57.417115267867, 60.224172277442, 41.635752021705, 24.074540962859,
6.2847854917092, 10.644529778044, 24.19227425387, 10.537686730745,
10.699414795917, 49.84017267426, 53.139646558768, 60.160512118809,
41.509660845114, 31.42665220053, 8.1846370024428, 14.231126423354,
31.584125885363, 6.2494585568733, 10.654622041348, 49.854827699773,
57.49079026127, 60.192705735317, 41.55465351989, 31.509340361646,
6.2867464196657, 13.941251828322, 24.140336174865, 4.765718874642,
10.679016976694, 49.856439162736, 57.49079026127, 60.196678846453,
41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322,
24.140336174865, 4.7666691818074, 10.679016976694, 49.867624820879,
57.412299088098, 60.224172277442, 41.630930975211, 24.074540962859,
6.279972363168, 10.644529778044, 24.19227425387, 10.546845071479,
10.699414795917, 49.862851240855, 57.397787176282, 60.212457625018,
41.61637603957, 31.529239767749, 6.2952688513108, 10.640565481982,
24.178672145334, 8.0771089950663, 10.694731030907, 53.262541905639,
57.43627424514, 61.382796189332, 31.747253311549, 24.093100244121,
6.2658701281075, 10.661949889074, 18.495227442305, 18.417839037171,
8.1845086722809), ookSnirBer = c(8.8808636558081e-24, 3.2219795637026e-27,
2.6468895519653e-28, 3.9807779074715e-20, 1.0849324265615e-15,
2.5705217057696e-05, 4.7313805615763e-08, 1.8800438086075e-12,
0.00021005320203921, 1.9147343768384e-06, 8.8808636558081e-24,
3.0694773489537e-27, 2.6468895519653e-28, 3.9807779074715e-20,
1.0849324265615e-15, 2.5705217057696e-05, 4.7223753038869e-08,
1.8800438086075e-12, 0.00021005320203921, 1.9171738578051e-06,
8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28,
3.9014083702734e-20, 1.0342658440386e-15, 0.00019591630514278,
6.4692014108683e-08, 1.8600094209271e-12, 0.0002140067535655,
1.9074922485477e-06, 8.7096574467175e-24, 4.2779443633862e-27,
2.5231916788231e-28, 3.5761615214425e-20, 1.9750692814982e-12,
0.0001960392878411, 1.9748966344895e-06, 1.7515881895994e-12,
2.2078334799411e-06, 1.8649940680806e-06, 8.954486301678e-24,
3.2021085732779e-25, 2.690441113724e-28, 4.0627628846548e-20,
1.1134484878561e-15, 2.6061691733331e-05, 4.777159157954e-08,
9.4891388749738e-16, 0.00020359398491544, 1.9542110660398e-06,
8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28,
3.8819641115984e-20, 1.0237769828158e-15, 0.00019562832342849,
6.4455095380046e-08, 1.8468752030971e-12, 0.0010099091367628,
1.9051035165106e-06, 8.8085966897635e-24, 3.9715925056443e-27,
2.594108048185e-28, 3.8819641115984e-20, 1.0237769828158e-15,
0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12,
0.0010088638355194, 1.9051035165106e-06, 8.7096574467175e-24,
4.2987746909572e-27, 2.5231916788231e-28, 3.593647329558e-20,
1.9750692814982e-12, 0.00019705170257492, 1.9748966344895e-06,
1.7515881895994e-12, 2.1868296425817e-06, 1.8649940680806e-06,
8.7517439682173e-24, 4.3621551072316e-27, 2.553168170837e-28,
3.6469582463164e-20, 1.0032983660212e-15, 0.00019385229409318,
1.9830820164805e-06, 1.7760568361323e-12, 2.919419915209e-05,
1.8741284335866e-06, 2.8285944348148e-25, 4.1960751547207e-27,
7.8468215407139e-29, 8.0407329049747e-16, 1.9380328071065e-12,
0.00020004849911333, 1.9393279417733e-06, 5.9354475879597e-10,
6.4258355913627e-10, 2.6065221215415e-05), ookSnrBer = c(8.8808636558081e-24,
3.2219795637026e-27, 2.6468895519653e-28, 3.9807779074715e-20,
1.0849324265615e-15, 2.5705217057696e-05, 4.7313805615763e-08,
1.8800438086075e-12, 0.00021005320203921, 1.9147343768384e-06,
8.8808636558081e-24, 3.0694773489537e-27, 2.6468895519653e-28,
3.9807779074715e-20, 1.0849324265615e-15, 2.5705217057696e-05,
4.7223753038869e-08, 1.8800438086075e-12, 0.00021005320203921,
1.9171738578051e-06, 8.8229427230445e-24, 3.9715925056443e-27,
2.6045198111088e-28, 3.9014083702734e-20, 1.0342658440386e-15,
0.00019591630514278, 6.4692014108683e-08, 1.8600094209271e-12,
0.0002140067535655, 1.9074922485477e-06, 8.7096574467175e-24,
4.2779443633862e-27, 2.5231916788231e-28, 3.5761615214425e-20,
1.9750692814982e-12, 0.0001960392878411, 1.9748966344895e-06,
1.7515881895994e-12, 2.2078334799411e-06, 1.8649940680806e-06,
8.954486301678e-24, 3.2021085732779e-25, 2.690441113724e-28,
4.0627628846548e-20, 1.1134484878561e-15, 2.6061691733331e-05,
4.777159157954e-08, 9.4891388749738e-16, 0.00020359398491544,
1.9542110660398e-06, 8.8229427230445e-24, 3.9715925056443e-27,
2.6045198111088e-28, 3.8819641115984e-20, 1.0237769828158e-15,
0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12,
0.0010099091367628, 1.9051035165106e-06, 8.8085966897635e-24,
3.9715925056443e-27, 2.594108048185e-28, 3.8819641115984e-20,
1.0237769828158e-15, 0.00019562832342849, 6.4455095380046e-08,
1.8468752030971e-12, 0.0010088638355194, 1.9051035165106e-06,
8.7096574467175e-24, 4.2987746909572e-27, 2.5231916788231e-28,
3.593647329558e-20, 1.9750692814982e-12, 0.00019705170257492,
1.9748966344895e-06, 1.7515881895994e-12, 2.1868296425817e-06,
1.8649940680806e-06, 8.7517439682173e-24, 4.3621551072316e-27,
2.553168170837e-28, 3.6469582463164e-20, 1.0032983660212e-15,
0.00019385229409318, 1.9830820164805e-06, 1.7760568361323e-12,
2.919419915209e-05, 1.8741284335866e-06, 2.8285944348148e-25,
4.1960751547207e-27, 7.8468215407139e-29, 8.0407329049747e-16,
1.9380328071065e-12, 0.00020004849911333, 1.9393279417733e-06,
5.9354475879597e-10, 6.4258355913627e-10, 2.6065221215415e-05
)), class = "data.frame", row.names = c(NA, -100L), .Names = c("run",
"repetition", "module", "configname", "packetByteLength", "numVehicles",
"dDistance", "time", "distanceToTx", "headerNoError", "receivedPower_dbm",
"snr", "frameId", "packetOkSinr", "snir", "ookSnirBer", "ookSnrBer"
))
求变换函数
Y1 -> y2 该函数用于将次要y轴的数据按照第一个y轴进行“归一化”
变换函数:f(y1) = 0.025*x + 2.75
Y2 -> y1 该函数用于将第一个y轴的断点转换为第二个y轴的值。注意,现在坐标轴互换了。
变换函数:f(y1) = 40*x - 110
策划
注意如何在ggplot调用中使用转换函数来“动态地”转换数据
ggplot(data=combined_80_8192 %>% filter (time > 270, time < 280), aes(x=time) ) +
stat_summary(aes(y=receivedPower_dbm ), fun.y=mean, geom="line", colour="black") +
stat_summary(aes(y=packetOkSinr*40 - 110 ), fun.y=mean, geom="line", colour="black", position = position_dodge(width=10)) +
scale_x_continuous() +
scale_y_continuous(breaks = seq(-0,-110,-10), "y_first", sec.axis=sec_axis(~.*0.025+2.75, name="y_second") )
第一个stat_summary调用是为第一个y轴设置基数的调用。 第二个stat_summary调用用于转换数据。请记住,所有数据将以第一个y轴为基础。第一个y轴的数据需要标准化。为此,我使用数据上的转换函数:y=packetOkSinr*40 - 110
现在要转换第二个轴,我在scale_y_continuous调用中使用相反的函数:sec.axis=sec_axis(~.*0.025+2.75, name="y_second")。
我们当然可以用R函数图来建立一个双y轴的图。
# pseudo dataset
df <- data.frame(x = seq(1, 1000, 1), y1 = sample.int(100, 1000, replace=T), y2 = sample(50, 1000, replace = T))
# plot first plot
with(df, plot(y1 ~ x, col = "red"))
# set new plot
par(new = T)
# plot second plot, but without axis
with(df, plot(y2 ~ x, type = "l", xaxt = "n", yaxt = "n", xlab = "", ylab = ""))
# define y-axis and put y-labs
axis(4)
with(df, mtext("y2", side = 4))
我承认并同意哈德利(和其他人)的观点,即单独的y量表“存在根本缺陷”。说到这里,我经常希望ggplot2有这个特性——特别是当数据是宽格式的,并且我想快速地可视化或检查数据时(即仅供个人使用)。
虽然tidyverse库可以很容易地将数据转换为长格式(这样facet_grid()就可以工作),但这个过程仍然不是简单的,如下所示:
library(tidyverse)
df.wide %>%
# Select only the columns you need for the plot.
select(date, column1, column2, column3) %>%
# Create an id column – needed in the `gather()` function.
mutate(id = n()) %>%
# The `gather()` function converts to long-format.
# In which the `type` column will contain three factors (column1, column2, column3),
# and the `value` column will contain the respective values.
# All the while we retain the `id` and `date` columns.
gather(type, value, -id, -date) %>%
# Create the plot according to your specifications
ggplot(aes(x = date, y = value)) +
geom_line() +
# Create a panel for each `type` (ie. column1, column2, column3).
# If the types have different scales, you can use the `scales="free"` option.
facet_grid(type~., scales = "free")
根据上面的答案和一些微调(无论它有什么价值),这里有一种通过sec_axis实现两个尺度的方法:
假设有一个简单的(完全虚构的)数据集dt:在五天的时间里,它追踪了被打断的次数VS工作效率:
when numinter prod
1 2018-03-20 1 0.95
2 2018-03-21 5 0.50
3 2018-03-23 4 0.70
4 2018-03-24 3 0.75
5 2018-03-25 4 0.60
(两列的范围相差大约5倍)。
下面的代码将画出它们占用整个y轴的两个级数:
ggplot() +
geom_bar(mapping = aes(x = dt$when, y = dt$numinter), stat = "identity", fill = "grey") +
geom_line(mapping = aes(x = dt$when, y = dt$prod*5), size = 2, color = "blue") +
scale_x_date(name = "Day", labels = NULL) +
scale_y_continuous(name = "Interruptions/day",
sec.axis = sec_axis(~./5, name = "Productivity % of best",
labels = function(b) { paste0(round(b * 100, 0), "%")})) +
theme(
axis.title.y = element_text(color = "grey"),
axis.title.y.right = element_text(color = "blue"))
下面是结果(上面的代码+一些颜色调整):
重点(除了在指定y_scale时使用sec_axis之外)是在指定系列时将第二个数据系列的每个值与5相乘。为了在sec_axis定义中获得正确的标签,它需要除以5(并格式化)。因此,上述代码中的关键部分实际上是geom_line和~中的*5。sec_axis中的/5(一个除当前值的公式。5)。
相比之下(我不想在这里判断方法),这是两个图表叠加在一起的样子:
你可以自己判断哪一个能更好地传递信息(“不要打扰别人工作!”)。我想这是一个公平的决定方式。
这两个图像的完整代码(实际上并没有比上面更多,只是完成并准备运行)在这里:https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7d更详细的解释在这里:https://sebastianrothbucher.github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html
您可以创建一个缩放因子,应用于第二个geom和右y轴。这是从塞巴斯蒂安的解推导出来的。
library(ggplot2)
scaleFactor <- max(mtcars$cyl) / max(mtcars$hp)
ggplot(mtcars, aes(x=disp)) +
geom_smooth(aes(y=cyl), method="loess", col="blue") +
geom_smooth(aes(y=hp * scaleFactor), method="loess", col="red") +
scale_y_continuous(name="cyl", sec.axis=sec_axis(~./scaleFactor, name="hp")) +
theme(
axis.title.y.left=element_text(color="blue"),
axis.text.y.left=element_text(color="blue"),
axis.title.y.right=element_text(color="red"),
axis.text.y.right=element_text(color="red")
)
注意:使用ggplot2 v3.0.0
常见的用例有双y轴,例如,显示每月温度和降水的气体图。这里是一个简单的解决方案,从威震天的解决方案中推广,允许你设置变量的下限为零:
示例数据:
climate <- tibble(
Month = 1:12,
Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
Precip = c(49,36,47,41,53,65,81,89,90,84,73,55)
)
将以下两个值设置为接近数据限制的值(您可以使用这些值来调整图形的位置;坐标轴仍然是正确的):
ylim.prim <- c(0, 180) # in this example, precipitation
ylim.sec <- c(-4, 18) # in this example, temperature
下面根据这些极限进行必要的计算,并制作出图本身:
b <- diff(ylim.prim)/diff(ylim.sec)
a <- ylim.prim[1] - b*ylim.sec[1]) # there was a bug here
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = a + Temp*b), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
scale_x_continuous("Month", breaks = 1:12) +
ggtitle("Climatogram for Oslo (1961-1990)")
如果你想确保红线对应右边的y轴,你可以在代码中添加一个主题句:
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = a + Temp*b), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
scale_x_continuous("Month", breaks = 1:12) +
theme(axis.line.y.right = element_line(color = "red"),
axis.ticks.y.right = element_line(color = "red"),
axis.text.y.right = element_text(color = "red"),
axis.title.y.right = element_text(color = "red")
) +
ggtitle("Climatogram for Oslo (1961-1990)")
右轴的颜色:
It seemingly appears to be a simple question but it boggles around 2 fundamental questions. A) How to deal with a multi-scalar data while presenting in a comparative chart, and secondly, B) whether this can be done without some thumb rule practices of R programming such as i) melting data, ii) faceting, iii) adding another layer to existing one. The solution given below satisfies both the above conditions as it deals data without having to rescale it and secondly, the techniques mentioned are not used.
这是结果,
如果有兴趣了解更多关于此方法的信息,请点击下面的链接。 如何绘制一个2 y轴图表与条形并排而不重新缩放数据
我发现这个答案对我帮助最大,但发现有一些边缘情况,它似乎不能正确处理,特别是消极的情况,以及极限距离为0的情况(如果我们从最大/最小数据中获取极限,就会发生这种情况)。测试似乎表明,这是一致的
我使用以下代码。这里我假设我们有[x1,x2]我们想把它变换成[y1,y2]。我处理这个问题的方法是将[x1,x2]转换为[0,1](一个足够简单的转换),然后[0,1]转换为[y1,y2]。
climate <- tibble(
Month = 1:12,
Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
Precip = c(49,36,47,41,53,65,81,89,90,84,73,55)
)
#Set the limits of each axis manually:
ylim.prim <- c(0, 180) # in this example, precipitation
ylim.sec <- c(-4, 18) # in this example, temperature
b <- diff(ylim.sec)/diff(ylim.prim)
#If all values are the same this messes up the transformation, so we need to modify it here
if(b==0){
ylim.sec <- c(ylim.sec[1]-1, ylim.sec[2]+1)
b <- diff(ylim.sec)/diff(ylim.prim)
}
if (is.na(b)){
ylim.prim <- c(ylim.prim[1]-1, ylim.prim[2]+1)
b <- diff(ylim.sec)/diff(ylim.prim)
}
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = ylim.prim[1]+(Temp-ylim.sec[1])/b), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~((.-ylim.prim[1]) *b + ylim.sec[1]), name = "Temperature"), limits = ylim.prim) +
scale_x_continuous("Month", breaks = 1:12) +
ggtitle("Climatogram for Oslo (1961-1990)")
这里的关键部分是,我们用~((.-ylim.prim[1]) *b + ylim.sec[1])转换次要y轴,然后对实际值y = ylim.prim[1]+(Temp-ylim.sec[1])/b)应用逆。我们还应该确保limits = ylim.prim。
以下内容结合了Dag Hjermann的基本数据和编程,改进了user4786271创建“转换函数”的策略,以优化组合图和数据轴,并响应了浸信会的提示,这样的函数可以在R中创建。
#Climatogram for Oslo (1961-1990)
climate <- tibble(
Month = 1:12,
Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
Precip = c(49,36,47,41,53,65,81,89,90,84,73,55))
#y1 identifies the position, relative to the y1 axis,
#the locations of the minimum and maximum of the y2 graph.
#Usually this will be the min and max of y1.
#y1<-(c(max(climate$Precip), 0))
#y1<-(c(150, 55))
y1<-(c(max(climate$Precip), min(climate$Precip)))
#y2 is the Minimum and maximum of the secondary axis data.
y2<-(c(max(climate$Temp), min(climate$Temp)))
#axis combines y1 and y2 into a dataframe used for regressions.
axis<-cbind(y1,y2)
axis<-data.frame(axis)
#Regression of Temperature to Precipitation:
T2P<-lm(formula = y1 ~ y2, data = axis)
T2P_summary <- summary(lm(formula = y1 ~ y2, data = axis))
T2P_summary
#Identifies the intercept and slope of regressing Temperature to Precipitation:
T2PInt<-T2P_summary$coefficients[1, 1]
T2PSlope<-T2P_summary$coefficients[2, 1]
#Regression of Precipitation to Temperature:
P2T<-lm(formula = y2 ~ y1, data = axis)
P2T_summary <- summary(lm(formula = y2 ~ y1, data = axis))
P2T_summary
#Identifies the intercept and slope of regressing Precipitation to Temperature:
P2TInt<-P2T_summary$coefficients[1, 1]
P2TSlope<-P2T_summary$coefficients[2, 1]
#Create Plot:
ggplot(climate, aes(Month, Precip)) +
geom_col() +
geom_line(aes(y = T2PSlope*Temp + T2PInt), color = "red") +
scale_y_continuous("Precipitation", sec.axis = sec_axis(~.*P2TSlope + P2TInt, name = "Temperature")) +
scale_x_continuous("Month", breaks = 1:12) +
theme(axis.line.y.right = element_line(color = "red"),
axis.ticks.y.right = element_line(color = "red"),
axis.text.y.right = element_text(color = "red"),
axis.title.y.right = element_text(color = "red")) +
ggtitle("Climatogram for Oslo (1961-1990)")
Most noteworthy is that a new "transformation function" works better with just two data points from the data set of each axes—usually the maximum and minimum values of each set. The resulting slopes and intercepts of the two regressions enable ggplot2 to exactly pair the plots of the minimums and maximums of each axis. As user4786271 pointed out, the two regressions transform each data set and plot to the other. One transforms the break points of the first y axis to the values of the second y axis. The second transforms the data of the secondary y axis to be "normalized" according to the first y axis. The following output shows how the axis align the minimums and maximums of each dataset:
使最大值和最小值匹配可能是最合适的;但是,这种方法的另一个好处是,如果需要,可以通过更改与主轴数据相关的编程行轻松地移动与次要轴相关的绘图。下面的输出只是将y1编程行中输入的最小降水量更改为“0”,从而将最小温度水平与“0”降水水平对齐。
从:y1<-(c(max(气候$ precp), min(气候$ precp)))
到:y1<-(c(max(气候$ precp), 0))
请注意,生成的新回归和ggplot2如何自动调整绘图和轴,以正确地将最低温度与“0”降水水平的新“基数”对齐。同样,可以很容易地提升Temperature图,使其更加明显。下面的图是通过简单地将上面提到的线更改为:
“日元<——(c(150年,55岁))”
上面的线表示温度曲线的最大值与“150”降水水平相吻合,温度曲线的最小值与“55”降水水平相吻合。再次注意,ggplot2和由此产生的新的回归输出如何使图保持与轴的正确对齐。
以上可能不是理想的输出;然而,这是一个例子,说明了如何容易地操纵图形,并且在图和轴之间仍然有正确的关系。 Dag Hjermann的主题的结合提高了与情节对应的轴的识别。
这是我对如何做二次轴变换的两种看法。首先,您希望将主数据和辅助数据的范围耦合起来。这通常是混乱的,因为您不想要的变量污染了全局环境。
为了简化这一点,我们将创建一个生成两个函数的函数工厂,其中scales::rescale()完成所有繁重的工作。因为这些是闭包,所以它们知道创建它们的环境,所以它们“有”创建之前生成的to和from参数的“内存”。
一个函数进行正向转换:将辅助数据转换为主要尺度。 第二个函数进行反向转换:将主要单位中的数据转换为次要单位。
library(ggplot2)
library(scales)
# Function factory for secondary axis transforms
train_sec <- function(primary, secondary, na.rm = TRUE) {
# Thanks Henry Holm for including the na.rm argument!
from <- range(secondary, na.rm = na.rm)
to <- range(primary, na.rm = na.rm)
# Forward transform for the data
forward <- function(x) {
rescale(x, from = from, to = to)
}
# Reverse transform for the secondary axis
reverse <- function(x) {
rescale(x, from = to, to = from)
}
list(fwd = forward, rev = reverse)
}
这看起来相当复杂,但是创建函数工厂会使其余的一切变得更简单。现在,在绘制图形之前,我们将通过向工厂显示主要和次要数据来生成相关函数。我们将使用经济学数据集,它的失业列和pasavert列的范围非常不同。
sec <- with(economics, train_sec(unemploy, psavert))
然后我们使用y = sec$fwd(psavert)将辅助数据重新缩放到主轴,并指定~ sec$rev(.)作为辅助轴的转换参数。这给了我们一个主要范围和次要范围在图上占据相同空间的图。
ggplot(economics, aes(date)) +
geom_line(aes(y = unemploy), colour = "blue") +
geom_line(aes(y = sec$fwd(psavert)), colour = "red") +
scale_y_continuous(sec.axis = sec_axis(~sec$rev(.), name = "psavert"))
工厂比这稍微灵活一些,因为如果您只是想重新调整最大值,您可以传入下限为0的数据。
# Rescaling the maximum
sec <- with(economics, train_sec(c(0, max(unemploy)),
c(0, max(psavert))))
ggplot(economics, aes(date)) +
geom_line(aes(y = unemploy), colour = "blue") +
geom_line(aes(y = sec$fwd(psavert)), colour = "red") +
scale_y_continuous(sec.axis = sec_axis(~sec$rev(.), name = "psavert"))
由reprex包于2021-02-05创建(v0.3.0)
我承认这个例子中的区别不是很明显,但如果你仔细观察,你会发现最大值是相同的,红线比蓝色的线低。
编辑:
这种方法现在已经在ggh4x包中的help_secondary()函数中被捕获和扩展。声明:我是ggh4x的作者。
总有办法的。
这里有一个解决方案,允许完全任意轴而不重新缩放。其思想是生成两个除了轴以外完全相同的图,并使用cowplot包中的insert_yaxis_grob和get_y_axis函数将它们组合在一起。
library(ggplot2)
library(cowplot)
## first plot
p1 <- ggplot(mtcars,aes(disp,hp,color=as.factor(am))) +
geom_point() + theme_bw() + theme(legend.position='top', text=element_text(size=16)) +
ylab("Horse points" )+ xlab("Display size") + scale_color_discrete(name='Transmitter') +
stat_smooth(se=F)
## same plot with different, arbitrary scale
p2 <- p1 +
scale_y_continuous(position='right',breaks=seq(120,173,length.out = 3),
labels=c('little','medium little','medium hefty'))
ggdraw(insert_yaxis_grob(p1,get_y_axis(p2,position='right')))