如何区分ggplot线图中的跳转?

时间:2016-04-22 19:02:35

标签: r ggplot2

我正在处理包含(几个)跳转的信号,并希望通过将它们绘制为虚线来区分这些部分与实际信号。跳跃的确切位置是已知的。

下面是几乎(几乎)实现所需结果的几种方法,但对于这样一个看似简单的任务来说,它们对我来说都显得相当费力。主要问题似乎是,跳跃点之间没有数据点,可以设置为“NA”。

所以我想我的问题是,是否有更直接/简洁这样做?

示例数据和初始图。

library( "ggplot2")

s <- rep( sin( 2*pi*0:9/40), 2)
t <- seq_along( s)
jumps <- ifelse( t == 10 | t == 11, TRUE, FALSE)

ggplot() + geom_line( aes( t, s)) +
  geom_point( aes( t[ jumps], s[ jumps]), 'color' = 'red')

Initial
跳转发生在索引10和11之间(红点)。

变体1:将信号分成两个分支线。

s_on  <- ifelse( jumps, NA, s)
s_off <- ifelse( jumps, s, NA)

ggplot() + geom_line( aes( t, s_on)) +
  geom_line( aes( t, s_off), 'linetype' = 2)

Variant1
我能想到的最直接的解决方案,但实际信号部分缺少跳跃点。

变式2:照亮跳跃部分。

s_off <- ifelse( jumps, s, NA)

ggplot() + geom_line( aes( t, s)) +
  geom_line( aes( t, s_off), 'linetype' = 2, 'color' = 'white', 'alpha' = .8)

enter image description here
结果看起来更好,但并不完美。

变式3:为间隙附加中间点。

t_jumps  <- t[ jumps]
odd_idxs <- rep_len( c( TRUE, FALSE), length( t_jumps))
t_gaps   <- ( t_jumps[ odd_idxs] + t_jumps[ !odd_idxs]) / 2
s_gaps   <- rep( NA, length( t_gaps))

s_off <- ifelse( jumps, s, NA)

ggplot() + geom_line( aes( c( t, t_gaps), c( s, s_gaps))) +
  geom_line( aes( t, s_off), 'linetype' = 2)

enter image description here
完美的结果,但相当错综复杂。

变式4:过采样。

t_os <- seq( min( t), max( t), 'by' = .5)
s_os <- approx( t, s, t_os)$y

jumps_os <- approx( t, jumps, t_os)$y >= 1
gaps_os  <- c( FALSE, jumps_os[ -length( jumps_os)]) & c( jumps_os[ -1], FALSE)

s_os_on  <- ifelse( gaps_os, NA, s_os)
s_os_off <- ifelse( jumps_os, s_os, NA)

ggplot() + geom_line( aes( t_os, s_os_on)) +
  geom_line( aes( t_os, s_os_off), 'linetype' = 2)

enter image description here
完美的结果,但也相当错综复杂。

编辑:以下是实际数据的摘录。索引50和51之间有一个跳转的100个数据点。数据没有时间码,但是连续采样没有任何间隙;即,索引可以被解释为时间码。连续值通常非常接近,因此如果两个连续值之间的差异大于某个阈值(在这种情况下> 0.5),我们就会跳跃。

s <- c(1.11297501465306, 0.998232815600932, 1.00542810484767, 0.882111160457134, 
   0.864832695387304, 0.875465966481715, 0.814592253696173, 0.911200049519539, 
   0.729520738497376, 0.643376989290118, 0.511524957325309, 0.421549461968243, 
   0.499176602717489, 0.638274888228625, 0.641277324035764, 0.822692758217454, 
   0.653877788316458, 0.662919995840639, 0.752974952850491, 0.59309477712959, 
   0.706765754334629, 0.686750632990152, 0.665331035014242, 0.757375655323267, 
   0.754760862141848, 0.597661179304123, 0.765902449004352, 0.66198324309662, 
   0.723390854336321, 0.877095195278525, 1.0325927500613, 1.22280563246459, 
   1.21561478627846, 1.05408674599603, 1.22628475017846, 1.15282000247389, 
   1.14075413802639, 1.16317573199049, 1.29142561722547, 1.3457714674063, 
   1.29182361606508, 1.28387220101431, 1.1401680175215, 1.03548344178125, 
   1.17217653244734, 1.29718279903755, 1.49284766763449, 1.58462042240426, 
   1.53352373661473, 1.5376752092503, 0.709300844464451, 0.740689239930362, 
   0.703234727680683, 0.587989527359605, 0.716839470714331, 0.71350401584059, 
   0.578017875924706, 0.661974735092372, 0.705410783644766, 0.549552099686116, 
   0.438565947301686, 0.457195165939629, 0.292463065031916, 0.144086477160454, 
   0.241596068348736, 0.394813115056604, 0.573318116273731, 0.476153524685651, 
   0.362233571987599, 0.245603948552161, 0.120956567674875, 0.000272847153246339, 
   -0.14302936391905, -0.0648500232025982, -0.135479792486876, -0.183215864375234, 
   -0.0843432129360736, -0.171867656242102, -0.0671323497779668, 
   -0.237922695651651, -0.169482465460897, -0.00180741865187888, 
   0.108692320249975, 0.20488171428442, 0.132713130954653, 0.186498426925391, 
   0.159074306581169, 0.0921048566699027, 0.193063378147781, 0.00139091908931722, 
   -0.0429555546492339, -0.121841486822814, -0.254593643080443, 
   -0.20847160955891, -0.374809342063964, -0.488266025483608, -0.289662906434387, 
   -0.439308459591121, -0.621471555065364, -0.461930149141699)

1 个答案:

答案 0 :(得分:1)

我最终创建了一个新的ggplot geom (基于geom_linerange)我打电话给 geom_conline (对于连线),基本上是geom_line添加了属性con (用于连接)。它需要一个布尔矢量,您可以在其中为每个点指定,如果它应该连接到下一个点。

这稍微改变了表示不连续性的向量格式(以前的#39;跳转&#39;现在&#39;连接&#39;在示例中)。

s <- rep( sin( 2*pi*0:9/40), 2)
t <- seq_along( s)
connections <- ifelse( t == 10, FALSE, TRUE)

ggplot() +
  geom_conline( aes( t, s, 'con' = connections)) +
  geom_conline( aes( t, s, 'con' = !connections), 'linetype' = 2)

enter image description here

<强> geom_conline:

geom_conline <- function(
  mapping     = NULL,
  data        = NULL,
  stat        = "identity",
  position    = "identity",
  ...,
  na.rm       = FALSE,
  show.legend = NA,
  inherit.aes = TRUE
)
{
  layer(
    data        = data,
    mapping     = mapping,
    stat        = stat,
    geom        = GeomConLine,
    position    = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params      = list(
      na.rm = na.rm,
      ...
    )
  )
}

GeomConLine <- ggproto(
  "GeomConLine",
  Geom,
  default_aes  = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
  draw_key     = draw_key_vpath,
  # required_aes = c("x", "ymin", "ymax"),
  required_aes = c("x", "y", "con"),
  draw_panel   = function( data, panel_scales, coord) {
    # data <- transform(data, xend = x, y = ymin, yend = ymax)
    data <- subset(
      transform(
        data,
        'xend' = c( x[ 2:nrow( data)], NA),
        'yend' = c( y[ 2:nrow( data)], NA),
        'con' = c( con[ 1:nrow( data)-1], FALSE)
      ),
      'subset' = con,
      'select' = -con
    )
    ggplot2:::ggname("geom_stem", GeomSegment$draw_panel(data, panel_scales, coord))
  }
)