2011-06-20 8 views
9

Deseo representar la media (u otra función) del tiempo de reacción como una función de la ubicación del objetivo en el plano x y. Como datos de prueba:¿Puede GGPLOT hacer resúmenes 2D de datos?

library(ggplot2) 
xs <- runif(100,-1,1) 
ys <- runif(100,-1,1) 
rts <- rnorm(100) 
testDF <- data.frame("x"=xs,"y"=ys,"rt"=rts) 

Sé que puedo hacer esto:

p <- ggplot(data = testDF,aes(x=x,y=y))+geom_bin2d(bins=10) 

Lo que me gustaría ser capaz de hacer, es lo mismo pero trazar una función de los datos en cada bin en lugar de contar ¿Puedo hacer esto?

¿O necesito generar los medios condicional primero en R (por ejemplo, drt <- tapply(testDF$rt,list(cut(testDF$x,10),cut(testDF$y,10)),mean)) y luego trazar eso?

Gracias.

Respuesta

1

Esto resultó ser más difícil de lo que esperaba.

Puede casi truco ggplot para que haga esto, al ofrecer una estética weights, pero eso sólo le da la suma de los pesos en la papelera, no la media (y se tiene que especificar drop=FALSE para retener valores de ubicación negativas) También puede recuperar los recuentos o la densidad dentro de un contenedor, pero ninguno de esos realmente resuelve el problema.

Esto es lo que terminó con:

## breaks vector (slightly coarser than the 10x10 spec above; 
## even 64 bins is a lot for binning only 100 points) 
bvec <- seq(-1,1,by=0.25) 

## helper function 
tmpf <- function(x,y,z,FUN=mean,breaks) { 
    midfun <- function(x) (head(x,-1)+tail(x,-1))/2 
    mids <- list(x=midfun(breaks$x),y=midfun(breaks$y)) 
    tt <- tapply(z,list(cut(x,breaks$x),cut(y,breaks$y)),FUN) 
    mt <- melt(tt) 
    ## factor order gets scrambled (argh), reset it 
    mt$X1 <- factor(mt$X1,levels=rownames(tt)) 
    mt$X2 <- factor(mt$X2,levels=colnames(tt)) 
    transform(X, 
      x=mids$x[mt$X1], 
      y=mids$y[mt$X2]) 
} 

ggplot(data=with(testDF,tmpf(x,y,rt,breaks=list(x=bvec,y=bvec))), 
     aes(x=x,y=y,fill=value))+ 
    geom_tile()+ 
    scale_x_continuous(expand=c(0,0))+ ## expand to fill plot region 
    scale_y_continuous(expand=c(0,0)) 

Esto supone anchos de caja iguales, etc., podrían ser extendidas ... Realmente es una lástima que (por lo que puedo decir) stat_bin2d doesn' t aceptar una función especificada por el usuario.

+1

I quedan "objeto 'X' no encontrado", y cuando cambio la X a X en 'transformar() ', Obtengo" Error en eval (expr, envir, enclos): objeto 'mids' no encontrado ". –

11

actualización Con el lanzamiento de ggplot2 0.9.0, gran parte de esta funcionalidad está cubierto por las nuevas incorporaciones de stat_summary2d y stat_summary_bin.

aquí es una esencia de esta respuesta: https://gist.github.com/1341218

aquí es una ligera modificación de stat_bin2d con el fin de aceptar la función arbitraria:

