Andrew Clark

Amongst interactive chart options for R, plotly (aided by its wrapper function for ggplot2) is the pre-eminent, interactive chart

Carson Sievert has been the driving force behind development of the package and he recently held a webinar to supplement the excellent under development book

Here I am focusing on a couple of functions to aid highlighting and provide animation using some English soccer data

Goal Scoring in the Premier League

Firstly, the add_fun() function to easily highlight specific lines. The equivalent coverage from his book can be found here

Manchester United won 13 of the first 21 Premier League titles but have struggled over the past four seasons in spite of spending a shedload of cash on transfer fees and salaries. This chart highlights their continuing struggle to score goals


First load libraries and import one dataset which tracks each teams’ league position by round of competition

library(plotly)
library(tidyverse)
library(crosstalk)
library(htmltools)

#load and display dataset
standings <- readRDS("data/standings.rds")
glimpse(standings)
## Observations: 19,378
## Variables: 20
## $ season        <chr> "2004/05", "2004/05", "2004/05", "2004/05", "200...
## $ final_Pos     <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ team          <chr> "Chelsea", "Chelsea", "Chelsea", "Chelsea", "Che...
## $ OppTeam       <chr> "Newcastle U", "Man. Utd.", "Charlton", "Bolton"...
## $ GF            <int> 1, 3, 1, 2, 3, 0, 1, 3, 4, 1, 3, 1, 0, 1, 3, 2, ...
## $ GA            <int> 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, ...
## $ gameDate      <date> 2005-05-15, 2005-05-10, 2005-05-07, 2005-04-30,...
## $ tmGameOrder   <int> 506, 505, 504, 503, 502, 501, 500, 499, 498, 497...
## $ tmYrGameOrder <int> 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, ...
## $ venue         <chr> "A", "A", "H", "A", "H", "H", "H", "A", "H", "H"...
## $ MATCHID       <int> 5285, 5277, 5265, 5253, 5243, 5235, 5217, 5212, ...
## $ points        <dbl> 1, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 1, 3, 3, 3, ...
## $ cumGF         <int> 72, 71, 68, 67, 65, 62, 62, 61, 58, 54, 53, 50, ...
## $ cumGA         <int> 15, 14, 13, 13, 13, 12, 12, 11, 10, 9, 9, 8, 8, ...
## $ cumPts        <dbl> 95, 94, 91, 88, 85, 82, 81, 80, 77, 74, 71, 68, ...
## $ cumGD         <int> 57, 57, 55, 54, 52, 50, 50, 50, 48, 45, 44, 42, ...
## $ allGames      <int> 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, ...
## $ position      <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ res           <chr> "Draw", "Win", "Win", "Win", "Win", "Draw", "Dra...
## $ tt            <chr> "<table cellpadding='4' style='line-height:1'><t...

The fields Of interest are team, season, tmYrGameOrder (the number of games played) and cumGF (the cumulative number of Goals scored).

With 25 lines to show, it is probably inappropriate to apply a color to each season, although plotly offers the option to toggle lines on/off by clicking the legend. Let’s just start with a a barebones example which, on hovering, shows the x and y axis information

# Limit to one team and group dataset for subsequent highlighting
allYears <- standings %>% 
  filter(team=="Man. Utd.") %>% 
  group_by(season) 

# create and display line chart
p <-allYears %>% 
  plot_ly(x=~tmYrGameOrder,y=~cumGF) %>% 
  add_lines(color=I('lightgrey'))


p

I would to enhance this initial plot in three respects

  • Highlight specific seasons
  • Improve tooltip to show hovered season
  • Tidy up look of chart

Of these, the one of major new interest is the first where a function can be created and applied. I wish to highlight the latest two years to compare the impact of new manager Mourinho and a bunch of new players with the turgid football under the previous top dog, van Gaal

# function with one variable, season and enhanced tooltip

layer_season <- function(plot, name) {
  plot %>% filter(season == name) %>% add_lines(name = name,
                                                hoverinfo="text",
                                                text=~paste0(season,
                                                             "<br>Pl: ",tmYrGameOrder,
                                                             "<br>Gls: ",cumGF))
}

# Set title font characteristics
t <- list(
  family = "sans serif",
  size = 18,
  color = 'red')

## plot all years
p <-allYears %>% 
  plot_ly(x=~tmYrGameOrder,y=~cumGF) %>% 
  add_lines(color=I('lightgrey'), name="EPL Seasons",
            hoverinfo="text",
            text=~paste0(season,
                         "<br>Pl: ",tmYrGameOrder,
                         "<br>Gls: ",cumGF)) %>% 
## highlight last two years  
  add_fun(layer_season,"2015/16") %>% 
  add_fun(layer_season,"2016/17") %>% 
## Improve layout  
  layout(hovermode="closest",
    title="Man. Utd. Cumulative Goals-For by Game by PL Season",
    titlefont=t,
         xaxis=list(title="Games Played"),
         yaxis=list(title="Goals Scored")) %>% 
   config(displayModeBar = F,showLink = F)
p

So an improvement over last year but at the time of writing (after 31 games) still the worst output bar last season
N.B. As I update the standings file this will change


I have previously touched on the sharedData option and this can easily be adapted so that we can look at any of the 47 teams that have graced the Premier League, to date

Just press the down-button in the select box and choose a team

# Exclude filter for individual team
allTeamYears <- standings %>% 
  group_by(season,team) 



sd <- SharedData$new(allTeamYears)


fs <- filter_select(
id = "team",
label = "Select Team",
sharedData = sd,
group =  ~ team,
allLevels = FALSE,
multiple = FALSE
)


## this is needed as crosstalk does not work nicely with bootstrap, apparently
fs_nobootstrap <- fs

attr(fs_nobootstrap, "html_dependencies") <- Filter(
  function(dep) {dep$name != "bootstrap"},
  attr(fs_nobootstrap, "html_dependencies")
)


 
 ## plot all years
 myChart  <-sd %>% 
  plot_ly(x=~tmYrGameOrder,y=~cumGF) %>% 
  add_lines(color=I('lightgrey'), name="EPL Seasons",
            hoverinfo="text",
            text=~paste0(season,
                         "<br>Pl: ",tmYrGameOrder,
                         "<br>Gls: ",cumGF)) %>% 
# highlight current season if team is in PL
   add_fun(layer_season,"2016/17") %>% 
## Improve layout  
  layout(hovermode="closest",
    title="Cumulative Goals-For by Game by PL Season",
    titlefont=t,
         xaxis=list(title="Games Played"),
         yaxis=list(title="Goals Scored")) %>% 
   config(displayModeBar = F,showLink = F)



## combine the selector and chart

 
  tagList(
  fs_nobootstrap,
   myChart
)