Introduction: What is MLTP?



Tagpro is a capture the flag (CTF) web browser game played between two teams of four players each on a variety of tile-based maps. Each person plays as a two-dimensional, paint-filled ball traversing the game with up/down/left/right keypresses as input. In competitive play, teams consist of two offenders and two defenders. The central objective is to grab the opponent’s flag and carry it back without getting tagged with the imposition that teams may only capture if their flag is safe.

Offenders focus their efforts on grabbing the flag, holding the flag, staying alive until an opportunity arises, and then pushing into their own base to attempt to get a capture. Other duties include helping their defense tag or contain the enemy flag carrier, fighting for powerups, blocking adversaries to assist their teammates, and getting regrab. Regrab refers to the strategy of having one offender wait in the opponent’s base when their partner already has the opponent’s flag. If the offensive partner is popped, the other offender will instantly grab the flag when it teleports back to the opponent’s base.

Defenders will focus primarily on keeping the flag secure. When the flag is grabbed, the defenders are responsible for chasing the flag carrier and tagging him. When flag carriers are tagged, they pop, and the flag is teleported back to its home tile in the base. Other duties for defenders include fighting for powerups, blocking for their flag carrier, and playing anti-re. Anti-re, short for anti-regrab, is a strategy developed to counter regrab involving a player guarding the empty flag tile in their own base. The point of this maneuver is that once the enemy flag carrier dies and the flag teleports back, there is a player to defend the flag from the other team’s regrab.

With a basic understanding of the fundamentals of Tagpro, we can revisit the initial question: What is MLTP? MLTP is the premier level of competitive Tagpro in the North American scene; the acronym stands for Major League TagPro. I employ data visualization techniques to showcase the statistical categories MLTP players are judged upon and how the distributions evolved over time. Season 10 will be considered the first modern season for the purpose of this exploration for two primary reasons. First, it was the inaugural season for widely utilized anti-re in the competitive meta. Second, Season 10 was the first season that stats started being automatically recorded and imported to TagproLeague instead of manually entered into Excel documents. With the advent of TagproLeague came a variety of new metrics that were beyond the scope of the previous manual laborers.



Metrics for Player Evaluation



The main statistics used to holistically judge the performance of an offender are:

  • Captures: the number of times an offender scored
  • Grabs: the number of times an offender picked up the flag
  • Scoring percentage: \((\frac{Captures}{Grabs})*100\)
  • Powerups: the number of powerups a player picked up
  • Hold: the duration of time in seconds that an offender has the flag in their possession.

Defenders are holistically judged based on:

  • Prevent: the duration of time the defender protected the flag from being grabbed
  • Tags: the number of times a player pops a player on the other team
  • Kill/Death ratio: \(\frac{Tags}{Pops}\)
  • Powerups: the number of powerups a player picked up

Finally, team success is typically measured using either win/loss/tie record or by capture differential. Capture differential is the logical choice, as we need some way to measure success quantitatively. For statistics that accrue over time, the values must be transformed to per-minute statistics since players have different amounts of playtime; fractional statistics do not require preprocessing.



Exploration



Part I: Defense Scatterplots



First, we consider a handful of interactive scatterplots comparing some of the defensive metrics to each other. In each plot, the size of the data point depicts the capture differential per minute for that observation. Hovering over a data point displays the player’s name, abscissa, and ordinate. Each plot also has a slider that controls which MLTP season is displayed on the graph. Pressing the ‘Play’ button will have the graph cycle autonomously through the seasons for one full rotation, and manually clicking on a season in the slider will shift the plot directly to that season.

Tags per minute versus prevent per minute, colored by player position:





Next, we remove the offenders from the mix to only see the plot for the defenders. Reducing the domain and range of the axes provides a better picture of the distribution of the defenders:





Part II: Offense Scatterplots



Now we employ the same technique for hold per minute compared to grabs per minute, again presenting both positions separated by color, and then a subset including only the offenders:







Part III: Distribution Visualization



Beeswarm plots are a superb way to visualize MLTP statistical distributions. Beeswarms show the individual observations as unique data points, unlike other distribution visualization techniques that often encode the data abstractly. For example, boxplots use a box and whiskers to encapsulate all of the non-outlier observations and rely on quartiles and summary statistics. Histograms assort the data for a continuous variable into different chunks, which are then displayed as bars, which obscures the individual data points. Showing each data point on a beeswarm plot becomes prohibitively difficult once the size of the dataset becomes too great. Modern MLTP seasons typically have between 32 and 64 majors starters, depending on the number of MLTP teams, which falls into the acceptable range for the number of observations a beeswarm plot should contain.

