【问题标题】:Animated sorted bar chart: problem with overlapping bars动画排序条形图:重叠条的问题
【发布时间】:2019-07-22 09:47:14
【问题描述】:

我创建了一个动画条形图,其中显示了一些球员的进球数。整个代码下方显示了我是如何输出的。

动画效果如愿。但是,具有相同值的条形重叠。

我想防止条重叠。最好的情况是先得分的玩家显示在同等级的其他玩家之上。

在动画开始时得分相同的玩家的顺序无关紧要。

library(tidyverse)
library(gganimate)
theme_set(theme_classic())

df <- data.frame(Player = rep(c("Aguero", "Salah", "Aubameyang", "Kane"), 6), 
                 Team = rep(c("ManCity", "Liverpool", "Arsenal", "Tottenham"), 6), 
                 Gameday = c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6),
                 Goals = c(0,1,2,0,1,1,3,1,2,1,3,2,2,2,4,3,3,2,4,5,5,3,5,6),
                 stringsAsFactors = F)

gap <- df %>%
  group_by(Gameday) %>%
  mutate(rank = min_rank(-Goals) * 1,
     Value_rel = Goals/Goals[rank==1],
     Value_lbl = paste0(" ", Goals)) %>%
  filter(rank <=10) %>%
  ungroup()

