Overview of firstapiR Functions

Stacy Irwin

2020-01-01

The Getting Started vignette covered how to use the GetSession() function to create a Session object and how to use that Session object in other firstapiR functions. This vignette provides an overview of the remaining firstapiR functions. For detailed information on each function, type help(function_name) at the console or in the RStudio help view search box.

Version 2.0.1

This guide is for version 2.0.1 of the firstapiR package. Guidance for version 1.0.0 of firstapiR is located here.

Simple Functions for Retrieving FIRST Data

There are several functions that take no arguments other than the Session argument.

GetServerStatus(session)
Retrieves information about the FIRST API server.
GetSeason(session)
Gets information about the season specified in session$season.
GetDistricts(session)
Provides a list of FIRST districts.
GetAwardsList(session)
Obtains a list and description of awards available to FRC teams.

Data Retrieval Functions with Additional Arguments

All other firstapiR functions take at least a few additional arguments. Most of the additional arguments are optional and, usually, only one or two of the additional arguments are used at any one time.

GetEvents(session, event, team, district, exclude_district)
Provide information about FRC competition events.
GetTeams(session, team, event, district, state, page)
Gets information about FIRST FRC teams.
GetSchedule(session, event, level, team, start, end)
Downloads the match schedule for a specific event.
GetHybridSchedule(session, event, level, start, end)
Downloads the match schedule, along with results for completed matches.
GetMatchResults(session, event, level, team, match, start, end)
Gets the scores for the selected matches.
GetScores(session, event, level, team, match, start, end)
Downloads the scoring sheet for each match.
GetAlliances(session, event)
Obtains the playoff alliances.
GetRankings(session, event, team, top)
Gets the team rankings.
GetAwards(session, event, team)
Lists the awards and recipients for an FRC competition.

Function Arguments

Many of the same arguments are used in several different firstapiR functions.

team

The four digit FRC team number.

districts

A code representing a FIRST district. Use GetDistricts() to obtain the district codes that can be used in other firstapiR functions:

event

An event code, such as WAAMV (disctrict competition held at Auburn MountainView High School in Washington State) or PNCMP (Pacific Northwest District Championships). Use the GetEvents() function to get the event codes:

##     code                                                          name
## 1  ORORE  PNW District - Clackamas Academy of Industrial Science Event
## 2  ORPHI                                PNW District - Philomath Event
## 3  ORWIL                              PNW District - Wilsonville Event
## 4  PNCMP Pacific Northwest District Championship sponsored by Autodesk
## 5  WAAHS                                   PNW District - Auburn Event
## 6  WAAMV                      PNW District - Auburn Mountainview Event
## 7  WAELL            PNW District - Central Washington University Event
## 8  WAMOU                             PNW District - Mount Vernon Event
## 9  WASNO                             PNW District - Glacier Peak Event
## 10 WASPO                              PNW District - West Valley Event
##     code           dateStart
## 1  ORORE 2016-03-31T00:00:00
## 2  ORPHI 2016-03-24T00:00:00
## 3  ORWIL 2016-03-10T00:00:00
## 4  PNCMP 2016-04-06T00:00:00
## 5  WAAHS 2016-04-01T00:00:00
## 6  WAAMV 2016-03-03T00:00:00
## 7  WAELL 2016-03-17T00:00:00
## 8  WAMOU 2016-03-18T00:00:00
## 9  WASNO 2016-03-11T00:00:00
## 10 WASPO 2016-03-03T00:00:00

level

Either “playoff” or “qual”. Defaults to “qual”.

start, end, match

Integers specifying the range of matches that will be included in the returned data.

Pages Argument

There is one firstapiR function, GetTeams(), that accepts the page argument. When requesting data on FRC teams, the FIRST API will split the results into multiple pages if there are more than 65 teams in the response, requiring a separate HTTP request for each page. Users that are requesting the data frame format can ignore the page argument because GetTeams will automatically detect if there are multiple pages in the response, conduct a separate HTTP request for each page, and merge the results into a single data frame. This feature is not available when XML or JSON formats are sepecifed in the Session$format parameter. Users requesting XML or JSON formatted data will have to call GetTeams() for each page of data, incrementing the page argument for each request.

