2016-01-08 9 views
6

Próbuję użyć nowej funkcjonalności ggplot2 w R, która pozwala na tworzenie własnych funkcji stat_. Tworzę prostą do obliczenia i wykreślenia interpolowanej powierzchni pomiędzy punktami ułożonymi na tablicy 2d.ggplot2 2.0 nowa funkcja stat_: ustawienie domyślnej skali dla podanej estetyki

ja chce utworzyć stat_topo() wymaga x, y i val estetykę wykreślając prostą geom_raster interpolowanych val mapowany fill.

library(ggplot2) 
library(dplyr) 
library(akima) 

cpt_grp <- function(data, scales) { 
    #interpolate data in 2D 
    itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T) 
    out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>% 
    mutate(fill=as.vector(itrp$z)) 
    # str(out) 
    return(out) 
} 

StatTopo <- ggproto("StatTopo", Stat, 
        compute_group = cpt_grp, 
        required_aes = c("x","y","val") 
) 
stat_topo <- function(mapping = NULL, data = NULL, geom = "raster", 
         position = "identity", na.rm = FALSE, show.legend = NA, 
         inherit.aes = TRUE, ...) { 
    layer(
    stat = StatTopo, data = data, mapping = mapping, geom = geom, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
    params = list(na.rm = na.rm, ...) 
) 
} 

set.seed(1) 
nchan <- 30 
d <- data.frame(val = rnorm(nchan), # some random values to be mapped to fill color 
     x = 1:nchan*cos(1:nchan), # the x and y position of the points to interpolate 
     y = 1:nchan*sin(1:nchan)) 
plot(d$x,d$y) 

ggplot(d,aes(x=x,y=y,val=val)) + 
    stat_topo() + 
    geom_point() 

Gdy uruchomię to pojawia się następujący błąd:

Error: numerical color values must be >= 0, found -1 

Rozumiem, że to dlatego, że jakoś skala fill estetyki jest ustawiony na dyskretne.

Jeśli wejdę w ten sposób:

ggplot(d,aes(x=x,y=y,val=val)) + 
    stat_topo() + 
    scale_fill_continuous() + 
    geom_point() 

mam co chciałem: spodziewany raster z ciągłej skali barw, co chcę stat_ zrobić domyślnie ...

enter image description here

Zgaduję, że pytanie brzmi: Jak mogę zapobiec ustawianiu dyskretnej skali przez ggplot tutaj i najlepiej ustawić domyślną skalę w ramach połączenia z moją nową funkcją stat_.

+0

I niby myśleć trzeba mieć sparowane 'geom' przejść z stat, aby uzyskać to, co chcesz domyślnie. –

Odpowiedz

2

Wygląda na to, że podczas tworzenia nowej zmiennej wewnątrz funkcji stat_ należy jawnie powiązać ją z estetyką, do której zostanie zmapowany z parametrem default_aes = aes(fill = ..fill..) w ramach definicji ggproto.

To mówi ggplot, że jest to obliczona estetyka i wybierze skalę na podstawie typu danych.

Więc musimy zdefiniować stat_ następująco:

cpt_grp <- function(data, scales) { 
    # interpolate data in 2D 
    itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T) 
    out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>% 
    mutate(fill=as.vector(itrp$z)) 
    # str(out) 
    return(out) 
} 

StatTopo <- ggproto("StatTopo", Stat, 
        compute_group = cpt_grp, 
        required_aes = c("x","y","val"), 
        default_aes = aes(fill = ..fill..) 
) 

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

Wtedy następujący kod:

set.seed(1) 
nchan <- 30 
d <- data.frame(val = rnorm(nchan), 
       x = 1:nchan*cos(1:nchan), 
       y = 1:nchan*sin(1:nchan)) 
ggplot(d,aes(x=x,y=y,val=val)) + 
    stat_topo() + 
    geom_point() 

Produkuje zgodnie z oczekiwaniami:

The result of stat_topo

Bez konieczności określić scale_ m co prawda, ale pozostawia możliwość łatwego dostosowania skali w zwykły sposób, na przykład za pomocą np.scale_fill_gradient2(low = 'blue',mid='white',high='red')

dostałem taką odpowiedź tutaj: https://github.com/hadley/ggplot2/issues/1481

+0

Hej, ukradłeś 15 punktów ode mnie. –

1

Dobra, spałem na nim i miałem pomysł, i myślę, że to może zrobić, co chcesz. W funkcji warstwy stat_topo zamiast ggproto zwróciłem listę z nią jako pierwszym elementem, a następnie dodałem do tej listy kolejne ggproto z wywołaniem do scale_fill_continuous().

library(ggplot2) 
library(dplyr) 
library(akima) 

cpt_grp <- function(data, scales) { 
    #interpolate data in 2D 
    itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T) 
    out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>% 
    mutate(fill=as.vector(itrp$z)) 
    return(out) 
} 
StatTopo <- ggproto("StatTopo", Stat, 
        compute_group = cpt_grp, 
        required_aes = c("x","y","val") 
) 
stat_topo <- function(mapping = NULL, data = NULL, geom = "raster", 
         position = "identity", na.rm = FALSE, show.legend = NA, 
         inherit.aes = TRUE, ...) { 
    list(
    layer(
     stat = StatTopo, data = data, mapping = mapping, geom = geom, 
     position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
     params = list(na.rm = na.rm) 
    ), 
    scale_fill_continuous() 
) 
} 
set.seed(1) 
nchan <- 30 
d <- data.frame(val = rnorm(nchan), # some random values to be mapped to fill color 
       x = 1:nchan*cos(1:nchan), # the x and y position of interp points 
       y = 1:nchan*sin(1:nchan)) 
ggplot(d,aes(x=x,y=y,val=val)) + 
    stat_topo() + 
    geom_point() 

uzyskując to samo zdjęcie jak powyżej.

+0

świetnie, dzięki! key tworzył listę w stat_topo. Próbowałem dodać je wcześniej, ale nie chciałem. – Max

+0

Nadal wydaje się, że jest coś podejrzanego w sposobie odwzorowania wartości w estetyce "wypełnienia". Złożyłem problem na githplot github. – Max