11

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.

enter image description here

# 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?

enter image description here

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

enter image description here

Albin
  • 822
  • 1
  • 7
  • 25

1 Answers1

8

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

animated plot

Z.Lin
  • 28,055
  • 6
  • 54
  • 94
  • Thank you for your submission. With your help I was able to import and include the images, but somehow R replaced the icons with the _r-logo_. Is there a package missing? – Albin Mar 06 '19 at 18:19
  • you need to post the code that you used that caused the error. Otherwise it is very hard for us to understand where you went wrong. – Arthur Yip Mar 06 '19 at 22:53
  • @niblaAS What do your `icon1.png` / `icon2.png` / etc. look like? – Z.Lin Mar 07 '19 at 02:29
  • @ArthurYip I edited my code and marked where the error probably occurs – Albin Mar 07 '19 at 11:48
  • @Z.Lin I added the images below. Are they not accessible with the link? – Albin Mar 07 '19 at 11:49
  • you have a typo - icon4 should be icon4.png : df2 <- data.frame(Player = c("Aguero", "Salah", "Aubameyang", "Kane"), Image = c("icon1.png", "icon2.png", "icon3.png", "icon4"), stringsAsFactors = F) – Arthur Yip Mar 08 '19 at 00:15
  • @ArthurYip sadly that does not have change something on the output – Albin Mar 08 '19 at 13:37
  • 1
    @niblaAS In step 1, the `Image` column should contain the path to the actual image, i.e. `Image = c("https://raw.githubusercontent.com/sialbi/examples/master/player1.png", ...)`. There's no need to load the images via `image_read`. You can refer to the `geom_image` example in ggimage's [vignette](https://cran.r-project.org/web/packages/ggimage/vignettes/ggimage.html). – Z.Lin Mar 08 '19 at 13:41
  • niblAS - were you able to find a solution for this. kind of having the same issue. always get "rstudio logo" pics shown. – TomTe Nov 25 '19 at 23:51