p <- ggplot(gap, aes(rank, group = Player, stat = "identity",
                 fill = as.factor(Player), color = as.factor(Player))) +
  geom_tile(aes(y = Goals/2,
            height = Goals,
            width = 0.9), alpha = 0.8, color = NA) +
  geom_text(aes(y = 0, label = paste(Player, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y=Goals,label = Value_lbl, hjust=0)) +
  coord_flip(clip = "off", expand = FALSE) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  guides(color = FALSE, fill = FALSE) +
  labs(title = "Gameday {closest_state}", x="", y = "Goals scored") +
  theme(plot.title = element_text(hjust = 0, size = 22),
       axis.ticks.y = element_blank(),  # These relate to the axes post-flip
       axis.text.y  = element_blank(),  # These relate to the axes post-flip
       plot.margin = margin(1,1,1,4, "cm")) +
  transition_states(Gameday, transition_length = 4, state_length = 1) +
  ease_aes('cubic-in-out')

p

代码输出如下图:

补充说明:

最后,应该根据下面的示例显示条形。为了提高可读性,条形图最好不要处于相同的高度。

非常感谢您的努力!

【问题讨论】:

    标签: r ggplot2 gganimate


    【解决方案1】:

    根据澄清编辑解决方案:

    gap %>%
    
      # for each player, note his the rank from his previous day
      group_by(Player) %>%
      arrange(Gameday) %>%
      mutate(prev.rank = lag(rank)) %>%
      ungroup() %>%
    
      # for every game day,
      # sort players by rank & break ties by previous day's rank
      group_by(Gameday) %>%
      arrange(rank, prev.rank) %>%
      mutate(x = seq(1, n())) %>%
      ungroup() %>%
    
      ggplot(aes(x = x, y = Goals, fill = Player, color = Player)) +
      # geom_tile(aes(y = Goals/2, height = Goals, width = width)) +
      geom_col() +
      geom_text(aes(y = 0, label = Player), hjust = 1) +
      geom_text(aes(label = Value_lbl), hjust = 0) +
    
      # rest of the code below is unchanged from the question
      coord_flip(clip = "off", expand = FALSE) +
      scale_y_continuous(labels = scales::comma) +
      scale_x_reverse() +
      guides(color = FALSE, fill = FALSE) +
      labs(title = "Gameday {closest_state}", x="", y = "Goals scored") +
      theme(plot.title = element_text(hjust = 0, size = 22),
            axis.ticks.y = element_blank(), 
            axis.text.y  = element_blank(),
            plot.margin = margin(1,1,1,4, "cm")) +
      transition_states(Gameday, transition_length = 4, state_length = 1) +
      ease_aes('cubic-in-out')
    

    原解决方案:

    gap %>%
    
      # for each player, note his the rank from his previous day
      group_by(Player) %>%
      arrange(Gameday) %>%
      mutate(prev.rank = lag(rank)) %>%
      ungroup() %>%
    
      # for every game day & every rank,
      # reduce tile width if there are multiple players sharing that rank, 
      # sort players in order of who reached that rank first, 
      # & calculate the appropriate tile midpoint depending on how many players are there
      group_by(Gameday, rank) %>%
      mutate(n = n_distinct(Player)) %>%
      mutate(width = 0.9 / n_distinct(Player)) %>%
      arrange(prev.rank) %>%
      mutate(x = rank + 0.9 * (seq(1, 2 * n() - 1, by = 2) / 2 / n() - 0.5)) %>%
      ungroup() %>%
    
      ggplot(aes(x = x, fill = Player, color = Player)) +
      geom_tile(aes(y = Goals/2, height = Goals, width = width)) +
      geom_text(aes(y = 0, label = Player), hjust = 1) +
      geom_text(aes(y = Goals, label = Value_lbl), hjust = 0) +
    
      # rest of the code below is unchanged from the question
      coord_flip(clip = "off", expand = FALSE) +
      scale_y_continuous(labels = scales::comma) +
      scale_x_reverse() +
      guides(color = FALSE, fill = FALSE) +
      labs(title = "Gameday {closest_state}", x="", y = "Goals scored") +
      theme(plot.title = element_text(hjust = 0, size = 22),
            axis.ticks.y = element_blank(), 
            axis.text.y  = element_blank(),
            plot.margin = margin(1,1,1,4, "cm")) +
      transition_states(Gameday, transition_length = 4, state_length = 1) +
      ease_aes('cubic-in-out')
    

    注意:这并不完美。我想如果有太多玩家/太多天,上面用于确定同一天/排名内的玩家顺序的简单逻辑将不理想,因为它只能向后看一天。但它适用于这个例子,而且我对足球的了解还不够(至少我认为这是足球?)来推断你的用例。

    【讨论】:

    • 解决方案很有希望。但我想以不同的高度显示条形图。我已经通过可视化调整了我的问题。
    【解决方案2】:

    一个更简单的解决方案:您只需要排名是目标和球员姓名的顺序 (无需记住上周排名或担心玩家数量 - 只要他们的名字不同,条不会重叠)

    library(tidyverse)
    library(gganimate)
    theme_set(theme_classic())
    
    df <- data.frame(Player = rep(c("Aguero", "Salah", "Aubameyang", "Kane"), 6), 
                     Team = rep(c("ManCity", "Liverpool", "Arsenal", "Tottenham"), 6), 
                     Gameday = c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6),
                     Goals = c(0,1,2,0,1,1,3,1,2,1,3,2,2,2,4,3,3,2,4,5,5,3,5,6),
                     stringsAsFactors = F)
    
    gap <- df %>%
      group_by(Gameday) %>%
      mutate(rank1 = min_rank(-Goals) * 1,
             Value_rel = Goals/Goals[rank1==1],
             Value_lbl = paste0(" ", Goals)) %>%
      filter(rank1 <=10) %>%
      ungroup() %>%
      
      group_by(Gameday) %>%
      arrange(rank1, Player) %>%
      mutate(rank = seq(1, n())) %>%
      ungroup() 
    
    p <- ggplot(gap, aes(rank, group = Player, stat = "identity",
                         fill = as.factor(Player), color = as.factor(Player))) +
      geom_tile(aes(y = Goals/2,
                    height = Goals,
                    width = 0.9), alpha = 0.8, color = NA) +
      geom_text(aes(y = 0, label = paste(Player, " ")), vjust = 0.2, hjust = 1) +
      geom_text(aes(y=Goals,label = Value_lbl, hjust=0)) +
      coord_flip(clip = "off", expand = FALSE) +
      scale_y_continuous(labels = scales::comma) +
      scale_x_reverse() +
      guides(color = FALSE, fill = FALSE) +
      labs(title = "Gameday {closest_state}", x="", y = "Goals scored") +
      theme(plot.title = element_text(hjust = 0, size = 22),
            axis.ticks.y = element_blank(),  # These relate to the axes post-flip
            axis.text.y  = element_blank(),  # These relate to the axes post-flip
            plot.margin = margin(1,1,1,4, "cm")) +
      transition_states(Gameday, transition_length = 4, state_length = 1) +
      ease_aes('cubic-in-out')
    
    p
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-25
      • 1970-01-01
      • 2015-12-07
      • 2015-10-14
      相关资源
      最近更新 更多