Topoplot in ggplot2 - 2D rendering, for example. EEG data

Can ggplot2 be used to create the so-called poplar field (often used in neuroscience)?

topoplot

Sample data:

  label xy 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.

Rows are separate electrodes. Columns x and y represent the projection into 2D space, and the signal column is essentially the z axis, representing the voltage measured on this electrode.

stat_contour does not work, apparently due to an uneven grid.

geom_density_2d provides only an estimate of the density of x and y .

geom_raster not suitable for this task, or I should use it incorrectly, as it quickly ran out of memory.

Smoothing (as in the image on the right) and head contours (nose, ears) are not needed.

I want to avoid Matlab and convert the data so that it matches one or another set of tools ... Thanks a lot!

Update (January 26, 2016)

The closest I could reach my goal with is

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

which creates such an image:

enter image description here

Update 2 (January 27, 2016)

I tried the @alexforrence approach with full data and this is the result:

@ alexforrence's approach

This is a great start, but there are a couple of problems:

  • The last call ( ggplot() ) takes about 40 seconds on the Intel i7 4790K, while the Matlab toolbars allow you to create them almost instantly; my "emergency solution above takes about a second."
  • As you can see, the upper and lower borders of the central part look β€œchopped” - I'm not sure what causes this, but this may be the third problem.
  • I get the following warnings:

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

Update 3 (January 27, 2016)

Comparison of two graphs obtained with different values ​​of interp(xo, yo) and stat_contour(binwidth) :

comparison between different values

Torn edges, if you select low interp(xo, yo) , in this case xo / yo = seq(0, 1, length = 100) :

ragged edges

+7
r ggplot2 eeglab
source share
1 answer

This is where the launch starts:

First we will add some packages. Am I using akima to perform linear interpolation, although it seems like EEGLAB is using some kind of spherical interpolation here? (data was a bit rare to try).

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

Further, reading in the data:

 dat <- read.table(text = " label xy 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") 

We will interpolate the data and stick to it in the data frame.

 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 

I am going to borrow some of the previous answers. circleFun below 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,] 

And I really liked the look of the contour of the contour in R plot fill.contour () in ggpplot2 , so we'll take it.

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

enter image description here


With the improvements mentioned in the comments (setting extrap = TRUE and linear = FALSE in the interp call to fill in the gaps and smooth the splines, respectively, and remove the NA before building), we get:

enter image description here


mgcv can execute spherical splines. This replaces akima (a piece containing interp () is not required).

 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 

enter image description here

+8
source share

All Articles