【问题标题】:topoplot in ggplot2 – 2D visualisation of e.g. EEG dataggplot2 中的拓扑图 - 例如的 2D 可视化脑电图数据
【发布时间】:2016-05-03 08:14:16
【问题描述】:

ggplot2 可以用来生成所谓的拓扑图(常用于神经科学)吗?

样本数据:

   label          x          y     signal
1     R3 0.64924459 0.91228430  2.0261520
2     R4 0.78789621 0.78234410  1.7880972
3     R5 0.93169511 0.72980685  0.9170998
4     R6 0.48406513 0.82383895  3.1933129

Full sample data.

行代表单个电极。列 xy 表示投影到 2D 空间中,列 signal 本质上是表示在给定电极上测量的电压的 z 轴。

stat_contour 不起作用,显然是由于网格不相等。

geom_density_2d 仅提供xy 的密度估计。

geom_raster 不适合这项任务,或者我必须不正确地使用它,因为它很快就会耗尽内存。

不需要平滑(如右图所示)和头部轮廓(鼻子、耳朵)。

我想避免使用 Matlab 并转换数据以使其适合这个或那个工具箱……非常感谢!

更新(2016 年 1 月 26 日)

我最接近目标的是通过

library(colorRamps)
ggplot(channels, aes(x, y, z = signal)) + stat_summary_2d() + scale_fill_gradientn(colours=matlab.like(20))

生成这样的图像:

更新 2(2016 年 1 月 27 日)

我用完整数据尝试了@alexforrence 的方法,结果如下:

这是一个很好的开始,但有几个问题:

  1. 最后一次调用 (ggplot()) 在 Intel i7 4790K 上大约需要 40 秒,而 Matlab 工具箱几乎可以立即生成这些;我上面的“紧急解决方案”大约需要一秒钟。
  2. 如您所见,中心部分的上下边框似乎被“切片”了——我不确定是什么原因造成的,但这可能是第三个问题。
  3. 我收到以下警告:

    1: Removed 170235 rows containing non-finite values (stat_contour). 
    2: Removed 170235 rows containing non-finite values (stat_contour). 
    

更新 3(2016 年 1 月 27 日)

用不同的interp(xo, yo)stat_contour(binwidth) 值生成的两个图之间的比较:

如果选择低interp(xo, yo),则边缘参差不齐,在本例中为xo/yo = seq(0, 1, length = 100)

【问题讨论】:

    标签: r ggplot2 neuroscience eeglab


    【解决方案1】:

    这是一个潜在的开始:

    首先,我们将附加一些包。我正在使用akima 进行线性插值,虽然看起来 EEGLAB 使用了某种球面插值 here?(尝试使用的数据有点稀疏)。

    library(ggplot2)
    library(akima)
    library(reshape2)
    

    接下来,读入数据:

    dat <- read.table(text = "   label          x          y     signal
    1     R3 0.64924459 0.91228430  2.0261520
    2     R4 0.78789621 0.78234410  1.7880972
    3     R5 0.93169511 0.72980685  0.9170998
    4     R6 0.48406513 0.82383895  3.1933129")
    

    我们将插入数据,并将其粘贴到数据框中。

    datmat <- interp(dat$x, dat$y, dat$signal, 
                     xo = seq(0, 1, length = 1000),
                     yo = seq(0, 1, length = 1000))
    datmat2 <- melt(datmat$z)
    names(datmat2) <- c('x', 'y', 'value')
    datmat2[,1:2] <- datmat2[,1:2]/1000 # scale it back
    

    我将借用一些以前的答案。下面的circleFun 来自Draw a circle with ggplot2

    circleFun <- function(center = c(0,0),diameter = 1, npoints = 100){
      r = diameter / 2
      tt <- seq(0,2*pi,length.out = npoints)
      xx <- center[1] + r * cos(tt)
      yy <- center[2] + r * sin(tt)
      return(data.frame(x = xx, y = yy))
    }
    
    circledat <- circleFun(c(.5, .5), 1, npoints = 100) # center on [.5, .5]
    
    # ignore anything outside the circle
    datmat2$incircle <- (datmat2$x - .5)^2 + (datmat2$y - .5)^2 < .5^2 # mark
    datmat2 <- datmat2[datmat2$incircle,]
    

    我真的很喜欢R plot filled.contour() output in ggpplot2 中等高线图的外观,所以我们会借用那个。

    ggplot(datmat2, aes(x, y, z = value)) +
      geom_tile(aes(fill = value)) +
      stat_contour(aes(fill = ..level..), geom = 'polygon', binwidth = 0.01) +
      geom_contour(colour = 'white', alpha = 0.5) +
      scale_fill_distiller(palette = "Spectral", na.value = NA) + 
      geom_path(data = circledat, aes(x, y, z = NULL)) +
      # draw the nose (haven't drawn ears yet)
      geom_line(data = data.frame(x = c(0.45, 0.5, .55), y = c(1, 1.05, 1)), 
                aes(x, y, z = NULL)) +
      # add points for the electrodes
      geom_point(data = dat, aes(x, y, z = NULL, fill = NULL), 
                 shape = 21, colour = 'black', fill = 'white', size = 2) +
      theme_bw()
    


    通过 cmets 中提到的改进(在 interp 调用中分别设置 extrap = TRUElinear = FALSE 以填补空白并进行样条平滑,并在绘图前移除 NA),我们得到:


    mgcv 可以做球面样条。这将替换 akima(不需要包含 interp() 的块)。

    library(mgcv)
    spl1 <- gam(signal ~ s(x, y, bs = 'sos'), data = dat)
    # fine grid, coarser is faster
    datmat2 <- data.frame(expand.grid(x = seq(0, 1, 0.001), y = seq(0, 1, 0.001)))
    resp <- predict(spl1, datmat2, type = "response")
    datmat2$value <- resp
    

    【讨论】:

    • 这很棒,尤其是作为“潜在的开始”,非常感谢!不幸的是,似乎有几个问题,主要是 a)最后一次调用在 Intel i7 4790K 上大约需要 40 秒,而 Matlab 工具箱几乎可以立即生成这些(为什么会这样?),b)我收到警告关于删除的行,并且 c)情节似乎在中心部分周围“切片”(请在几分钟内查看我更新的问题)。如果您愿意使用它,我还在原始样本下方添加了给定时间点的完整数据。
    • 太棒了,谢谢!它不仅看起来很棒并且可以完成工作,而且您的描述也很有教育意义。这仍然需要大量时间,但我注意到如果我将interp() xo/yo = length 减少到 100,它看起来实际上 相同并且只需要大约 3 秒。提高stat_countour() binwidth to 0.1 几乎是瞬间完成的。边缘有点粗糙(图像越大,“像素化”边缘越多),但也许有一种方法可以将填充延伸到圆外一点,然后通过掩盖外部来将其切断?查看我的更新。
    • 另外,如果您有机会了解 EEGLAB 是如何做到的,我们将不胜感激。
    • 如果可以的话,还有一件事:在我的数据的某些其他时间点,该图似乎包含诸如颜色级别之间的显着直线(我的意思是颜色之间的对比度)之类的模式,这应该'不在那里(即使没有加快速度的调整)。这是由于插值问题吗?可以修吗?
    • 我可能不小心复制了失败的张量样条尝试,试试s() 而不是te()
    猜你喜欢
    • 2011-01-04
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多