Ggplot with geom_images help

I'm just learning R (about 4 months in) and am on the "making neat plots" part of the new user progression. I'm getting stuck on what is maybe a bit more advanced feature of a plot creation.

I've got a data frame (WPA) which has 32 rows (one for each team) and 3 columns that look like as an example

Team Offense_WPA Defense_WPA
ARI     .12      .09
BAL    -.01      .03

etc...

I'm able to get the scatterplot to work fine using this

ggplot(WPA, aes(x=Offense_WPA, y=Defense_WPA)) +
  geom_point() +
  geom_text_repel(aes(label=Team)) +
  geom_smooth(method=lm, se=FALSE, linetype="dashed",color="darkred")

Which creates

I'm then trying to add images of the team logos as the points. The package I am using (nflfastr) has a predefined list of teams and their respective logos (see this image)

There is a beginners guide too that has some pre-written code and they are using this for their example

qbs %>%
  ggplot(aes(x = cpoe, y = epa)) +
  #horizontal line with mean EPA
  geom_hline(yintercept = mean(qbs$epa), color = "red", linetype = "dashed", alpha=0.5) +
  #vertical line with mean CPOE
  geom_vline(xintercept =  mean(qbs$cpoe), color = "red", linetype = "dashed", alpha=0.5) +
  #add points for the QBs with the logos
  geom_image(aes(image = team_logo), size = qbs$n_plays / 45000, asp = 16 / 9) +
  #add names using ggrepel, which tries to make them not overlap
  geom_text_repel(aes(label=name)) +
  #add a smooth line fitting cpoe + epa
  stat_smooth(geom='line', alpha=0.5, se=FALSE, method='lm')+
  #titles and caption
  labs(x = "Completion % above expected (CPOE)",
       y = "EPA per play (passes, rushes, and penalties)",
       title = "Quarterback Efficiency, 2015 - 2019",
       caption = "Data: @nflfastR") +
  theme_bw() +
  #center title
  theme(
    aspect.ratio = 9 / 16,
    plot.title = element_text(size = 14, hjust = 0.5, face = "bold")
  ) +
  #make ticks look nice
  scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10))

Which produces this nice and clean plot

I'm really just trying to get the logos and worry about all the extra stuff later but I cannot get the images to be plotted.

I've tried a few different attempts

ggplot(WPA, aes(x=Offense_WPA, y=Defense_WPA)) +
  geom_point() +
  geom_text_repel(aes(label=Team)) +
  geom_smooth(method=lm, se=FALSE, linetype="dashed",color="darkred") +
  geom_image(inherit.aes = TRUE, image=team_logos)

which just produces

Error: Aesthetics must be either length 1 or the same as the data (32): image

and also

ggplot(WPA, aes(x=Offense_WPA, y=Defense_WPA)) +
  geom_point() +
  geom_text_repel(aes(label=Team)) +
  geom_smooth(method=lm, se=FALSE, linetype="dashed",color="darkred") +
  geom_image(aes(image=team_logos))

which errors out as

Don't know how to automatically pick scale for object of type spec_tbl_df/tbl_df/tbl/data.frame. Defaulting to continuous.
Error: Aesthetics must be either length 1 or the same as the data (32): image

Any help would be appreciated on how to get the team images as points.

Did you make team_logos a column of your WPA data.frame?

Ah, I did not! I thought I could reference a different data frame that held the team_logo information.

I just gave it a shot by merging my WPA df with the team_logo df and it worked. However is there a way to reference a different df there?

It's probably not a good idea, the whole point of having a data frame in the first place is that you can keep all your data together and process it together.

Technically though, there is no problem with giving a separate vector as mapping, but then you have to worry about the order of the rows etc. That was your problem here: Aesthetics must be either length 1 or the same as the data (32) means you were giving a vector of x, a vector of y, and a vector of image that was a different length, and probably not in the same order.

If you want to provide two data frames, that's also technically possible using the data= argument of all geoms. But again, that adds complexity in making sure you're providing the right data in the right order.

Thanks for your help. I was just looking for a way to avoid having to do a sort of rbind or merge every time as the logo information is not native to the main file of all the data that gets scraped, so it would always have to be:

Scrape main data
Clean main data
Merge logo data to main data

Thanks for your help!

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.