Подтвердить что ты не робот

Спиральный барплот с использованием ggplot & coord_polar (Condegram)

Я хотел бы создать график штрихов на архимедовой спирали, как обсуждалось здесь.

С конечной целью чего-то вроде this, но менее подавляющим.

Здесь образец кадра данных:

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

Я могу сделать гистограмму, используя следующий код:

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

И я могу сделать спираль, используя следующий код:

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

Но как (если вообще) я могу построить полосы на спирали?

Это примерно так же близко, как и я: создание спирали с моими данными, а не приведенная выше формула. Но мои данные фактически не отображаются...

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

Ответ 1

Интересный вопрос. Чтобы сделать это правильно с помощью баров, нам нужно использовать полигоны, чтобы правильно учитывать "деформацию" каждого угла. Этот график будет выглядеть лучше, чем больше баров за каждый цикл, но вы можете изменить пределы y, чтобы избежать сильных искажений в центре. Вам придётся придумать какой-либо способ красиво пометить ось y, но coord_polar не очень хорош в этом, чтобы начать с.

library(tidyverse)

Сначала создайте образец df с нуля:

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) 

Или, работая из существующего df:

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

Продолжите следующее:

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

введите описание изображения здесь

Альтернативой является просто создание круговой тепловой карты:

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

введите описание изображения здесь