Modified-Since Arguments

There are two additional arguments that can be passed to almost all firstapiR functions (only GetSession() and GetServerStatus() do not accept them). The two arguments, which are always optional, are mod_since and only_mod_since. These two arguments help to reduce the load on the FIRST API server by allowing the server to skip the database query and send only a short HTTP response when the FIRST API server data has not changed since the user last queried the server.

Both of these arguments accept a character vector containing an HTTP formatted date and time string. If the user includes the mod_since argument, and no data has changed on the FIRST API server since the date and time specified in the argument, the FIRST API server will provide an HTTP 304 response with no content. When this happens, irstapiR functions will return a logical character vector with the value NA. Here is an example:

# Create an HTTP date-time string set to midnight GMT yesterday
mod_date <- httr::http_date(as.POSIXct(Sys.Date() - 1))

# Request recently changed data from the server
match_results <- firstapiR::GetMatchResults(sn, event = "PNCMP",
                                            mod_since = mod_date)

# Assuming there have been no updates to the data since yesterday, this
#   returns TRUE
is.na(match_results)

# The value passed to mod_since returned as an attribute, even when the
#   result is NA
print(attr(match_results, "mod_since"))

If the user includes the only_mod_since argument, the FIRST API server will return only the data that has changed since the date and time specified in the only_mod_since argument. In no changes have been made, the FIRST API server provides a 304 response and firstapiR functions return a logical vector set to NA.

# Create an HTTP date-time string set to midnight GMT yesterday
mod_date <- httr::http_date(as.POSIXct(Sys.Date() - 1))

# Request recently changed data from the server
match_results <- firstapiR::GetMatchResults(sn, event = "PNCMP",
                                            only_mod_since = mod_date)

# Assuming there have been no updates to the data since yesterday, this
#   returns TRUE
is.na(match_results)

# The value passed to mod_since returned as an attribute, even when the
#   result is NA
print(attr(match_results, "only_mod_since"))

