Home > Software engineering >  Making the images go over the barcharts in ggplot
Making the images go over the barcharts in ggplot

Time:10-06

I have a ggplot with a few issues that I'm trying to solve. It's inspired by enter image description here

My questions:

  • I'm showing the top 3 and bottom 3 teams. I want to indicate this somehow on the plot. How do add text on the x-axis which groups them into top 3 and bottom 3?
  • The logo for Wolfsburg is partially hidden. How do I make the logos either go at the end of the barchart, or above, so that they are fully visible?

My code:

data <- tibble(
  Diff_home_perc = c(-0.3, -0.2, -0.1,-0.05, 0.2, 0.3),
  Team = c("A", "B", "C","D", "E", "F"),
  ind = c("Green","Green","Green","Red","Red","Red"),
  image = list(
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-00000G.svg"),
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-000017.svg"),
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-000018.svg"),
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-000003.svg"),
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-000004.svg"),
    image_read_svg("https://www.bundesliga.com/assets/clublogo/DFL-CLU-00000.svg")
  )
)

g=ggplot(data, aes(reorder(Team, Diff_home_perc),Diff_home_perc, fill = ind, image = image))  
  ylab("Ratio of points from home games") ylim(-0.3,0.3) ylab("Difference") xlab("Team") 
  geom_isotype_col(
    img_height = NULL, img_width = grid::unit(0.5, "null"),
    ncol = 1, nrow = 1, hjust = 0.5, vjust = 0
  )  
  guides(fill = "none") 
  theme_minimal() theme(
    plot.title = element_blank(),
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    text = element_text(size=15),legend.title = element_blank(),legend.position="none")

CodePudding user response:

The easy part is the axis text, e.g. you could add some labels for the groups via scale_x_discrete(labels = c("", "Bottom 3", "", "", "Top 3", "")). Another option would be to make use of faceting.

Concerning the positioning of the logos. I'm not sure whether this could be achieved via ggtextures. As far as I get it ggtextures is meant to add textures on column charts, which probably is the reason why one of the logos gets clipped off. Instead I would suggest to make use of the ggtext package which allows to add logos as text labels and gives you a lot of control on where to put the logos. One drawback is that ggtext does not work with svg so you first have to download the logos and convert them to png.

library(magick)
#> Linking to ImageMagick 6.9.12.3
#> Enabled features: cairo, fontconfig, freetype, heic, lcms, pango, raw, rsvg, webp
#> Disabled features: fftw, ghostscript, x11

# download svgs, convert to png and save
urls <- paste0(
  "https://www.bundesliga.com/assets/clublogo/DFL-CLU-",
  c("00000G", "000017", "000018", "000003", "000004", "000005"),
  ".svg"
)
lapply(urls, function(x) download.file(x, destfile = fs::path_file(x)))
fn <- fs::path_file(urls)
lapply(fn, function(x) image_write(image_convert(image_read_svg(x)), path = gsub("\\.svg", ".png", x), format = "png"))

library(tidyverse)
library(ggtext)

data <- tibble(
  Diff_home_perc = c(-0.3, -0.2, -0.1, -0.05, 0.2, 0.3),
  Team = c("A", "B", "C", "D", "E", "F"),
  ind = c("Green", "Green", "Green", "Red", "Red", "Red"),
  label = gsub("\\.svg", ".png", fs::path_file(fn)),
  vjust = ifelse(Diff_home_perc < 0, 0, 1)
)
data$label <- paste0("<img src='", data$label, "' width = '40'/>")
data$vjust <- ifelse(abs(data$Diff_home_perc) < .1, 1 - data$vjust, data$vjust)
ggplot(data, aes(reorder(Team, Diff_home_perc), Diff_home_perc, fill = ind))  
  ylab("Ratio of points from home games")  
  ylim(-0.3, 0.3)  
  ylab("Difference")  
  xlab("Team")  
  geom_col(position = "dodge2")  
  ggtext::geom_richtext(aes(label = label, vjust = vjust),
    label.colour = NA, fill = NA, label.padding = unit(c(0, 0.25, -.3, 0.25), "lines")
  )  
  guides(fill = "none")  
  theme_minimal()  
  theme(
    plot.title = element_blank(),
    axis.title.x = element_blank(),
    text = element_text(size = 15)
  )  
  scale_x_discrete(labels = c("", "Bottom 3", "", "", "Top 3", ""))

  • Related