2017-01-12 22 views
11

Chciałbym utworzyć wykres słupkowy na spirali Archimedesa, jak omówione here.Spirala barplot za pomocą ggplot & coord_polar (Condegram)

Z celem końcowym podobnym do this, ale mniej przytłaczającym.

Oto dataframe próbki:

test <- structure(list(month = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 
      year = c(2015, 2015, 2015, 2015, 2015, 2015, 2015, 
        2015, 2015, 2015, 2015, 2015, 2016, 2016, 
        2016, 2016, 2016, 2016, 2016, 2016, 2016, 
        2016, 2016, 2016), 
      value = c(49, 34, 35, 34, 50, 35, 48, 50, 44, 38, 42, 
        43, 33,30, 42, 43, 58, 55, 47, 36, 35, 53, 
        61, 59)), 
      .Names = c("month", "year", "value"), 
      class = "data.frame", row.names = c(NA, -24L)) 

mogę zrobić wykres słupkowy, stosując następujący kod:

ggplot(monthly, aes(x = ym, y = value)) + 
     geom_bar(stat = "identity") 

I mogę zrobić spiralę, stosując następujący kod:

a <- 0 #Any number here & it still looks the same to me... 
    b <- 10 #Any number here & it still looks the same to me... 
    theta <- seq(0,10*pi, 0.01) 
    r <- a + b*theta 
    df <- data.frame(x = r*cos(theta), y = r*sin(theta)) 
    ggplot(df, aes(x,y)) + 
     geom_point(col = 'red') 

Ale jak (jeśli w ogóle) mogę wykreślić paski na spirali?

To jest tak blisko, jak to zrobiłem: tworzenie spirali z moich danych zamiast powyższej formuły. Ale moje dane nie są wyświetlane ...

d <- ggplot(monthly, aes(x = month, y = month, color = year)) + 
     geom_path(size = 2) + 
     coord_polar() + 
     theme_minimal() + 
     theme(legend.position = "none") 
    d 

Odpowiedz

12

Zabawne pytanie. Aby zrobić to poprawnie za pomocą pasków, musimy użyć wielokątów, aby poprawnie uwzględnić "wypaczenie" każdego narożnika. Ten wykres będzie wyglądał lepiej, im więcej słupków na cykl masz, ale możesz zmienić limity y, aby uniknąć silnych zniekształceń w środku. Będziesz musiał wymyślić jakiś sposób, by dobrze opisać oś y, ale na początku nie jest to zbyt dobre.

library(tidyverse) 

pierwsze, albo utworzyć przykładową df od podstaw:

monthly <- 
    expand.grid(month = 1:12, year = factor(unique(monthly$year))) %>% 
    mutate(value = runif(n(), 10, 20), 
     y = as.numeric(year) - 1 + (month - 1)/12) 

Albo, pracujący z istniejącego DF:

monthly <- monthly %>% 
     mutate(y = as.numeric(year) - 1 + (month - 1)/12) 

dalej z następujących czynności:

bars <- monthly %>% 
    mutate(value_norm = value/(max(value) * 1.1), 
     xmin = month - 0.5, 
     xmax = month + 0.5, 
     ymin = y, 
     ymax = y + value_norm) 
# we could plot `bars` here, but things will not line up nicely, since 
# the bar will be nice and flat, but it needs to curve with the spiral. 

poly <- bars %>% 
    rowwise() %>% 
    do(with(., data_frame(year = year, 
         month = month, 
         x = c(xmin, xmax, xmax, xmin), 
         y = c(ymin - 1/24, 
           ymin + 1/24, 
           ymax + 1/24, 
           ymax - 1/24)))) 

ggplot(poly, aes(x, y, fill = interaction(month, year))) + 
    geom_polygon(col = 1) + 
    coord_polar() + 
    ylim(-3, 5) + 
    viridis::scale_fill_viridis(discrete = TRUE, option = 'C') + 
    scale_x_continuous(breaks = 1:12, labels = month.name) + 
    theme_minimal() + 
    theme(legend.position = "none", axis.text.y = element_blank(), 
     axis.title = element_blank()) 

enter image description here

Alternatywą jest po prostu zrobić spiralę mapę cieplną:

bars2 <- monthly %>% 
    mutate(xmin = month - 0.5, 
     xmax = month + 0.5, 
     ymin = y, 
     ymax = y + 1) 

poly2 <- bars2 %>% 
    rowwise() %>% 
    do(with(., data_frame(value = value, 
         year = year, 
         month = month, 
         x = c(xmin, xmax, xmax, xmin), 
         y = c(ymin - 1/24, ymin + 1/24, ymax + 1/24, ymax - 1/24)))) 

enter image description here

+2

This.is.awesome. –

+1

To jest świetne! Odpowiedź została zaakceptowana. Poprawiłem przykładowy plik df i wprowadziłem kilka zmian w kodzie. Może istnieć lepszy sposób na zachowanie elastyczności kodu w przypadku, gdy jest więcej niż 24 wiersze, ale nrow() wydaje się działać dla mnie. 3 pytania: Jak mogę pokolorować paski zgodnie z ich wartością? Zmiana na wypełnienie = wartość tworzy coś, co wygląda jak gwiazda ninja. Propozycje? Czy możesz dodać kod do wykreślenia mapy ciepła? Wreszcie, wciąż pracuję nad tym, jak to dostosować, aby narysować wiele słupków miesięcznie, na przykład jeden słupek na wartość dzienną. Pomysły powitane! – jesstme

+1

Wyjaśniłem, jak manipulować kolorem. Nadal mam nadzieję na wskazówki dotyczące codziennych wartości w każdym miesiącu i roku. 'ggplot (poly, aes (x, y, grupa = interakcja (miesiąc, rok))) + geom_polygon (aes (wypełnienie = wartość, kolor = rok), rozmiar = 1) + coord_polar()' – jesstme

Powiązane problemy