To supplement each beeswarm plot, I have also included an interactive boxplot (a.k.a box-and-whiskers plot) with the individual player information next to each box. Hovering over the box for each season will display the summary statistics for that box: minimum, maximum, first quartile, third quartile, median, and upper/lower fence if applicable. Hovering over each data point will give the player’s name, the season, and the ordinate value. Toggling the colored boxes in the legend allows each season to be removed or returned to the plot, and double-clicking on any of the boxes will display that season in isolation.



Section A: Prevent



Defenders were not very adept at keeping the flag in base back in Season 10, with a median prevent per minute (PPM) of only 11.76, a maximum of only 16.59 PPM from YoungSinatra, and a nadir of an abysmal 6.02 PPM from Gem. The following season was cleaner at the bottom end, with a minimum of 9.36 PPM, which raised the median up to 13.33 PPM. However, the maximum of 16.24 PPM from Bal McCartny suggests that the top defenders didn’t manage to make any meaningful progress in shutting down offenses in S11 compared to S10.

Season 12 marked the beginning of the prevent Renaissance, dubbed the Preventaissance, with the Meme*Team defensive duo of Syniikal and YoungSinatra (xXw3Edl0rdXx). The pair obliterated the previous records by staggering margins, with Syniikal achieving 19.93 PPM and Young Sinatra putting up 20.19 PPM. Young Sinatra became the first player ever to cross the 20+ PPM threshold, setting a high bar for aspiring defenders. The median also took a big leap from 13.33 PPM up to 14.58 PPM.

S13 saw defensive prowess continue to flourish, with the median prevent continuing to climb up to 15.75 PPM. Syniikal finished the season with 20.05 PPM, becoming the second player to break the 20+ PPM barrier. S14 brought a period of stagnation for most of the league, with the median moving almost imperceptibly up to 15.90 PPM. However, Syniikal still achieved a mind-blowing 25.14 PPM, becoming the first and only player ever to cross the 25+ PPM threshold.

S15 and S16 both saw minuscule increases in the median PPM, again with Syniikal leading the pack in both seasons. S16 saw Syniikal’s partner, HERB, become the third member to join the 20+ PPM crew. In S17, the game’s creator, known in-game as LuckySpammer, removed every extant Tagpro server and replaced them with new ones from a different provider. The new servers were a direct downgrade for many players, and complaints about poor connection, high ping, and server instability plagued the league. Season 17 marked the first season in the modern era in which the median PPM had fallen from the previous season. This didn’t slow down BigBird as he managed to accrue a hefty 20.69 PPM. BigBird became the 4th player to join the 20+ PPM club and the only one who managed to do so without being Syniikal or his partner.

The median PPM continued to nosedive in S18 all the way down to 14.58 PPM, lower than it had been since S11. S19 saw a very slight recovery in the median PPM, but the distribution looks similar to the S18 distribution. Syniikal, playing as TomatoFarmer, once again used his experience to wield the prevent crown, dominating the leaderboard for the seventh straight season.





Section B: Tags



Back in S10, most defenders struggled to get tags, with the median being a paltry 1.44 tags per minute (TPM). Even though the median TPM was low, the founders of the 2.0+ TPM club were born: Abe Lincoln weighing in at 2.11 TPM and the infamous GriefSeeds with an astounding 2.38 TPM. The mechanical skill disparity between GriefSeeds and the rest of the defenders from the Classical Era was immense. GriefSeeds received a lifetime ban from MLTP for botting in S7, which was then overturned due to a lack of definitive evidence by the start of S8. He then continued to put up dominant mechanical performances that seemed to defy human limitations in S8 and S10, after which he unfortunately retired. Despite the community still being split on whether or not cheating was involved, none could deny the performances GriefSeeds shared with us were magnificent. Inducted into the Ball of Fame after his incredible Season 10 performance, he received approval from 100% of the voters.

