使用ggplot和coord_polar(Condegram)制作螺旋条形图

12

我想在一个阿基米德螺旋线上创建一张条形图,就像这里讨论的那样 here.

最终目标是得到类似于这个,但更简单。

这是一个示例数据框:

    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
1个回答

18

一个有趣的问题。要正确地使用条形图,我们需要使用多边形来正确计算每个角的“扭曲”。这个图表将会更好看,如果你每个周期有更多的条形图,但你可以改变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) 

或者,从现有的数据框中工作:
    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())

enter image description here

另一种选择是制作螺旋状的热力图:

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


1
太好了!答案被接受了。我修复了提供的示例df并在您的代码中进行了一些更改。如果有超过24行,可能有更好的方法来保持代码的灵活性,但nrow()对我来说似乎很有效。有3个问题:如何根据值着色条形图?将fill = value更改为某些东西会创建类似忍者星的东西。有什么建议吗?此外,您可以添加绘制热图的代码吗?最后,我仍在努力调整此设置以每月绘制多个条形图,例如每日值一个条形图。欢迎提出想法! - jesstme
1
已经弄清楚如何操作颜色。仍然希望能够在每个月和年份内绘制每日值的指导。ggplot(poly, aes(x, y, group = interaction(month, year))) + geom_polygon(aes(fill = value, colour = year), size = 1) + coord_polar() - jesstme
1
我知道我没有提供一个完全灵活的函数,但它应该相对容易适应。y = as.numeric(year) - 1 + (month - 1) / 12 将需要更改,对于天数,它将类似于 y = as.numeric(year) - 1 + (day - 1) / 365。多边形需要调整 1/730 而不是 1/24 - Axeman
是的,将分组与填充分开是实现按值着色的方法。 - Axeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接