If the mod_since or only_mod_since arguments are not specified, the corresponding mod_since or only_mod_sinceattribute attached to the return value will be set toNULL`.

Users can keep track of the date and time provided in the last_modified attribute, which corresponds to the most recent date and time that the information changed on the FIRST API server, and use this date and time to request only new data from the server. If a user repeats a firstapiR function call with the same arguments and sets the mod_since or only_mod_since argument to the last_modified attribute value from the intial firstapiR function call, the FIRST API server will return all requested data – the same data that was provided in the first function call. Users who would rather receive a 304 response in this situation should either add at least a second to the last_modified value, or should instead use the time_downloaded attribute value to set the mod_since or only_mod_since arguments.

Data Frame Shaping Functions

Team Shape

The functions GetSchedule(), GetHybridSchedule(), and GetMatchResults() return data frames with one row per team. For example, let’s take a look at the first two qualification matches from the 2016 Pacific Northwest District Championships:

##           match alliance station team scoreAuto scoreFinal
## q.1.blue1     1     Blue   Blue1 4915        30        102
## q.1.blue2     1     Blue   Blue2 3674        30        102
## q.1.blue3     1     Blue   Blue3 4125        30        102
## q.1.red1      1      Red    Red1 1318        32        107
## q.1.red2      1      Red    Red2 2907        32        107
## q.1.red3      1      Red    Red3 2944        32        107
## q.2.blue1     2     Blue   Blue1 2374        30        126
## q.2.blue2     2     Blue   Blue2 2557        30        126
## q.2.blue3     2     Blue   Blue3 5920        30        126
## q.2.red1      2      Red    Red1 1595        30        103
## q.2.red2      2      Red    Red2 1425        30        103
## q.2.red3      2      Red    Red3 2147        30        103

There is one team listed in each row, and it takes six rows to provide all of the information from a single match. This is called team shape. This format is useful for calculating summary statistics for individual teams. For example, to see average scores for the ten teams with the highest scores:

##    team scoreFinal scoreAuto scoreFoul
## 12 1983   123.1667  32.16667  4.166667
## 19 2557   121.1667  28.16667  2.916667
## 1   360   118.6667  30.83333  4.166667
## 9  1540   118.1667  27.33333  3.750000
## 46 4131   114.5833  25.41667  4.583333
## 60 5803   114.5000  28.33333  2.500000
## 49 4450   114.2500  28.75000  3.750000
## 6  1318   114.0000  28.50000  3.750000
## 63 5942   112.9167  27.50000  1.666667
## 7  1425   111.7500  24.33333  1.666667

Data frames in team shape will have their shape attribute set to “team”.

## [1] "team"

Alliance Shape

For some calculations, such as offensive power rating (OPR), the alliance shape, with three teams per row and two rows per match (one row each for the red and blue alliances), is more suitable. The function ToAllianceShape() will reshape Schedule, HybridSchedule, or MatchResults data frames from team to alliance shape.

##        match alliance team.1 team.2 team.3 scoreAuto scoreFinal
## 1.blue     1     Blue   4915   3674   4125        30        102
## 1.red      1      Red   1318   2907   2944        32        107
## 2.blue     2     Blue   2374   2557   5920        30        126
## 2.red      2      Red   1595   1425   2147        30        103

Data frames in alliance shape will have their shape attribute set to “alliance”.

## [1] "alliance"

Match Shape

Finally, Schedule, HybridSchedule, and MatchResults data frames may be converted from team to match shape.

##   match team.Red1 team.Red2 team.Red3 team.Blue1 team.Blue2 team.Blue3
## 1     1      1318      2907      2944       4915       3674       4125
## 2     2      1595      1425      2147       2374       2557       5920
##   scoreFinal.Blue scoreFinal.Red
## 1             102            107
## 2             126            103

Converting Back to Team Shape

The ToTeamShape() function will convert match and alliance data frames back to team shape. This function depends on the ReshapeWide attribute, which is added to the match and alliance data frames by R’s reshape() function. ToTeamShape() will not work if the ReshapeWide attribute is deleted.

Converting Between Match and Alliance Shape

To convert a data frame from match to alliance shape or vice-versa, first convert the data frame back to team shape.

Saving and Loading Data

Use firstapiR’s SaveData() function to open a save file dialog box and save data to an RDS data file. The ReadData() function opens an open file dialog and returns the value saved in the RDS file. Refer to R’s documentation on the saveRDS() and `readRDS()’ functions for more information on RDS data files.

SaveData(firstapiR::GetAlliances(sn, event = "WAAMV"))
evt_alliances <- firstapiR::ReadData()

Getting all Event Data

Sometimes it’s handy to get all the available information for an FRC competition with single command. The GetAll() function retrieves all data for a specific event and stores the data in a list. I recommend not using this function during competitions to avoid overloading the server. Also, save the event data to a file so it only needs to be downloaded once.

# Get all data for the 2016 district competition at Auburn Mountainview HS
sn <- firstapiR::GetSession("username", "key")
all_data <- firstapiR::GetAll(sn, event = "WAAMV")

Preloaded Data

Version 2.0.1 of firstapiR includes all competition data for the 2016 FRC championships in St. Louis. Data for each subdivision and the finals are available in R lists named archimedes2016, carson2016, carver2016, curie2016, galileo2016, hopper2016, newton2016, tesla2016, and einstein2016.