S11 through S15 saw a stable median TPM, with each falling within the 1.53-1.58 TPM range. When considered in conjunction with the prevent numbers during the same time frame, we can see that the average defender increased PPM numbers while maintaining TPM. S12 saw an anomaly towards the top end of the TPM spectrum, with the 2.0+ TPM club growing to a total of four players: CB13 (2.00), Abe Lincoln (2.04), and Iblis (2.10).

S16 through S19 saw a lower distribution of tagging prowess, with the median TPM being around 1.4, the top taggers rarely reaching even 1.8 TPM, and no players joining the 2+ TPM club. Considering that prevent numbers were declining across those seasons, the data points to the offenders pushing back against the defensive edge that had been built in the prior seasons.





Section C: Kill/Death Ratio



S10 saw three players cross the 3+ K/D ratio barrier: GriefSeeds (3.07), Abe Lincoln (3.67), and Syniikal (5.82). Syniikal crossed the 3+ K/D threshold every single season; no other player managed to do so after S10, which kept the club at an exclusive three players. The median K/D ratio stayed consistent from S10 through S15, before starting to decrease monotonically in S16 through S18, and then increased slightly again in S19. While the historical data makes it seem unlikely another player will join the 3+ club, perhaps another player with enough discipline will arise one day.





Section D: Hold



Season 10 & 11 were the holding man’s dreamscape. The median hold per minute (HPM) was around 11.5 HPM in both seasons, which even top holders struggled to achieve in the later seasons. In the last eight seasons combined, only one player (gg!) managed to get at least 14 HPM, yet three players in S10 and five players in S11 exceeded that threshhold.

Starting in S12, with the advent of the prevent era (Preventaissance), the median HPM and the top HPM both started shifting drastically lower. By S15, the hold leader, badger (11.24 HPM), was unable to reach the hold numbers that the median offenders could in Season 10 or Season 11. Median HPM continued to decrease in subsequent seasons, although several players did manage to beat the S11 median HPM: WarriOrs (x3), bright (x2), DEAD NAN, okthenXD, gg!, and Messi. Even though PPM started to fall in S17 and S18, HPM continued to drop to an all-time low in S18. Despite hold leader gg! finding a way to put up a dominant 14.02 HPM, the median HPM was only a paltry 8.48 HPM.





Section E: Captures



Despite hold being high and prevent being low in Season 10, offenders were not able to score very many captures. The median captures per minute (CPM) was a scant 0.115 CPM, the worst of any modern season. With low median values for TPM and PPM in Season 10, defenders struggled to keep the flag in the base and get the flag reset. With both flags frequently being held simultaneously, neither flag carrier had opportunities to capture.

In Season 11, there was a noticeable jump, with the median shooting up to 0.135 CPM. Hold stayed approximately the same as the previous season, while tags and prevent both increased. The increased prevent indicates that the defenders protected the flag more than the previous season. A large part of this phenomenon was the ever-increasing popularity of anti-re. Offenders were given more opportunities to capture while the defenders were blocking the other team out.

Season 12 was possibly the most statistically enjoyable season for both offenders and defenders alike. While S12 had only the 6th highest median PPM, it was also first in both median TPM & median CPM and third in median HPM. Offenders were getting a decent amount of hold while getting a lot of caps. Defenders were getting lots of tags and keeping the flag in base enough for offenders to capture frequently. Offenders got rewarded for good grabs and hold, while defenders got rewarded for keeping the flag safe and getting resets by playing effective anti-re. I personally believe this lends some analytical evidence to the reason why many veteran players look back so fondly on Season 12.

From Season 13 through Season 19, the median CPM was relatively stable, fluctuating around a baseline value of 0.13-0.14, except Season 17 (the server debacle season). The hold numbers continuing to drop is probably the main reason that the median CPM will never be as high as it used to be. Offenders will simply not have as much time to run in circles with the flag. Instead, offenders are relying upon quick, dynamic paths with the flag to notch a crisp capture before the defenders can catch up.

The 15+ HPM club remains empty to this day, with toasty’s Season 11 performance of 14.88 HPM being the closest any player has ever come. The 14+ HPM region contains eight players: MILKY (x2), toasty, Mr. Hat, Hulzy, BAN NAN (DEAD NAN), Stojakovic, gg!, and LEBRON*JAMES.





Section F: Grabs



