How does gganimate order an ordered bar time-series?

前端 未结 2 1382
孤城傲影
孤城傲影 2020-12-14 12:17

I have a time-series of data, where I\'m plotting diagnosis rates for a disease on the y-axis DIAG_RATE_65_PLUS, and geographical groups for comparison on the x

2条回答
  •  萌比男神i
    2020-12-14 12:55

    To add on to @eipi10's great answer, I think this is a case where it's worth replacing geom_bar for more flexibility. geom_bar is normally quite convenient for discrete categories, but it doesn't let us take full advantage of gganimate's silky-smooth animation glory.

    For instance, with geom_tile, we can recreate the same appearance as geom_bar, but with fluid movement on the x-axis. This helps to keep visual track of each bar and to see which bars are shifting order the most. I think this addresses the 2nd part of your question nicely.

    To make this work, we can add to the data a new column showing the ordering that should be used at each month. We save this order as a double, not an integer (by using* 1.0). This will allow gganimate to place a bar at position 1.25 when it's animating between position 1 and 2.

    df2 <- df %>%
      group_by(ACH_DATEyearmon) %>%
      mutate(ordering = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
      ungroup() 
    

    Now we can plot in similar fashion, but using geom_tile instead of geom_bar. I wanted to show the NAME both on top and at the axis, so I used two geom_text calls with different y values, one at zero and one at the height of the bar. vjust lets us align each vertically using text line units.

    The other trick here is to turn off clipping in coord_cartesian, which lets the bottom text go below the plot area, into where the x-axis text would usually go.

    p <- df2 %>%
      ggplot(aes(ordering, group = NAME)) +
    
      geom_tile(aes(y = DIAG_RATE_65_PLUS/2, 
                    height = DIAG_RATE_65_PLUS,
                    width = 0.9), alpha = 0.9, fill = "gray60") +
      # text on top of bars
      geom_text(aes(y = DIAG_RATE_65_PLUS, label = NAME), vjust = -0.5) +
      # text in x-axis (requires clip = "off" in coord_cartesian)
      geom_text(aes(y = 0, label = NAME), vjust = 2) +
      coord_cartesian(clip = "off", expand = FALSE) +
    
      labs(title='{closest_state}', x = "") +
      theme(plot.title = element_text(hjust = 1, size = 22),
            axis.ticks.x = element_blank(),
            axis.text.x  = element_blank()) + 
    
      transition_states(ACH_DATEyearmon, 
                        transition_length = 2, state_length = 1) +
      ease_aes('cubic-in-out')
    
    animate(p, nframes = 300, fps = 20, width = 400, height = 300)
    

    Back to your first question, here's a color version that I made by removing fill = "gray60" from the geom_tile call. I sorted the NAME categories in order of Aug 2017, so they will look sequential for that one, as you described.

    There's probably a better way to do that sorting, but I did it by joining df2 to a table with just the Aug 2017 ordering.

    Aug_order <- df %>%
      filter(ACH_DATEyearmon == "Aug 2017") %>%
      mutate(Aug_order = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
      select(NAME, Aug_order)
    
    df2 <- df %>%
      group_by(ACH_DATEyearmon) %>%
      mutate(ordering = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
      ungroup() %>%
      left_join(Aug_order) %>%
      mutate(NAME = fct_reorder(NAME, -Aug_order))
    

提交回复
热议问题