ChatGPT解决这个技术问题 Extra ChatGPT

ggplot 每边有 2 个 y 轴和不同的比例

我需要在一个图表中绘制一个显示计数的条形图和一个显示速率的折线图,我可以分别做这两个,但是当我把它们放在一起时,我的第一层(即geom_bar)的比例是重叠的由第二层(即geom_line)。

我可以将 geom_line 的轴向右移动吗?

您可以使用这里所展示的方法吗,rpubs.com/kohske/dual_axis_in_ggplot2
向下滚动以查看 scale_y_* 中的本机 ggplot2 实现,当前称为 sec.axis

T
Tung

从 ggplot2 2.2.0 开始,您可以添加这样的辅助轴(取自 ggplot2 2.2.0 announcement):

ggplot(mpg, aes(displ, hwy)) + 
  geom_point() + 
  scale_y_continuous(
    "mpg (US)", 
    sec.axis = sec_axis(~ . * 1.20, name = "mpg (UK)")
  )

https://i.stack.imgur.com/BePYe.png


缺点是,它只能使用当前轴的一些公式转换,而不是新变量,例如。
但是您可以转换新变量,使其具有与旧变量大致相同的范围,然后使用 sec_axis 显示将新变量放回其原始比例的标签。
h
hadley

这在 ggplot2 中是不可能的,因为我认为具有单独 y 尺度(而不是相互转换的 y 尺度)的图从根本上是有缺陷的。一些问题:

不可逆:给定绘图空间上的一个点,您不能将它唯一地映射回数据空间中的一个点。

与其他选项相比,它们相对难以正确阅读。有关详细信息,请参阅 Petra Isenberg、Anastasia Bezerianos、Pierre Dragicevic 和 Jean-Daniel Fekete 的双尺度数据图表研究。

它们很容易被操纵以误导:没有唯一的方法来指定轴的相对比例,从而使它们易于操纵。 Junkcharts 博客中的两个示例:一、二

它们是任意的:为什么只有 2 个刻度,而不是 3、4 或 10?

您可能还想阅读 Stephen Few 关于主题 Dual-Scaled Axes in Graphs Are They Ever the Best Solution? 的冗长讨论。


您介意详细说明您的意见吗?没有开明,我认为这是一种绘制两个自变量的相当紧凑的方式。这也是一个似乎被要求的功能,并且被广泛使用。
@hadley:大多数情况下我同意,但是多个 y 尺度有一个真正的用途——对相同的数据使用 2 个不同的单位,例如温度时间序列上的摄氏和华氏尺度。
@Hadley 在您看来。不是我的,也不是许多其他科学家。当然,这可以通过将第二个图(具有完全透明的背景)直接放在第一个图上来实现,因此它们看起来像一个。我只是不知道如何确保边界框的角彼此对齐/注册。
@hadley 例如,在 Walther-Lieth Climate Diagrams 中,通常使用两个 y 轴。由于有一个固定的处方如何做到这一点,可能的混淆是最小的......
@hadley我很抱歉,我看不出给定的气候图有什么问题。将温度和降水放在一个图表中(使用固定的处方),人们可以快速猜测它是潮湿还是干旱气候。或者反过来:什么是可视化温度、降水及其“关系”的更好方法?无论如何,非常感谢您在 ggplot2 中所做的工作!
M
M--

有时客户需要两个 y 刻度。给他们“有缺陷”的演讲通常是没有意义的。但我确实喜欢 ggplot2 坚持以正确的方式做事。我确信 ggplot 实际上正在教育普通用户正确的可视化技术。

也许您可以使用 faceting 和 scale free 来比较两个数据系列? - 例如看这里:https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page


