2016-10-16 13 views
5

Chcę utworzyć nowy typ Geom: geom_ohlc(), który jest czymś w rodzaju Wykresów świecowych, aby wykreślić czas otwarcia od najwyższego do najniższego poziomu zamknij dane.

Po opanowaniu tej Hadley's article: próbowałem to:

GeomOHLC <- ggproto(`_class` = "GeomOHLC", `_inherit` = Geom, 

       required_aes = c("x", "op", "hi", "lo", "cl"), 

       draw_panel = function(data, panel_scales, coord){ 

        coords <- coord$transform(data, panel_scales) 
        browser() # <<-- here is where I found the problem 
        grid::gList(
        grid::rectGrob(
         x = coords$x, 
         y = pmin(coords$op, coords$cl), 
         vjust = 0, 
         width = 0.01, 
         height = abs(coords$op - coords$cl), 
         gp = grid::gpar(col = coords$color, fill = "yellow") 
        ), 
        grid::segmentsGrob(
         x0 = coords$x, 
         y0 = coords$lo, 
         x1 = coords$x, 
         y1 = coords$hi 
         ) 
        ) 
       }) 
    geom_ohlc <- function(data = NULL, mapping = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) 
    { 
     layer(
     geom = GeomOHLC, mapping = mapping, data = data, 
     stat = stat, position = position, show.legend = show.legend, 
     inherit.aes = inherit.aes, params = list(na.rm = na.rm, ...) 
    ) 
    } 
    dt <- data.table(x = 1:10, open = 1:10, high = 3:12, low = 0:9, close = 2:11) 
    p <- ggplot(dt, aes(x = x, op = open, hi = high, lo = low, cl = close)) + 
     geom_ohlc() 
    p 

dla uproszczenia, ja po prostu nie wziąć pod uwagę kolor paska.

Działka wynik jest tak:

screenshot

dodaję browser() wewnątrz ggproto funkcję, a okazało się, że coord$transform nie przekształcić op, hi, lo, cl estetykę w interverl [ 0,1]. Jak rozwiązać ten problem?

Co więcej, czy istnieją inne dokumenty na temat tworzenia własnego typu Geom oprócz tego artykułu Hadley?

+0

Wina wydaje się być 'transform_position()' wywoływana przez funkcję w 'coord $ transform'. Kod pokazuje, że przekształci tylko kolumny w data.frame o nazwie 'x' i' y'. Nie znam rozwiązania twojego problemu, ale spróbowałbym się zastanowić, czy * potrzebujesz ich * do przeskalowania (?). – ddiez

+0

Chociaż w drugiej chwili ten sam kod sugeruje również, że kilka skal to "x" i/lub "y". Może coś tam jest? – ddiez

+0

Ponadto funkcją 'ggplot2 ::: aes_to_scale' jest odwzorowywanie nazw' data.frame' na to, czy są to skale "x" lub "y". Patrząc na dokumentację, należy użyć "" x "," xmin "," xmax "," xend "," xintercept "' lub odpowiednika estetyki dla osi y. Wspomniano go również w '? Transform_position'. Myślę, że jeśli potrafisz wymyślić sposób na odwzorowanie zmiennych na te, które rozwiążesz swój problem. – ddiez

Odpowiedz

2

Jak wspomniano w komentarzach w pytaniu OP, problemem jest aes_to_scale() funkcja wewnątrz transform_position(), która z kolei jest wywoływana przez coord$transform. Transformacje są ograniczone do zmiennych o nazwie x, xmin, xmax, xend, xintercept i odpowiedników dla osi y. To jest wymienione w pomocy dla transform_position:

Description

Convenience function to transform all position variables.

Usage

transform_position(df, trans_x = NULL, trans_y = NULL, ...) Arguments

trans_x, trans_y Transformation functions for x and y aesthetics. (will transform x, xmin, xmax, xend etc) ... Additional arguments passed to trans_x and trans_y.

Rozwiązaniem byłoby używać tych nazw zmiennych zamiast nazw zmiennych używanych przez PO. Poniższy kod działa przy transformacji zmiennych, ale kończy się niepowodzeniem w innym miejscu (patrz na końcu). Nie znam szczegółów planowanego spisku, więc nie próbowałem naprawiać tego błędu.

GeomOHLC <- ggproto(
    `_class` = "GeomOHLC", 
    `_inherit` = Geom, 

    required_aes = c("x", "yintercept", "ymin", "ymax", "yend"), 

    draw_panel = function(data, panel_scales, coord) { 
    coords <- coord$transform(data, panel_scales) 
    #browser() # <<-- here is where I found the problem 
    grid::gList(
     grid::rectGrob(
     x = coords$x, 
     y = pmin(coords$yintercept, coords$yend), 
     vjust = 0, 
     width = 0.01, 
     height = abs(coords$op - coords$cl), 
     gp = grid::gpar(col = coords$color, fill = "yellow") 
    ), 
     grid::segmentsGrob(
     x0 = coords$x, 
     y0 = coords$ymin, 
     x1 = coords$x, 
     y1 = coords$ymax 
    ) 
    ) 
    } 
) 
geom_ohlc <- 
    function(data = NULL, 
      mapping = NULL, 
      stat = "identity", 
      position = "identity", 
      na.rm = FALSE, 
      show.legend = NA, 
      inherit.aes = TRUE, 
      ...) 
    { 
    layer(
     geom = GeomOHLC, 
     mapping = mapping, 
     data = data, 
     stat = stat, 
     position = position, 
     show.legend = show.legend, 
     inherit.aes = inherit.aes, 
     params = list(na.rm = na.rm, ...) 
    ) 
    } 
dt <- 
    data.table(
    x = 1:10, 
    open = 1:10, 
    high = 3:12, 
    low = 0:9, 
    close = 2:11 
) 
p <- 
    ggplot(dt, aes(
    x = x, 
    yintercept = open, 
    ymin = high, 
    ymax = low, 
    yend = close 
)) + 
    geom_ohlc() 
p 

ten przekształca zmienne, ale produkuje się następujący błąd:

Error in unit(height, default.units) : 
    'x' and 'units' must have length > 0 

Ale miejmy nadzieję, stąd może być wykonane do pracy.

UWAGA: Wybrałem odwzorowanie pomiędzy oryginalnymi nazwami zmiennych (op, hi, lo, cl) raczej arbitralnie. Specjalnie yintercept nie wydaje się dobrze pasować. Może istnieje potrzeba wspierania dowolnych nazw zmiennych skali w ggplot2?

+0

Myślę, że masz rację. Próbuję zmienić nazwy kolumn 'danych' wewnątrz funkcji' draw_panel', od 'op, hi, lo, cl' do' y, ymax, ymin, yend'. Następnie 'coords $ transfrom'" wie ", aby przekształcić te kolumny w [0, 1]. –