# Show elements in curie2016 list:
names(firstapiR::curie2016)
##  [1] "season"           "event"            "teams"            "schedule.qual"   
##  [5] "schedule.playoff" "hybrid.qual"      "hybrid.playoff"   "matches.qual"    
##  [9] "matches.playoff"  "scores.qual"      "scores.playoff"   "results.qual"    
## [13] "results.playoff"  "rankings"         "alliances"        "awards"
# Show alliances for Curie Subdivision (first 8 columns)
firstapiR::curie2016$alliances[1:8]
##   number       name captain round1 round2 round3 backup backupReplaced
## 1      1 Alliance 1    3546    166    858   3618     NA             NA
## 2      2 Alliance 2    1089   1983   4469    836     NA             NA
## 3      3 Alliance 3      25   2848   4329   1885     NA             NA
## 4      4 Alliance 4    5803   3310   2168   5940     NA             NA
## 5      5 Alliance 5    5406   3641   1261   2883     NA             NA
## 6      6 Alliance 6     639   3990   1662    287     NA             NA
## 7      7 Alliance 7    3005    876   2557   4061     NA             NA
## 8      8 Alliance 8     694   3339    379   1511     NA             NA

Merging Team and Score Data

The GetScores() function retrieves detailed performance data for for both the red and blue alliances for each match. However the Scores data frame does not list the teams that were assigned to each alliance. The function MergeResults() merges a HybridResults data frame with a Scores data frame to create a Results data frame that contains both the detailed match performance data and the teams that were assigned to each match.

# Merge MatchResults and Scores data frames
curie_results <- firstapiR::MergeResults(firstapiR::curie2016$hybrid.qual,
                                         firstapiR::curie2016$scores.qual)