我同意 Andreas - 有时(例如现在,对我来说)客户想要在同一个图上使用两组数据,并且不想听我谈论绘图理论。我要么必须说服他们不再想要那样(并不总是我想发动的战斗),要么告诉他们“我使用的绘图包不支持这一点。”所以我今天从 ggplot 切换到这个特定的项目。 =(
为什么绘图包需要在其操作方式中插入自己的个人意见?不,谢谢。
不能同意这个评论(重新咆哮)。尽可能地压缩信息是非常(!)常见的,例如,考虑到科学期刊等施加的严格限制,以便快速传达信息。因此,无论如何都要添加第二个 y 轴,我认为 ggplot 应该有助于这样做。
令人惊讶的是,“有缺陷的”和“正确的方式”之类的词是如何毫无疑问地被抛出的,就好像它们不是基于一个本身实际上相当固执和教条的理论,但被太多人不假思索地接受了,正如可以看出的那样事实上,在撰写本文时,这个完全无益的答案(引发了链接骨)有 72 个赞成票。例如,在比较时间序列时,将两者放在同一张图表上可能是非常宝贵的,因为差异的相关性更容易发现。只要问问每天整天都在做这件事的成千上万受过高等教育的金融专业人士。
@hadley 我同意。 ggplot absolutley 100% 需要双轴。每天将有成千上万的人继续使用双轴,将它们放在 r 中会很棒。这是一个痛苦的疏忽。我正在将数据从 r 中取出并放入 excel 中。
M
Malcolm Gillies

有常见的双 y 轴用例,例如,climatograph 显示每月温度和降水量。这是一个简单的解决方案,它是从 Megatron 的解决方案推广而来的,它允许您将变量的下限设置为非零的值:

示例数据:

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)")  

https://i.stack.imgur.com/qVSoP.png

如果要确保红线对应右手y轴,可以在代码中加一句theme

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)")

为右手轴着色:

https://i.stack.imgur.com/xvsd7.png


这在 ylim.primylim.sec 的某些值处中断。
这很棒。两轴图表没有“缺陷”的好例子。认为他们比你更了解你的工作的一般 tidyverse 心态的一部分。
当我选择特定的轴限制(在我的情况下 ylim.prim <- c(90, 130) 和 ylim.sec <- c(15, 30))时,它不会应用它,而是选择任意限制,弄乱所有比例.我不确定我在复制上面的代码时缺少什么,只是更改了变量名和轴限制
@anke:当提到 ylim.prim 和 ylim.sec 时,文本有些草率。它们不是指轴的限制,而是指数据的限制。当您设置 ylim.prim <- c(90, 130) 和 ylim.sec <- c(15, 30) 时,温度图最终高出条形图(因为温度轴从 -75 开始) ,但每个图的轴仍然正确。
S
Sebastian Rothbucher

采用上述答案和一些微调(以及不管它的价值),这是一种通过 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"))

这是结果(上面的代码+一些颜色调整):

https://i.stack.imgur.com/hAtKJ.png

要点(除了在指定 y_scale 时使用 sec_axis 是在指定系列时将第二个数据系列的每个值乘以 5。为了在 sec_axis 定义中获得正确的标签,然后需要除以 5(和格式化)。因此,上述代码中的关键部分实际上是 geom_line 中的 *5 和 sec_axis 中的 ~./5(将当前值 . 除以 5 的公式) .

相比之下(我不想在这里判断这些方法),这就是两个图表相互叠加的样子:

https://i.stack.imgur.com/gCjvf.png

您可以自己判断哪个更能传达信息(“不要打扰工作中的人!”)。猜猜这是一个公平的决定方式。

两个图像的完整代码(实际上并不比上面的更多,只是完整并准备好运行)在这里:https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7d在这里更详细的解释:https://sebastianrothbucher.github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html


这是获得两个带有虚拟刻面的不同刻度的巧妙技巧!我想知道是否有比使用全局变量更“合法”的方式?如果数据中的一列可以用作 scale_y_continuouslabels 参数的输入,那该多好?
M
Megatron

您可以创建一个应用于第二个几何图形和右 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")
  )

https://i.stack.imgur.com/H6W2Q.png

注意:使用 ggplot2 v3.0.0


这是一个干净的解决方案。
杰出的!!! +1
C
C.K

Kohske 大约在 3 年前 [KOHSKE] 提供了解决这一挑战的技术骨干。 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)
}

现在可以将所有内容放在一起:下面的代码显示了建议的解决方案如何在日常环境中使用。绘图调用现在不再绘制原始数据 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

https://i.stack.imgur.com/NEsUT.png

直截了当地说,上述解决方案是一个有限的摇摇欲坠的黑客。当它使用 ggplot 内核时,它会抛出一些警告,我们会交换事后比例等。它必须小心处理,并且可能在另一个设置中产生一些不希望的行为。也可能需要摆弄辅助函数来获得所需的布局。图例的放置是个问题(它将放置在面板和新轴之间;这就是我放弃它的原因)。 2 轴的缩放/对齐也有点挑战性:当两个比例都包含“0”时,上面的代码可以很好地工作,否则一个轴会移位。所以肯定有一些改进的机会......

