Including images on axis label in an animated ggplot2

浪子不回头ぞ 提交于 2020-01-01 05:42:12

问题


I created an animated bar plot displaying goals scored by players (fictional).

Please see the reproduced data for the example:

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)

Following animated bar plot are created by the code below.

# loading required
library(tidyverse)
library(gganimate)
library(png)

Edited: I would like to include following icons for each player:

icon1.png <- image_read('https://raw.githubusercontent.com/sialbi/examples/master/player1.png')
icon2.png <- image_read('https://raw.githubusercontent.com/sialbi/examples/master/player2.png')
icon3.png <- image_read('https://raw.githubusercontent.com/sialbi/examples/master/player3.png')
icon4.png <- image_read('https://raw.githubusercontent.com/sialbi/examples/master/player4.png')

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

gap %>%
  group_by(Player) %>%
  arrange(Gameday) %>%
  mutate(prev.rank = lag(rank)) %>%
  ungroup() %>%

  group_by(Gameday) %>%
  arrange(rank, prev.rank) %>%
  mutate(x = seq(1, n())) %>%
  ungroup() %>%

  ggplot(aes(x = x, y = Goals, fill = Player, color = Player)) +
  geom_col() +
  geom_text(aes(y = 0, label = Player), size = 5, color="black", hjust = -0.05) +
  geom_text(aes(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 = 26),
        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')

Problem

To complete the animation I would like to include a picture of each player on the y axis. Below I edited the animation to display the desired result (the circles were chosen to avoid violating any copyrights).

The images (circles) should also move up and down as the bars.

Is there are way to include images on the y-axis?

Edited Code

After the presented suggestions I was able to fix the problems. The code below is working accordingly.

library(imager)
library(ggimage)
library(magick)
library(tidyverse)
library(gganimate)
library(png)
library(gapminder)


 #read data
 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)

# import images
df2 <- data.frame(Player = c("Aguero", "Salah", "Aubameyang", "Kane"),
              Image = sample(c("https://raw.githubusercontent.com/sialbi/examples/master/player1.png",
                        "https://raw.githubusercontent.com/sialbi/examples/master/player2.png",
                        "https://raw.githubusercontent.com/sialbi/examples/master/player3.png",
                        "https://raw.githubusercontent.com/sialbi/examples/master/player4.png")),
              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 = gap %>%
  left_join(df2, by = "Player") %>% # add image file location to the dataframe being
  group_by(Player) %>%
  arrange(Gameday) %>%
  mutate(prev.rank = lag(rank)) %>%
  ungroup() %>%      
  group_by(Gameday) %>%
  arrange(rank, prev.rank) %>%
  mutate(x = seq(1, n())) %>%
  ungroup()

ggplot(p, aes(x = x, y = Goals, fill = Player, color = Player)) +
  geom_col() +
  geom_text(aes(y = 0, label = Player), size = 5, color="black", hjust = -0.05) +
  geom_text(aes(label = Value_lbl), hjust = 0) +

  # where the error occurs 
  geom_image(aes(x = x, Image = Image), y = 0,  
             size = 0.25, hjust = 1,
             inherit.aes = FALSE) +

  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_classic() +
  theme(plot.title = element_text(hjust = 0, size = 26),
        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')


回答1:


You can try the following:

Step 0. Create png images for use, because I don't want to worry about copyright violations either.

emoji.list <- c("grinning", "smile", "heart_eyes", "smirk")
for(i in seq_along(emoji.list)) {
  ggsave(paste0("icon", i, ".png"),
         ggplot() + 
           emojifont::geom_emoji(alias = emoji.list[i], size = 10, vjust = 0.5) +
           theme_void(),
         width = 0.4, height = 0.4, units = "in")
}
rm(emoji.list, i)

Step 1. Create a data frame mapping each player to the location of his image file.

df2 <- data.frame(Player = c("Aguero", "Salah", "Aubameyang", "Kane"),
                  Image = c("icon1.png", "icon2.png", "icon3.png", "icon4.png"),
                  stringsAsFactors = F)

Step 2. Add image to plot in a new geom_image layer, & animate everything as before.

library(ggimage)

gap %>%
  left_join(df2, by = "Player") %>% # add image file location to the dataframe being
                                    # passed to ggplot()      
  group_by(Player) %>%
  arrange(Gameday) %>%
  mutate(prev.rank = lag(rank)) %>%
  ungroup() %>%      
  group_by(Gameday) %>%
  arrange(rank, prev.rank) %>%
  mutate(x = seq(1, n())) %>%
  ungroup() %>%

  ggplot(aes(x = x, y = Goals, fill = Player, color = Player)) +
  geom_col() +
  geom_text(aes(y = 0, label = Player), size = 5, color="black", hjust = -0.05) +
  geom_text(aes(label = Value_lbl), hjust = 0) +

  geom_image(aes(x = x, image = Image), y = 0,  # add geom_image layer
             size = 0.25, hjust = 1,
             inherit.aes = FALSE) +

  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_classic() +
  theme(plot.title = element_text(hjust = 0, size = 26),
        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')



来源:https://stackoverflow.com/questions/54973129/including-images-on-axis-label-in-an-animated-ggplot2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!