# Show structure of resulting data frame
str(curie_results)
## Classes 'Results' and 'data.frame':  750 obs. of  49 variables:
##  $ match                 : int  1 1 1 1 1 1 2 2 2 2 ...
##  $ level                 : Factor w/ 1 level "Qualification": 1 1 1 1 1 1 1 1 1 1 ...
##  $ alliance              : Factor w/ 2 levels "Blue","Red": 1 1 1 2 2 2 1 1 1 2 ...
##  $ description           : chr  "Qualification 1 (B)" "Qualification 1 (B)" "Qualification 1 (B)" "Qualification 1 (B)" ...
##  $ start                 : chr  "2016-04-28T08:30:00" "2016-04-28T08:30:00" "2016-04-28T08:30:00" "2016-04-28T08:30:00" ...
##  $ actualStart           : chr  "2016-04-28T08:31:22.123" "2016-04-28T08:31:22.123" "2016-04-28T08:31:22.123" "2016-04-28T08:31:22.123" ...
##  $ team                  : Factor w/ 75 levels "8","25","166",..: 34 6 12 29 74 54 7 65 45 8 ...
##  $ station               : Factor w/ 6 levels "Blue1","Blue2",..: 1 2 3 4 5 6 1 2 3 4 ...
##  $ surrogate             : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ disqualified          : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ AudienceGroup         : Factor w/ 4 levels "GroupA","GroupB",..: 2 2 2 2 2 2 2 2 2 2 ...
##  $ robot1Auto            : Factor w/ 3 levels "Crossed","None",..: 1 1 1 3 3 3 1 1 1 3 ...
##  $ robot2Auto            : Factor w/ 3 levels "Crossed","None",..: 3 3 3 1 1 1 1 1 1 3 ...
##  $ robot3Auto            : Factor w/ 3 levels "Crossed","None",..: 1 1 1 3 3 3 1 1 1 1 ...
##  $ autoBouldersLow       : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ autoBouldersHigh      : int  1 1 1 0 0 0 0 0 0 1 ...
##  $ teleopBouldersLow     : int  6 6 6 6 6 6 5 5 5 4 ...
##  $ teleopBouldersHigh    : int  4 4 4 0 0 0 12 12 12 1 ...
##  $ towerFaceA            : Factor w/ 4 levels "Challenged","None",..: 1 1 1 2 2 2 1 1 1 1 ...
##  $ towerFaceB            : Factor w/ 4 levels "Challenged","None",..: 1 1 1 4 4 4 3 3 3 3 ...
##  $ towerFaceC            : Factor w/ 4 levels "Challenged","None",..: 1 1 1 4 4 4 2 2 2 1 ...
##  $ towerEndStrength      : int  5 5 5 -1 -1 -1 4 4 4 -6 ...
##  $ teleopTowerCaptured   : logi  TRUE TRUE TRUE FALSE FALSE FALSE ...
##  $ teleopDefensesBreached: logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
##  $ position1crossings    : int  2 2 2 2 2 2 2 2 2 2 ...
##  $ position2             : Factor w/ 7 levels "A_ChevalDeFrise",..: 6 6 6 1 1 1 6 6 6 6 ...
##  $ position2crossings    : int  2 2 2 1 1 1 2 2 2 2 ...
##  $ position3             : Factor w/ 5 levels "A_ChevalDeFrise",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ position3crossings    : int  2 2 2 2 2 2 2 2 2 2 ...
##  $ position4             : Factor w/ 8 levels "A_ChevalDeFrise",..: 7 7 7 6 6 6 7 7 7 1 ...
##  $ position4crossings    : int  2 2 2 2 2 2 2 2 2 2 ...
##  $ position5             : Factor w/ 8 levels "A_ChevalDeFrise",..: 1 1 1 7 7 7 1 1 1 7 ...
##  $ position5crossings    : int  2 2 2 2 2 2 2 2 2 2 ...
##  $ foulCount             : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ techFoulCount         : int  0 0 0 1 1 1 1 1 1 0 ...
##  $ autoPoints            : int  32 32 32 14 14 14 30 30 30 24 ...
##  $ autoReachPoints       : int  2 2 2 4 4 4 0 0 0 4 ...
##  $ autoCrossingPoints    : int  20 20 20 10 10 10 30 30 30 10 ...
##  $ autoBoulderPoints     : int  10 10 10 0 0 0 0 0 0 10 ...
##  $ teleopPoints          : int  87 87 87 52 52 52 125 125 125 83 ...
##  $ teleopCrossingPoints  : int  40 40 40 40 40 40 35 35 35 45 ...
##  $ teleopBoulderPoints   : int  32 32 32 12 12 12 70 70 70 13 ...
##  $ teleopChallengePoints : int  15 15 15 0 0 0 5 5 5 10 ...
##  $ teleopScalePoints     : int  0 0 0 0 0 0 15 15 15 15 ...
##  $ breachPoints          : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ capturePoints         : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ adjustPoints          : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ foulPoints            : int  5 5 5 0 0 0 0 0 0 5 ...
##  $ totalPoints           : int  124 124 124 66 66 66 155 155 155 112 ...
##  - attr(*, "url")= chr  "https://frc-api.firstinspires.org/v2.0/2016/schedule/CURIE/qual/hybrid" "https://frc-api.firstinspires.org/v2.0/2016/scores/CURIE/qual"

Actually, using MergeResults() is not necessary for preloaded data (such as curie2016 or for any data structures created with the GetAll() function. These lists already contain merged data frames – see curie2016$results.qual and curie2016$results.playoff for examples. I used the preloaded data to demonstrate the MergeResults() function because that’s an easy way to do it.

Merging Qualification and Playoff Data Frames

There are several functions provide data for either qualification or playoff matches, but not both. Use R’s rbind() function to merge this data into a single data frame.

# Number qualification matches
nrow(firstapiR::curie2016$matches.qual)
## [1] 750
# Number playoff matches
nrow(firstapiR::curie2016$matches.playoff)
## [1] 102
# Merge qualification and playoff data into a single table
all_matches <- rbind(firstapiR::curie2016$matches.qual,
                     firstapiR::curie2016$matches.playoff)

# Total Matches
nrow(all_matches)
## [1] 852

Ask Questions

Post an issue on the firstapiR github repository if you have questions, find bugs or have recommendations for the next version.