如果想要保存图片,则必须将调用包装到设备打开/关闭中:

png(...)
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
dev.off()

t
teunbrand

这是我关于如何对辅助轴进行转换的两分钱。首先,您要耦合主要和次要数据的范围。就用你不想要的变量污染你的全局环境而言,这通常是混乱的。

为了使这更容易,我们将创建一个生成两个函数的函数工厂,其中 scales::rescale() 完成所有繁重的工作。因为这些是闭包,所以它们知道创建它们的环境,因此它们“有记忆”在创建之前生成的 tofrom 参数。

一个函数进行正向转换:将辅助数据转换为主要尺度。

第二个函数进行反向转换:将主要单位中的数据转换为次要单位。

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)
}

这看起来相当复杂,但是制作函数工厂使所有其他事情变得更容易。现在,在绘制绘图之前,我们将通过向工厂显示主要和次要数据来生成相关函数。我们将使用 unemploypsavert 列的范围非常不同的经济数据集。

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"))

https://i.imgur.com/hkjCQX8.png

工厂比这稍微灵活一些,因为如果你只是想重新调整最大值,你可以传入下限为 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"))

https://i.imgur.com/i9SLv5v.png

reprex package (v0.3.0) 于 2021 年 2 月 5 日创建

我承认这个例子的区别不是很明显,但是如果你仔细观察,你会发现最大值是一样的,红线比蓝线低。

编辑:

这种方法现在已在 ggh4x 包的 help_secondary() 函数中被捕获和扩展。免责声明:我是 ggh4x 的作者。


这是一个很好的解决方案 - 我唯一要添加的是这些范围函数上的“rm.na = TRUE”,以防被绘制的数据有一些 NA 值
这是一个很好的建议谢谢!我将其包含在上面的答案中
@HenryHolm 你是如何删除第二个轴的 NA 值的?我认为是因为这个我得到了! transformation for secondary axes must be monotonic
这应该在列表中更高 - 对于那些双轴实际上是一个好主意的 0.1% 的情况,这是一种看似简单而优雅的解决问题的方法,而无需诉诸丑陋的 hack。
S
Stas Prihod'co

以下文章帮助我将 ggplot2 生成的两个图组合在一行上:

Multiple graphs on one page (ggplot2) by 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)

multiplot 函数发生了什么?尽管我已经安装并加载了 ggplot2 库,但我收到一个找不到该函数的错误。
@Danka multiplot 函数是一个自定义函数(在链接页面的底部)。
可以加剧情吗?
最近,有许多软件包比 multiplot stackoverflow.com/a/51220506 具有更多的选项/功能
u
user4786271

对我来说,棘手的部分是弄清楚两个轴之间的转换函数。我为此使用了 myCurveFit

> 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轴进行“归一化”

https://i.stack.imgur.com/rukrP.png

转换函数:f(y1) = 0.025*x + 2.75

y2 --> y1 该函数用于将第一个 y 轴的断点转换为第二个 y 轴的值。请注意,轴现在已交换。

https://i.stack.imgur.com/F1OVB.png

转换函数: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")

https://i.stack.imgur.com/UyF42.png


R 可以做这种事情,coef(lm(c(-70, -110) ~ c(1,0)))coef(lm(c(1,0) ~ c(-70, -110)))。您可以定义一个辅助函数,例如 equationise <- function(range = c(-70, -110), target = c(1,0)){ c = coef(lm(target ~ range)) as.formula(substitute(~ a*. + b, list(a=c[[2]], b=c[[1]]))) }
是的,我知道...只是认为该网站会更直观
D
Demo

我们绝对可以使用基本 R 函数 plot 构建具有双 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))

a
ambrish dhaka

这似乎是一个简单的问题,但它围绕 2 个基本问题令人困惑。 A)如何在比较图表中呈现多标量数据,其次,B)这是否可以在没有 R 编程的一些经验法则的情况下完成,例如 i)融合数据,ii)刻面,iii)添加现有一层的另一层。下面给出的解决方案满足上述两个条件,因为它无需重新调整数据即可处理数据,其次,没有使用提到的技术。

https://i.stack.imgur.com/ybr4U.jpg

对于那些有兴趣了解更多有关此方法的人,请点击下面的链接。 How to plot a 2- y axis chart with bars side by side without re-scaling the data