The median grabs per minute (GPM) was relatively low in S10, sitting at only 1.47 GPM. In Season 11, the median GPM jumped to 1.65 GPM. Median GPM stayed roughly the same over the next two seasons, before starting to fall starting in Season 14, culminating with the median GPM in S19 approximately equivalent to the median GPM in S10, bringing us full circle after ten seasons. The only player to join the 2.0+ GPM club was protag with 2.03 GPM in Season 14. An honorable mention goes to MILKY for his Season 12 performance with 1.9964 GPM, just barely missing the cutoff to join the elite club.





Section G: Scoring Percentage



The median scoring percentage in Season 10 was a pitiful 6.4%. In the ensuing seasons, the median scoring percentage trended upward, climbing to a peak in Season 16 at a respectable 9.08% and settling at 8.76% in Season 19. The elite club of players with a scoring percentage of at least 15% consists of only four members: Syniikal (x4), WarriOrs (x2), bright, and Ty. Syniikal also managed to put up a scoring percentage of 0% in three separate seasons, which no other player has committed the iniquity of achieving even once.





Section H: Capture Differential



Theoretically, the capture differential per minute should be centered around zero since Tagpro is a zero-sum game. However, only players with at least 120 minutes played in the season are included in the dataset. Now the median capture differential per minute (CDPM) actually provides information on the performance of the substitute players who were just filling in for majors starters. The higher a season’s median CDPM, the worse the filler players performed. Two of the weakest sets of players compared to the substitutes were Season 11 and Season 14 with -0.046 CDPM and -0.055 CDPM, respectively. The strongest group of starters occurred in the crowd favorite Season 12, with a +0.032 CDPM. Only five players ever managed to enter the 0.30+ CDPM clan: caramelbaays (0.363), Apopalypse (0.318), DOKE(0.306), Epiphany (0.303), and toasty (0.300).





Part IV: Miscellaneous Lesser Categories



I have created beeswarms and boxplots for some of the stat categories that are rarely talked about in competitive play, but may still be of interest. Unlike the previous sections, I have merely displayed the distributions for perusal and eschewed any explanations.











IDE Information



## R version 3.6.1 (2019-07-05)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 17763)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252 
## [2] LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] beeswarm_0.2.3    pls_2.7-2         factoextra_1.0.6 
##  [4] data.table_1.12.2 plotly_4.9.1      ggfortify_0.4.8  
##  [7] forcats_0.4.0     stringr_1.4.0     dplyr_0.8.3      
## [10] purrr_0.3.2       readr_1.3.1       tidyr_1.0.0      
## [13] tibble_2.1.3      ggplot2_3.2.1     tidyverse_1.2.1  
## 
## loaded via a namespace (and not attached):
##  [1] ggrepel_0.8.1      Rcpp_1.0.2         lubridate_1.7.4   
##  [4] lattice_0.20-38    assertthat_0.2.1   zeallot_0.1.0     
##  [7] digest_0.6.21      mime_0.7           R6_2.4.0          
## [10] cellranger_1.1.0   backports_1.1.4    evaluate_0.14     
## [13] httr_1.4.1         pillar_1.4.2       rlang_0.4.0       
## [16] lazyeval_0.2.2     readxl_1.3.1       rstudioapi_0.10   
## [19] rmarkdown_1.15     htmlwidgets_1.3    munsell_0.5.0     
## [22] shiny_1.3.2        broom_0.5.2        compiler_3.6.1    
## [25] httpuv_1.5.2       modelr_0.1.5       xfun_0.9          
## [28] pkgconfig_2.0.3    htmltools_0.3.6    tidyselect_0.2.5  
## [31] gridExtra_2.3      viridisLite_0.3.0  crayon_1.3.4      
## [34] withr_2.1.2        later_0.8.0        grid_3.6.1        
## [37] nlme_3.1-140       jsonlite_1.6       xtable_1.8-4      
## [40] gtable_0.3.0       lifecycle_0.1.0    magrittr_1.5      
## [43] scales_1.0.0       cli_1.1.0          stringi_1.4.3     
## [46] promises_1.0.1     xml2_1.2.2         generics_0.0.2    
## [49] vctrs_0.2.0        RColorBrewer_1.1-2 tools_3.6.1       
## [52] glue_1.3.1         hms_0.5.1          crosstalk_1.0.0   
## [55] yaml_2.2.0         colorspace_1.4-1   rvest_0.3.4       
## [58] knitr_1.25         haven_2.1.1