топоплот в ggplot2-2D визуализация, например, данных ЭЭГ


Можно ли использовать 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

Полный образец данных.

Ряды представляют собой отдельные электроды. Столбцы x и y представляют собой проекцию в двумерное пространство, а столбец signal по существу является осью z, представляющей напряжение, измеренное на данном электроде.

stat_contour не работает, видимо, из-за неравноправия сетка.

geom_density_2d только обеспечивает оценку плотности x и y.

geom_raster он не подходит для этой задачи, или я должен использовать его неправильно, так как он быстро заканчивается в памяти.

Сглаживание (как на изображении справа) и контуры головы (нос, уши) не требуются.

Я хочу избежать Matlab и преобразования данных так, чтобы они соответствовали тому или иному набору инструментов... большое спасибо!

Обновление (26 Января 2016)

Самое близкое, на что я был способен. добраться до моей цели можно через

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

Который производит изображение, подобное этому:

Введите описание изображения здесь

Обновление 2 (27 Января 2016 Г.)

Я попробовал подход @alexforrence с полными данными, и вот результат:

подход @ alexforrence

Это отличное начало, но есть пара проблем:

  1. последний вызов (ggplot()) занимает около 40 секунд на Intel i7 4790K, в то время как MATLAB toolboxes удается генерировать их почти мгновенно; мой ‘экстренное решение " выше занимает около секунды.
  2. Как вы можете видеть, верхняя и нижняя границы центральной части кажутся "разрезанными" – я не уверен, что вызывает это, но это может быть третья проблема.
  3. Я получаю эти предупреждения:

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

Обновление 3 (27 Января 2016 Г.)

Сравнение двух графиков, полученных с различными значениями interp(xo, yo) и stat_contour(binwidth):

сравнения между различными ценностями

Рваные края, если выбрать низкий interp(xo, yo), в это дело xo/yo = seq(0, 1, length = 100):

рваный край

1 7

1 ответ:

Вот потенциальное начало:

Сначала мы прикрепим несколько пакетов. Я использую akima для линейной интерполяции, хотя похоже, что EEGLAB использует здесь какую-то сферическую интерполяцию ? (данные были немного скудными, чтобы попробовать это).

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 ниже от ничья круг с 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() выводится в 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()

Введите описание изображения здесь


С улучшениями, упомянутыми в комментариях (установка extrap = TRUE и linear = FALSE в вызове interp для заполнения пробелов и сглаживания сплайнов, соответственно, и удаление NAs перед построением графика), мы получаем:

Введите описание изображения здесь


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

Введите описание изображения здесь