How To: Create a Requested Analysis via the Reboot Motion API
This tutorial uses code samples written in Python; however, if your organization uses a different language, you can still use the tutorials as a reference point — you will just need to translate the examples to the language of your choosing.
If you need help with getting set up to use the Reboot Motion API, you can check out our Getting Set Up tutorial here.
Welcome! This tutorial walks you through the process of creating a Requested Analysis via the Reboot Motion API. For more information about the endpoints included in this tutorial, or any other endpoint, you can check out our API documentation.
Note: You will need an API Key to interact with the API endpoints mentioned in this tutorial. API Keys are available to all active Reboot Motion customers. If you do not already have an API Key from Reboot Motion, you can generate one from your Reboot Motion Dashboard.
What exactly is a Requested Analysis? A Requested Analysis is simply a custom report that Reboot Motion can create for an organization using specific data that the organization provides.
For this tutorial, we will be analyzing a fictional example pitcher’s fastballs vs their curveballs. We will be using the Reboot Motion API to create a Requested Analysis that compares the example pitcher’s fastballs to their curveballs.
Step 0: Understanding the Endpoints
First, let’s take a look at the Reboot Motion API documentation for Analyses. You'll notice there are seven different endpoints :
Endpoint | Description |
---|---|
POST /player_group_segments | Create Player Group Segments |
PATCH /player_group_segments/{player_group_segment_id} | Update Player Group Segments |
GET /requested_analyses | List Requested Analyses |
POST /requested_analyses | Create Requested Analyses |
GET /requested_analyses/{requested_analysis_id} | Get Requested Analyses |
PATCH /requested_analyses/{requested_analysis_id} | Update Requested Analyses |
PATCH /requested_analyses/{requested_analysis_id}/submit | Set Requested Analyses Status To Requested |
For this tutorial, we will use two of the endpoints listed above. First, we create the primary and comparison segments using the POST /player_group_segments
endpoint (which returns the newly created segments' IDs). We then use the POST /requested_analyses
endpoint, which takes those segment IDs and submits the Requested Analysis for processing.
The first endpoint we will look at is the POST /requested_analyses
endpoint. You will notice that this endpoint requires the following parameters:
{ "name": "Player A comparing May 2022 to April 2022", "primary_analysis_segment_id": 1 "comparison_analysis_segment_id": 2, "population_analysis_segment_id": 3, }
There are some Reboot Motion-specific terms in here, like name
and primary/comparison/population analysis segment
— let’s define those:
Term | Definition |
---|---|
name | Whatever you want to name your generated report to make it easier for you to find either via the Reboot Motion API or the Dashboard. You can make this as specific or generic as you like; we suggest erring on the side of more specific to make it easier to find. |
player_group_segment | The underlying grouping of movements that will be analyzed in the Requested Analysis. The primary , comparison , and population segments are subsets of the larger player_group_segment . |
Again, in our example, our player_group_segment
is a specific player’s pitch types.
- Our
primary
segment will be the pitcher’s Fastballs, as that is the first pitch type we are going to be analyzing. - The
comparison
segment will be the pitcher's Curveballs, as we are comparing the pitcher's Curveballs to their Fastballs in this Requested Analysis. - The
population
segment is a bit more complicated than just choosing one pitch type for a player — this one will need to be defined within your organization and can change based on your use case. Thepopulation
segment is the total dataset for whatever you decide you want to look at. For the tutorial example, it could be all the example pitcher’s pitches in a certain game, all the pitcher’s pitches thus far in the season; all the pitcher’s Fastballs for the season, or all the pitcher’s Curveballs for the season. Thepopulation
segment is used to provide a larger dataset for which to compare your primary dataset and should be tailored to the data your organization is most interested in seeing.
If these segments are a bit confusing, don't worry — we will be walking through getting each necessary segment in the tutorial below with examples.
Before we start trying to figure out how to get our primary_segment_id
and comparison_segment_id
, we want to set up our main.py
file properly, so make sure you have the following import statements and constants at the top of your file — we are going to use the os.getenv()
function to get our API Key from wherever it is currently stored:
import os import requests API_KEY = "API_KEY_FROM_REBOOT"
If you're not sure what any of these import statements or constants are doing, hop over to our Getting Set Up tutorial, which walks you through each of those.
Note that "API_KEY_FROM_REBOOT" would be replaced with your actual API Key, given to you by Reboot Motion, as detailed in the Getting Set Up tutorial. In our example, we are hard-coding the API key for ease of understanding, but in practice it's wise to read the API key from an environment variable leveraging a library like python-dotenv
. As mentioned in the tutorial, please be incredibly careful not to commit your API Key to a public repository.
As a reminder: all the values used in this tutorial are example values. You cannot plug and play with the example values as they currently are; you will need to put in the correct values for your organization/player/etc. The example values used in this tutorial are for a fictional example player.
Step 1: Getting the List of Movement IDs to Compare
After looking at the API documentation, you'll notice that we need a list of Movement IDs in order to work with this endpoint.
You can get the list of Movement IDs in a couple different ways, depending on how your organization stores the data. If you're looking to compare a list of Movement IDs from a game (for example, a specific, league-provided ID), you can simply input the Movement IDs as arrays. If your organization has a larger dataset, you may retrieve that dataset directly from a database or stored in a CSV file. In the case of a CSV, a tool like Pandas can simplify the process of reading and filtering the data.
Getting the List of Movement IDs via CSV File:
Let's look at getting the list of Movement IDs via a CSV file, using Pandas. If you need a refresher on why we are using Pandas, you can look at the Pandas
section in the Getting Set Up tutorial.
In this scenario, we are getting the data to be compared from a CSV file, so will need the path to that file. Note that we do not provide this CSV file for you — it must come from your organization and you can save it wherever you would like within your codebase, but you’ll need to get the path to that file starting at the root folder to use in this step.
League-Provided ID | PitchType |
---|---|
aaeae660-70d8-443c-ad95-8824771e6251 | Fastball |
dae947c0-85b4-469e-ad27-72324add9b42 | Fastball |
9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5 | Fastball |
fbcfe483-b462-4135-b249-6c588c688851 | Curveball |
eb306285-c145-414a-93c5-5361d4c9915c | Curveball |
6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c | Curveball |
Our CSV file replicated above has two columns: one labeled League-Provided ID
and one labeled PitchType
. If you look at the PitchType
column, you’ll see it includes only Fastball
and Curveball
, which are the two Pitch Types we are comparing in this example; your data may have more values and can be filtered based on the values you want, or you may create a CSV file that includes only the values you're looking at, as we've done in this example.
When using Pandas, reading the data is easy — using the Pandas read_csv
function, we are able to easily read the file and create DataFrames from our CSV file, which looks like this:
import pandas as pd def main(): csv_df = pd.read_csv(PATH_TO_CSV_FILE) if __name__ == "__main__": main()
Again, the PATH_TO_CSV_FILE
would be replaced with the file path where the CSV file lives within your organization's repository.
The next step is to figure out what data we want from the file so we can start to make and filter our DataFrames — our original desire was to get the values of an example pitcher’s fastballs vs their curveballs, so our primary segment will be the one that contains that pitcher’s fastballs.
We will be making a copy of the csv_df
DataFrame and inserting that into a new DataFrame that we will call fastball_movements_df
. This dataframe will relate to the primary segment that we are looking at: in this case, the example pitcher’s fastballs.
From there, we need to take that primary DataFrame and filter it on the pitch type of Fastball
, as that's the pitch type we want to use to compare the rest of the data to. Since we are looking at both the pitcher's fastballs and curveballs, you will want to create a second DataFrame for the pitcher's curveballs as well, using the Curveball
pitch type.
fastball_movements_df = csv_df[csv_df["PitchType"] == "Fastball"] curveball_movements_df = csv_df[csv_df["PitchType"] == "Curveball"]
You now have a DataFrame of both the fastball and curveball movements that include the league-provided ID for the lines of the CSV file that correlate to either fastballs or curveballs. You now have a DataFrame of both the fastball and curveball movements that include the league-provided ID for the lines of the CSV file that correlate to either fastballs or curveballs.
The last step is to turn these DataFrames into lists of Movement IDs using the league-provided ID column and the `.tolist() function:
fastball_movements = fastball_movements_df["MLBPlayId"].tolist() curveball_movements = curveball_movements_df["MLBPlayId"].tolist()
This will give you two lists of Movement IDs that you can use to create the Primary and Comparison Segments:
fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"] curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"]
Regardless of the method you choose to get your list of Movement IDs, you will now have one list of fastball movements and one list of curveball movements that we will use as we progress through this tutorial.
Step 2: Creating the Primary Segment
From the API documentation, the first thing we need to create for our Requested Analysis is the Primary Segment ID.
The Primary Segment ID is the ID of a Player Group Segment that we can use to request the analysis. However, we don't have a Player Group Segment yet, let alone the ID of a Player Group Segment; we just have our lists of Movement IDs.
To create a Player Group Segment for our Primary Segment (aka Player Group Segment #1, aka the example pitcher's Fastballs) and get the ID needed to create the Requested Analysis, we will need to reference the Reboot Motion API documentation again, this time looking at the Create Player Group Segments endpoint.
This POST /player_group_segments
request will provide us with the Player Group Segment that we can use to move forward. We will be taking all the data we need for that primary segment and making a dictionary of primary_segment_criteria
.
In the documentation, you will see that movement_type_id
and dom_hand
are required fields. In our example, we will also be adding in external_context_ids
to further clarify what data we want. The External Context ID corresponds to the MLB Play ID for a movement you have uploaded to Reboot Motion, and is included in our CSV file as a column.
fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"] primary_segment_criteria = { "external_context_ids": fastball_movements, "movement_type_id": 2, "dom_hand": "RHA" }
Let’s walk through exactly what each of those dictionary elements means:
Dictionary Element | Definition |
---|---|
external_context_ids | The list of specific, league-provided IDs that we want to analyze, which we get from the "League-Provided ID" column of our CSV file or from the array of individual league-provided IDs. |
movement_type_id | The type of movement we want to analyze. For our example case, we are looking at baseball pitching movements, so we are using a movement_type_id of 2 . For the names and IDs of other movement types, you can query the API via the List Movement Types endpoint. |
dom_hand | The dominant hand for the movements we want to analyze — in our case, our example pitcher is right handed, so we use RHA (if we were analyzing left—handed movements, you would use LHA ). We use dom_hand to make this variable more flexible — it can be used for multiple sports and in many applications (i.e. in baseball it can be used for pitching and hitting, in basketball for shooting, and in football for throwing, to name a few). |
The next step is to send the API POST /player_group_segments
request to create the Primary Segment we just defined the criteria for. Since we’re using the requests library, passing the primary_segment_criteria
dictionary to the json=
parameter will automatically convert the dictionary to JSON and use it as the body of the request.
We authenticate with the API using the x-api-key
header as detailed in the documentation:
create_primary_segment = requests.post( "https://api.rebootmotion.com/player_group_segments", headers={'x-api-key': API_KEY}, json=primary_segment_criteria )
Now we have the create_primary_segment
JSON object, but we still need to get the analysis_segment_id
from it. Since this is a JSON object, we can’t just tack ["analysis_segment_id"]
straight onto the end of the response; we need to first convert it back to a dictionary and then we can retrieve the analysis_segment_id
parameter.
Since we are going to be reusing the same general code structure for Step 2, we are going to create some additional constants from our segment criteria dictionary since you must use the same values for movement_type_id
and dom_hand
for the primary, comparison, and population segments. Since we will also be using the same header and API KEY requests, we can turn that into a constant for easy reuse throughout the code.
API_HEADER = {'x-api-key': API_KEY} DOM_HAND = "RHA" MOVEMENT_TYPE_ID = 2 fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"] primary_segment_criteria = { "external_context_ids": fastball_movements, "movement_type_id": MOVEMENT_TYPE_ID, "dom_hand": DOM_HAND } create_primary_segment = requests.post( "https://api.rebootmotion.com/player_group_segments", headers=API_HEADER, json=primary_segment_criteria ) primary_segment_id = create_primary_segment.json()["analysis_segment_id"]
create_primary_segment
should return a response object that includes multiple keys and values; one of which is the analysis_segment_id
. If you are not getting a response object back, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.
Now let’s move on to Step 3, which is creating the Comparison Segment in the same way we just created the Primary Segment.
Step 3: Creating the Comparison Segment
Creating the Comparison Segment ID repeats the above steps but uses comparison_segment
instead of primary_segment
; curveball_movements
instead of fastball_movements
; and "Curveball" instead of "Fastball". The new block of code will therefore look like this:
curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"] comparison_segment_criteria = { "external_context_ids": curveball_movements, "movement_type_id": MOVEMENT_TYPE_ID, "dom_hand": DOM_HAND } create_comparison_segment = requests.post( "https://api.rebootmotion.com/player_group_segments", headers=API_HEADER, json=comparison_segment_criteria ) comparison_segment_id = create_comparison_segment.json()["analysis_segment_id"]
Again, create_comparison_segment
should return a response object with multiple keys and values; one of which is the analysis_segment_id
. If you are not getting a response object back, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.
Now we have both the Primary (fastball) and Comparison (curveball) Analysis Segment IDs that we can use in the last part of our code, which is actually creating the Requested Analysis.
Step 4: Creating the Requested Analysis
The last step in this tutorial is to write the POST /requested_analyses
request, creating the Requested Analysis itself. The documentation for this can be accessed in the Reboot Motion API documentation.
Since we now have both the primary_analysis_segment_id
and comparison_analysis_segment_id
, we can go back to our initial POST /requested_analyses
endpoint and fill the request body with the Segment IDs from Steps 2 and 3.
You will need to create a requested_analysis_criteria
dictionary and to make the POST request:
requested_analysis_criteria = { "name": "Example Pitcher Fastballs vs Curveballs", "primary_analysis_segment_id": int(primary_segment_id), "comparison_analysis_segment_id": int(comparison_segment_id), "status": "requested" } create_requested_analyses = requests.post( "https://api.rebootmotion.com/requested_analyses", headers=API_HEADER, json=requested_analysis_criteria )
Let’s walk through what each of the lines of the above code is doing.
We'll start with the requested_analysis_criteria
dictionary first.
Dictionary Element | Definition |
---|---|
name | As mentioned earlier in this tutorial, this is simply the name you would like to give your report — this can be whatever you would like, and as descriptive as you would like; we recommend erring on the side of a more descriptive name so your reports are easy to locate in the future via the API or Dashboard. |
primary_analysis_segment_id | The integer value of the primary_segment_id we got in Step 2 — this allows us to get the data for that primary segment you are looking to compare; in this case it’s the example pitcher’s fastballs. You’ll notice that we convert the primary_segment_id we got earlier into an integer using int() . |
comparison_analysis_segment_id | Also the integer value of the comparison_segment_id we got in Step 3, and allows us to get the data for the segment you are looking to compare the primary segment to. In this example, that would be the example pitcher’s curveballs. Again, the comparison_segment_id is converted to an integer using .int() . |
status | The status of the requested analysis. If you do not include this field, it will default to "draft". The status should always be requested when creating a new analysis; it will be updated as the analysis is processed on Reboot Motion’s end. |
Now that we have the dictionary with the criteria created, we can make the create_requested_analyses
POST request.
The headers for the POST
request remain the same as they were for getting the Primary and Comparison Segment IDs, but the URL and criteria we are providing the endpoint are different: the URL is now "https://api.rebootmotion.com/requested_analyses"
and the required requested_analysis_criteria
dictionary from the API documentation has been included as a JSON object.
If your create_requested_analyses
is not returning a full response object, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.
In the documentation, comparison_analysis_segment_id
and population_analysis_segment_id
are not required. Why is that?
Reboot Motion allows you to create a Requested Analysis for just one segment if you would like. This means you would only have a primary_analysis_segment_id
, and would not include a comparison_analysis_segment_id
or a population_analysis_segment_id
, giving you a Requested Analysis for just the one segment you have put in as your primary segment.
This tutorial has not provided an example of a population_analysis_segment_id
, but we do want to touch on what exactly that means. The population can be whatever you would like it to be: if you want to see a specific pitcher’s pitches for all games, the population segment can be that pitcher’s pitches for all their games (this season, last season, since they joined the organization, however you want to break it up); if you want to see all the shots from the entire organization, the population segment can be shots from your entire organization. This allows you to have the power to compare whatever segments you would like to compare with ease. That being said, the way to get the Population Analysis Segment ID is the exact same way as we used to get the Primary and Comparison Analysis Segment IDs: you’ll create a Player Group Segment with whatever you want the population to be. This can be used in conjunction with either just a Primary Analysis Segment or both a Primary and Comparison Analysis Segment.
The last part is to simply print the JSON response of the requested analysis from the API, and run the file. Putting all the previous parts together, our main.py
file should now look like the below, and you should be able to create a Requested Analysis (keep in mind that if you used Pandas for getting the Movement IDs, you will have a bit more code to get the fastball and curveball movements).
import os import requests API_KEY = "API_KEY_FROM_REBOOT" API_HEADER = {'x-api-key': API_KEY} DOM_HAND = "RHA" MOVEMENT_TYPE_ID = 2 def main(): fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"] primary_segment_criteria = { "external_context_ids": fastball_movements, "movement_type_id": MOVEMENT_TYPE_ID, "dom_hand": DOM_HAND } create_primary_segment = requests.post( "https://api.rebootmotion.com/player_group_segments", headers=API_HEADER, json=primary_segment_criteria ) primary_segment_id = create_primary_segment.json()["analysis_segment_id"] curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"] comparison_segment_criteria = { "external_context_ids": curveball_movements, "movement_type_id": MOVEMENT_TYPE_ID, "dom_hand": DOM_HAND } create_comparison_segment = requests.post( "https://api.rebootmotion.com/player_group_segments", headers=API_HEADER, json=comparison_segment_criteria ) comparison_segment_id = create_comparison_segment.json()["analysis_segment_id"] requested_analysis_criteria = { "name": "Example Pitcher Fastballs vs Curveballs", "primary_analysis_segment_id": int(primary_segment_id), "comparison_analysis_segment_id": int(comparison_segment_id), "status": "requested" } create_requested_analyses = requests.post( "https://api.rebootmotion.com/requested_analyses", headers=API_HEADER, json=requested_analysis_criteria ) print(create_requested_analyses.json()) if __name__ == "__main__": main()
Running this file will allow you to create a Requested Analysis, and will print out the JSON values of the response to your terminal.
Common Errors
Ideally, you wouldn't run into any errors while going through this tutorial, but there's a lot of information here and sometimes errors happen. That being said, let's go through some of the more common errors and the first steps to take to troubleshoot those errors to save you some time.
You can always access a full list of errors in the Reboot Motion documentation, but we will walk you through some more specific error messages you may encounter while trying to create a Requested Analysis.
ModuleNotFoundError: No module named '<module_name>'
This error comes from the module in question not being installed — you will need to install the module in order to use it. You can do this by running pip install requests
in your terminal. If you are using a different package manager, you will need to use the appropriate command for that package manager.
response.json()[‘analysis_segment_id’] throws an exception
This exception is likely being thrown because of a key error, coming from response.json()['analysis_segment_id']
. This error means the JSON coming back doesn't have an ['analysis_segment_id']
, which it should.
It likely means you have entered something incorrectly in your request; we recommend you double check the spelling of all the provided fields, as this is a frequent cause of this error. You may have also provided data in an incorrect form — double check with the documentation that everything matches up.
HTTP Exception 401: Unauthorized
You need to include a proper API Key — if you don't know how to get this, take a look at the Getting Set Up tutorial.
HTTP Exception 500: Internal Server Error
This means something is wrong on the Reboot Motion server's end - please reach out to the team at [email protected].
If you need to retry the API call after a failure, check that you have everything above correct, restart your server, and make the call again. If you continue to get an error message and can't figure out why, feel free to reach out to the Reboot Motion team.
Please feel free to reach out to the team with any additional questions you may have, or if you run into any issues that weren't addressed above!