R
Richard Border

总有办法的。

这是一个允许完全任意轴而无需重新缩放的解决方案。这个想法是生成两个图,除了轴之外相同,然后使用 cowplot 包中的 insert_yaxis_grobget_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')))

https://i.stack.imgur.com/JjI4q.png


D
David Arenburg

您可以对变量使用 facet_wrap(~ variable, ncol= ) 来创建新的比较。它不在同一个轴上,但它是相似的。


b
bonna

我承认并同意 hadley(和其他人)的观点,即单独的 y 尺度“存在根本缺陷”。话虽如此 - 我经常希望 ggplot2 具有该功能 - 特别是当数据在 wide-format 中时,我很快想要可视化或检查数据(即仅供个人使用)。

虽然 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")

在撰写本文时,ggplot2 已经通过 sec_axis 支持此功能。
K
Kieran Martin

我发现这个 answer 对我帮助最大,但发现它似乎无法正确处理一些边缘情况,特别是负面情况,以及我的限制距离为 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


S
Stephen

下面结合了 Dag Hjermann 的基本数据和编程,改进了 user4786271 的策略以创建“转换函数”以最佳地组合图和数据轴,并回应 baptist 的注释,即这样的函数可以在 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)")

最值得注意的是,一个新的“转换函数”只使用来自每个轴的数据集的两个数据点——通常是每组的最大值和最小值,效果更好。产生的两个回归的斜率和截距使 ggplot2 能够精确地配对每个轴的最小值和最大值的图。正如 user4786271 所指出的,这两个回归转换了每个数据集并绘制到另一个数据集。将第一个 y 轴的断点转换为第二个 y 轴的值。第二个根据第一个 y 轴将辅助 y 轴的数据转换为“标准化”。以下输出显示了轴如何对齐每个数据集的最小值和最大值:

https://i.stack.imgur.com/xTwzN.png

使最大值和最小值匹配可能是最合适的;然而,这种方法的另一个好处是,如果需要,可以通过更改与主轴数据相关的编程线来轻松移动与辅助轴相关的绘图。下面的输出只是将 y1 编程行中的最小降水量输入更改为“0”,从而将最小温度水平与“0”降水量水平对齐。

从:y1<-(c(max(climate$Precip), min(climate$Precip)))

至:y1<-(c(max(climate$Precip), 0))

https://i.stack.imgur.com/SfWS7.png

请注意生成的新回归和 ggplot2 如何自动调整绘图和轴以正确地将最低温度与“0”降水水平的新“基础”对齐。同样,可以轻松提升温度图,使其更加明显。下图是通过简单地将上述行更改为:

“y1<-(c(150, 55))”

上面的线告诉温度图的最大值与“150”降水水平一致,温度线的最小值与“55”降水水平一致。同样,请注意 ggplot2 和生成的新回归输出如何使图形与轴保持正确对齐。

https://i.stack.imgur.com/OLWX5.png

以上可能不是理想的输出;但是,它是如何轻松操作图形并且在图和轴之间仍然具有正确关系的示例。 Dag Hjermann 主题的结合提高了与情节对应的轴的识别。

https://i.stack.imgur.com/HjyWG.png


C
Community

The answer by Hadley 对 Stephen Few 的报告 Dual-Scaled Axes in Graphs Are They Ever the Best Solution? 提供了一个有趣的参考。

我不知道 OP 对“计数”和“速率”的含义,但快速搜索会得到 Counts and Rates,因此我得到了一些有关北美登山事故的数据1

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

然后我尝试按照上述报告第 7 页的建议绘制图表(并按照 OP 的要求将计数绘制为条形图,将比率绘制为折线图):

另一个不太明显的解决方案(仅适用于时间序列)是通过显示每个值与参考(或索引)值之间的百分比差异,将所有值集转换为共同的定量尺度。例如,选择一个特定的时间点,例如图表中出现的第一个区间,并将每个后续值表示为它与初始值之间的百分比差异。这是通过将每个时间点的值除以初始时间点的值,然后将其乘以 100 以将比率转换为百分比来完成的,如下所示。

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))
  )

https://i.stack.imgur.com/mBDDN.png

但我不是很喜欢它,我不能轻易地在它上面加上一个传奇......

1 威廉姆森、杰德等人。 2005 年北美登山事故。登山者书籍,2005 年。


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