StatAggr2d <- proto(Stat, { 
    objname <- "aggr2d" 
    default_aes <- function(.) aes(fill = ..value..) 
    required_aes <- c("x", "y", "z") 
    default_geom <- function(.) GeomRect 

    calculate <- function(., data, scales, binwidth = NULL, bins = 30, breaks = NULL, origin = NULL, drop = TRUE, fun = mean, ...) { 

    range <- list(
     x = scales$x$output_set(), 
     y = scales$y$output_set() 
    ) 

    # Determine binwidth, if omitted 
    if (is.null(binwidth)) { 
     binwidth <- c(NA, NA) 
     if (is.integer(data$x)) { 
     binwidth[1] <- 1 
     } else { 
     binwidth[1] <- diff(range$x)/bins 
     } 
     if (is.integer(data$y)) { 
     binwidth[2] <- 1 
     } else { 
     binwidth[2] <- diff(range$y)/bins 
     }  
    } 
    stopifnot(is.numeric(binwidth)) 
    stopifnot(length(binwidth) == 2) 

    # Determine breaks, if omitted 
    if (is.null(breaks)) { 
     if (is.null(origin)) { 
     breaks <- list(
      fullseq(range$x, binwidth[1]), 
      fullseq(range$y, binwidth[2]) 
     ) 
     } else { 
     breaks <- list(
      seq(origin[1], max(range$x) + binwidth[1], binwidth[1]), 
      seq(origin[2], max(range$y) + binwidth[2], binwidth[2]) 
     ) 
     } 
    } 
    stopifnot(is.list(breaks)) 
    stopifnot(length(breaks) == 2) 
    stopifnot(all(sapply(breaks, is.numeric))) 
    names(breaks) <- c("x", "y") 

    xbin <- cut(data$x, sort(breaks$x), include.lowest=TRUE) 
    ybin <- cut(data$y, sort(breaks$y), include.lowest=TRUE) 

    if (is.null(data$weight)) data$weight <- 1 
    ans <- ddply(data.frame(data, xbin, ybin), .(xbin, ybin), function(d) data.frame(value = fun(d$z))) 

    within(ans,{ 
     xint <- as.numeric(xbin) 
     xmin <- breaks$x[xint] 
     xmax <- breaks$x[xint + 1] 

     yint <- as.numeric(ybin) 
     ymin <- breaks$y[yint] 
     ymax <- breaks$y[yint + 1] 
    }) 
    } 
}) 

stat_aggr2d <- StatAggr2d$build_accessor() 

y uso:

ggplot(data = testDF,aes(x=x,y=y, z=rts))+stat_aggr2d(bins=3) 
ggplot(data = testDF,aes(x=x,y=y, z=rts))+ 
    stat_aggr2d(bins=3, fun = function(x) sum(x^2)) 

enter image description here

Además, aquí hay una ligera t modificación de stat_binhex:

StatAggrhex <- proto(Stat, { 
    objname <- "aggrhex" 

    default_aes <- function(.) aes(fill = ..value..) 
    required_aes <- c("x", "y", "z") 
    default_geom <- function(.) GeomHex 

    calculate <- function(., data, scales, binwidth = NULL, bins = 30, na.rm = FALSE, fun = mean, ...) { 
    try_require("hexbin") 
    data <- remove_missing(data, na.rm, c("x", "y"), name="stat_hexbin") 

    if (is.null(binwidth)) { 
     binwidth <- c( 
     diff(scales$x$input_set())/bins, 
     diff(scales$y$input_set())/bins 
    ) 
    } 

    try_require("hexbin") 

    x <- data$x 
    y <- data$y 

    # Convert binwidths into bounds + nbins 
    xbnds <- c(
     round_any(min(x), binwidth[1], floor) - 1e-6, 
     round_any(max(x), binwidth[1], ceiling) + 1e-6 
    ) 
    xbins <- diff(xbnds)/binwidth[1] 

    ybnds <- c(
     round_any(min(y), binwidth[1], floor) - 1e-6, 
     round_any(max(y), binwidth[2], ceiling) + 1e-6 
    ) 
    ybins <- diff(ybnds)/binwidth[2] 

    # Call hexbin 
    hb <- hexbin(
     x, xbnds = xbnds, xbins = xbins, 
     y, ybnds = ybnds, shape = ybins/xbins, 
     IDs = TRUE 
    ) 
    value <- tapply(data$z, [email protected], fun) 

    # Convert to data frame 
    data.frame(hcell2xy(hb), value) 
    } 


}) 

stat_aggrhex <- StatAggrhex$build_accessor() 

y uso:

ggplot(data = testDF,aes(x=x,y=y, z=rts))+stat_aggrhex(bins=3) 
ggplot(data = testDF,aes(x=x,y=y, z=rts))+ 
    stat_aggrhex(bins=3, fun = function(x) sum(x^2)) 

enter image description here

+1

+1 Gracias por publicar esto. Estudiaré esto con cuidado porque traté de hacer esta modificación pero no tuvo éxito. – Andrie

+0

+1 ¡Esto se ve genial! Quizás valga la pena cambiar 'function (x)' por 'function (z)' en los ejemplos de uso para mayor claridad. – Gregor

+0

@kohske: Solo una nota.Su fórmula y el ejemplo parecen no estar ajustados para aquellos sin su nivel de experiencia. –

Cuestiones relacionadas