Endpoint | URL | Method | Description |
---|---|---|---|
Upload User Files | https://equity-tool-api.urban.org/api/v1/upload-user-file/ | POST | Submit an analysis request to the Spatial Equity Data Tool |
Get Output Data Status | https://equity-tool-api.urban.org/api/v1/get-output-data-status/{file_id}/ | GET | Check the status of your submitted analysis request |
Get Output Data | https://equity-tool-api.urban.org/api/v1/get-output-data/{file_id}/ | GET | Obtain the results of a completed analysis request |
10 How to Use the API
On April 29th, we implemented a bugfix to address an error in the calculation of demographic disparity scores for supplemental demographic data (see Chapter 11 for more information on using supplemental data and Chapter 18 for more information on the bugfix).
The API has three endpoints we outline in the table below. We envision users calling the “Upload User Files” endpoint to begin a request, calling the “Get Output Data Status” endpoint to assess the request’s status, and calling the “Get Output Data” endpoint when their job finishes to receive the analysis results.
API Endpoints Index
The sedtR R Package
The sedtR
R package wraps the three endpoints and allows interaction through user-friendly functions using the R programming language. While the workhorse functions in this package are operational and pass an extensive suite of tests, this package should be considered inbeta
version for the time being. Please create an issue or emailsedt@urban.org
if you have questions or see issues in the code. You can install the development version of sedtR
from GitHub with:
# install.packages("devtools")
::install_github("UrbanInstitute/sedtR") devtools
The call_sedt_api()
Function
The library(sedtr)
function call_sedt_api()
wraps the calls to the three separate API endpoints in a single function. The user will submit the request parameters as arguments to the call_sedt_api()
function, which will submit the request to the “Upload User Files” endpoint, repeatedly ping the “Get Data Status” endpoint using sedtr::get_status()
until the API successfully completes the analysis or returns an error. If the analysis successfully completes, the function then calls the “Get Output Data” endpoint using sedtr::get_output_data()
and returns the results, formatted as shown below. Otherwise, the function returns an informative error message.
Example Function Call
library(sedtR)
call_sedt_api(
resource_file_path = here("data", "sample", "dc_test_api_resource.csv"),
resource_lat_column = "Y",
resource_lon_column = "X",
geo = "city",
acs_data_year = "2019",
demographic_file_path = here("data", "sample", "dc_test_api_demographic.csv"),
demographic_geo_id_column = "GEOID",
demographic_columns = list(
nh_white_pop = "nh_white_pop_margin",
hispanic = "hispanic_margin",
hispanic_men = "hispanic_men_margin"
),geographic_file_path = here("data", "sample", "dc_test_api_geographic.csv"),
geographic_geo_id_column = "GEOID",
geographic_columns = list(
hispanic_men = "hispanic_men_margin",
male_under_18 = "male_under_18_margin",
female_under_18 = "female_under_18_margin",
children = "children_margin"
),resource_weight = "ObjectId"
)
Upload User Files Endpoint
Endpoint URL
https://equity-tool-api.urban.org/api/v1/upload-user-file/
Request Parameters
Field Name | Value Type | Definition | Requirement |
---|---|---|---|
resource_lat_column | string | Name of column containing the latitudes for the observations in the resource datatset | required |
resource_lon_column | string | Name of column containing the longitudes for the observations in the resource dataset | required |
resource_file | file | Resource dataset file object | required |
demographic_file | file | Supplemental demographic dataset file object | optional |
demographic_geo_id_column | string | Name of the column containing the census tract FIPS codes/GEOID codes in the demographic dataset | optional (conditionally required if demographic_file included) |
demographic_columns | dictionary | Dictionary where the keys represent the names of the columns containing the additional demographic variables to be analyzed by the spatial equity data tools, and the values represent the names of the corresponding margin of error columns. If a given demographic column does not have a corresponding margin of error column, the value should be provided as NULL or NA. | optional (conditionally required if demographic_file included) |
geographic_file | file | Supplemental geographic dataset file object | optional |
geographic_geo_id_column | string | Name of the column containing the census tract FIPS codes/GEOID codes in the baseline dataset | optional (conditionally required if geographic_file included) |
geographic_columns | dictionary | Dictionary where the keys represent the names of the columns containing the additional baseline variables to be analyzed by the spatial equity data tools, and the values represent the names of the corresponding margin of error columns. If a given baseline column does not have a corresponding margin of error column, the value should be provided as NULL or NA. | optional (conditionally required if geographic_file included) |
resource_weight | string | Name of the column in the resource dataset that contains the weights that will be used in the analysis. | optional |
geo | string | Defines the geographic level of analysis. Either “city”, “county”, “state”, or “national”. | required |
acs_data_year | string | Defines the 5-year ACS data that will be used to for the built-in baseline and demographic data. Possible values are 2019 for the 2015-2019 ACS or 2021 for the 2017-2021 ACS. | required |
Response Format
The response is a JSON object documenting the input parameters selected by the user. Notably, there is a file_id
key that stores the unique file identifier as a string.
Example Request and Response
library(sedtR)
call_upload_user_files(
resource_file_path = here("data", "sample", "dc_test_api_resource.csv"),
resource_lat_column = "Y",
resource_lon_column = "X",
geo = "city",
acs_data_year = "2019",
demographic_file_path = here("data", "sample", "dc_test_api_demographic.csv"),
demographic_geo_id_column = "GEOID",
demographic_columns = list(
nh_white_pop = "nh_white_pop_margin",
hispanic = "hispanic_margin",
hispanic_men = "hispanic_men_margin"
),geographic_file_path = here("data", "sample", "dc_test_api_geographic.csv"),
geographic_geo_id_column = "GEOID",
geographic_columns = list(
hispanic_men = "hispanic_men_margin",
male_under_18 = "male_under_18_margin",
female_under_18 = "female_under_18_margin",
children = "children_margin"
),resource_weight = "ObjectId"
)
$status_code
1] 201
[
$file_id
1] "dec7f671-688e-41f7-b071-11cafede011f" [
import requests
import json
import os
= "https://equity-tool-api.urban.org/api/v1/upload-user-file/"
url
= {
payload "resource_lat_column" : "Y",
"resource_lon_column" : "X",
"geo" : "city",
"acs_data_year" : "2019",
"demographic_geo_id_column" : "GEOID",
"demographic_columns" : json.dumps({
"nh_white_pop":"nh_white_pop_margin",
"hispanic":"hispanic_margin",
"hispanic_men":"hispanic_men_margin"
}),"geographic_geo_id_column" : "GEOID",
"geographic_columns" : json.dumps({
"hispanic_men" : "hispanic_men_margin",
"male_under_18" : "male_under_18_margin",
"female_under_18" : "female_under_18_margin",
"children" : "children_margin"
}),"resource_weight" : "ObjectId"
}
= open("../data/sample/dc_test_api_resource.csv",
resource_file = 'r',
mode ='',
newline='utf-8-sig')
encoding= open("../data/sample/dc_test_api_demographic.csv",
demographic_file = 'r',
mode ='',
newline='utf-8-sig')
encoding= open("../data/sample/dc_test_api_geographic.csv",
geographic_file = 'r',
mode ='',
newline='utf-8-sig')
encoding
= requests.post(url,
r = payload,
data ={"resource_file": resource_file,
files"demographic_file": demographic_file,
"geographic_file": geographic_file}
)
{"id":566,
"file_id":"71a22764-b236-4582-925c-ac91a1b526a4",
"resource_file":"http://equity-tool-api.urban.org/media/documents/user-files/resource/65b6d42e-5031-4adc-a0cf-e37b9af80870_resource.csv",
"resource_file_name":"71a22764-b236-4582-925c-ac91a1b526a4_resource.csv",
"resource_lat_column":"Y",
"resource_lon_column":"X",
"demographic_file":"http://equity-tool-api.urban.org/media/documents/user-files/demographic/4565540d-0dfe-4fed-ba85-587fd9e5d747_demographic.csv",
"demographic_file_name":"71a22764-b236-4582-925c-ac91a1b526a4_demographic.csv",
"demographic_geo_id_column":"GEOID",
"demographic_columns":{"nh_white_pop":"nh_white_pop_margin",
"hispanic":"hispanic_margin",
"hispanic_men":"hispanic_men_margin"
},"geographic_file":"http://equity-tool-api.urban.org/media/documents/user-files/geographic/db8e170a-b574-49fc-ac43-9ea6d46b453f_geographic.csv",
"geographic_file_name":"71a22764-b236-4582-925c-ac91a1b526a4_geographic.csv",
"geographic_geo_id_column":"GEOID",
"geographic_columns":{"hispanic_men":"hispanic_men_margin",
"male_under_18":"male_under_18_margin",
"female_under_18":"female_under_18_margin",
"children":"children_margin"
},"resource_weight":"ObjectId",
"geo":"city",
"acs_data_year":"2019"
}
Get Data Status Endpoint
Endpoint URL
https://equity-tool-api.urban.org/api/v1/get-output-data-status/{file_id}/
Request Parameters
file_id
is the only request parameter for this endpoint. The file_id
is returned in the response of the “Upload User Files” endpoint and is a unique identifier for the API submission.
Response Format
The response content is a JSON object with keys next
, previous
, and null
. The results
key is associated with another JSON object with keys formdata
, fileid
, and file_exists
. fileid
is the same inputted file_id
. file_exists
returns either True
or False
. The formdata
JSON object has three keys: updates
, warnings
, and error-messages
. The “updates” JSON is populated as the code runs in the cloud. It has many keys, but most notably, there is a finished
key that returns True
when the equity calculations have been completed. warnings
intuitively provides a list of keys that either returns booleans to indicate whether a certain warning should be noted or a list of variables that meet certain warning conditions. Similarly, errors
has a list of keys that returns either booleans if that specific error is thrown or a list of variables from the supplemental dataset that leads to errors. For more information on the errors
and warnings
, see Chapter 12.
Example Request and Response
library(sedtR)
get_status("dec7f671-688e-41f7-b071-11cafede011f")
$`next`
NULL
$previous
NULL
$results
$results$formdata
$results$formdata$updates
$results$formdata$updates$started_processing
1] TRUE
[
$results$formdata$updates$read_in_file
1] TRUE
[
$results$formdata$updates$num_rows_file
1] 66
[
$results$formdata$updates$num_filter_rows_dropped
1] 0
[
$results$formdata$updates$num_null_rows_dropped
1] 0
[
$results$formdata$updates$num_rows_dropped_total
1] 9
[
$results$formdata$updates$num_rows_for_processing
1] 58
[
$results$formdata$updates$num_rows_processed
1] 58
[
$results$formdata$updates$num_rows_final
1] 57
[
$results$formdata$updates$num_sub_geo_total
NULL
$results$formdata$updates$num_sub_geo_data
NULL
$results$formdata$updates$g_disp
1] "Washington, DC"
[
$results$formdata$updates$sjoin_started
1] TRUE
[
$results$formdata$updates$finished
1] TRUE
[
$results$formdata$updates$`error-messages`
1] FALSE
[
$results$formdata$updates$tool_geo
1] "city"
[
$results$formdata$updates$tool_sub_geo
1] "tract"
[
$results$formdata$updates$g_disp_fips
1] "1150000"
[
$results$formdata$updates$total_time
1] "4.02"
[
$results$formdata$warnings
$results$formdata$warnings$multiple_geographies_flag
1] FALSE
[
$results$formdata$warnings$num_null_latlon_rows_dropped
1] 0
[
$results$formdata$warnings$num_null_filter_rows_dropped
1] 0
[
$results$formdata$warnings$num_null_weight_rows_dropped
1] 0
[
$results$formdata$warnings$num_out_of_geography_rows_dropped
1] 1
[
$results$formdata$warnings$multiple_geographies_list
NULL
$results$formdata$warnings$few_sub_geos_flag
1] FALSE
[
$results$formdata$warnings$geographic_cols_any_missing_values
list()
$results$formdata$warnings$geographic_dropped_over_half_values_greater_than_total_pop
list()
$results$formdata$warnings$geographic_values_greater_than_total_pop
list()
$results$formdata$warnings$geographic_dropped_over_half_values_negative
list()
$results$formdata$warnings$geographic_dropped_any_values_negative_margin
list()
$results$formdata$warnings$geographic_values_negative
list()
$results$formdata$warnings$geographic_float_values
1] "children_geographic_margin"
[
$results$formdata$warnings$demographic_cols_any_missing_values
list()
$results$formdata$warnings$demographic_dropped_over_half_values_greater_than_total_pop
list()
$results$formdata$warnings$demographic_values_greater_than_total_pop
1] "nh_white_pop_demographic_margin"
[
$results$formdata$warnings$demographic_dropped_over_half_values_negative
list()
$results$formdata$warnings$demographic_dropped_any_values_negative_margin
list()
$results$formdata$warnings$demographic_values_negative
list()
$results$formdata$warnings$demographic_float_values
list()
$results$formdata$`error-messages`
$results$formdata$`error-messages`$`form-data-parameter-validation-failed`
1] FALSE
[
$results$formdata$`error-messages`$data_readin_error
1] FALSE
[
$results$formdata$`error-messages`$df_conversion_to_gdf_failed
1] FALSE
[
$results$formdata$`error-messages`$filter_coltypes_mismatch
1] FALSE
[
$results$formdata$`error-messages`$weight_coltypes_mismatch
1] FALSE
[
$results$formdata$`error-messages`$filter_column_not_in_data
1] FALSE
[
$results$formdata$`error-messages`$all_rows_filtered
1] FALSE
[
$results$formdata$`error-messages`$pts_not_in_any_geography
1] FALSE
[
$results$formdata$`error-messages`$sjoin_failed
1] FALSE
[
$results$formdata$`error-messages`$unable_to_generate_presigned_urls
1] FALSE
[
$results$fileid
1] "dec7f671-688e-41f7-b071-11cafede011f"
[
$results$file_exists
1] TRUE [
= "https://equity-tool-api.urban.org/api/v1/get-output-data-status/"
url = "71a22764-b236-4582-925c-ac91a1b526a4"
example_file_id = url + example_file_id + "/"
full_url = requests.get(full_url)
response = json.loads(response.content)
content
#To view the output in a more clean way:
= json.dumps(content, indent = 4)
content_dump print(content_dump)
{"next": null,
"previous": null,
"results": {
"formdata": {
"updates": {
"started_processing": true,
"read_in_file": true,
"num_rows_file": 66,
"num_filter_rows_dropped": 0,
"num_null_rows_dropped": 0,
"num_rows_dropped_total": 2,
"num_rows_for_processing": 66,
"num_rows_processed": 66,
"num_rows_final": 64,
"num_sub_geo_total": null,
"num_sub_geo_data": null,
"g_disp": "Washington, DC",
"sjoin_started": true,
"finished": true,
"error-messages": false,
"tool_geo": "city",
"tool_sub_geo": "tract",
"g_disp_fips": "1150000",
"total_time": "4.94"
},"warnings": {
"multiple_geographies_flag": false,
"num_null_latlon_rows_dropped": 0,
"num_null_filter_rows_dropped": null,
"num_null_weight_rows_dropped": 0,
"num_out_of_geography_rows_dropped": 2,
"multiple_geographies_list": null,
"few_sub_geos_flag": false,
"geographic_cols_any_missing_values": [],
"geographic_dropped_over_half_values_greater_than_total_pop": [],
"geographic_values_greater_than_total_pop": [],
"geographic_dropped_over_half_values_negative": [],
"geographic_dropped_any_values_negative_margin": [],
"geographic_values_negative": [],
"geographic_float_values": [
"children_geographic_margin"
],"demographic_cols_any_missing_values": [],
"demographic_dropped_over_half_values_greater_than_total_pop": [],
"demographic_values_greater_than_total_pop": [
"nh_white_pop_demographic_margin"
],"demographic_dropped_over_half_values_negative": [],
"demographic_dropped_any_values_negative_margin": [],
"demographic_values_negative": [],
"demographic_float_values": []
},"error-messages": {
"form-data-parameter-validation-failed": false,
"data_readin_error": false,
"df_conversion_to_gdf_failed": false,
"filter_coltypes_mismatch": false,
"weight_coltypes_mismatch": false,
"filter_column_not_in_data": false,
"all_rows_filtered": false,
"pts_not_in_any_geography": false,
"sjoin_failed": false,
"unable_to_generate_presigned_urls": false
}
},"fileid": "71a22764-b236-4582-925c-ac91a1b526a4",
"file_exists": true
} }
Get Output Data Endpoint
Endpoint URL
https://equity-tool-api.urban.org/api/v1/get-output-data/{file_id}/
Request Parameters
file_id
is the only request parameter for this endpoint. The file_id
is returned in the responses of the upload-user-file/
and get-output-data-status/
endpoints and is a unique identifier for the API submission to upload-user-file/
.
Response Format
The response returns a JSON with keys next
, previous
, and results
. results
has a JSON as a value. That JSON has keys result
, fileid
, which returns the file identifier, and file_exists
, which returns a boolean indicating whether the file exists. result
returns a JSON with keys geo_bias_data
, which contains the geographic disparity scores, demographic_bias_data
, which contains the demographic disparity scores, messages
, which is itself a JSON with information on the process, download_links
which containts a JSON of three keys (geo_bias_geojson
, geo_bias_csv
, and demographic_bias_csv
which map to presigned URLS), and bbox
and demographic_bias_sub_geo_list
, which are only relevant for the GUI front end.
Note that this object allows two alternatives to access the geographic and demographic disparity scores: through geo_bias_data
and demo_bias_data
objects and through the presigned URLS in download_links
. Given that the geographic bias data is inherently geographic, the API allows downloading as a CSV or a geojson.
Example Request and Response
library(sedtR)
<- get_output_data("dec7f671-688e-41f7-b071-11cafede011f")
output $status_code
output$file_exists
output$file_id
outputhead(output$geo_bias_data)
head(output$demo_bias_data)
#output$full_api_results #we don't display this because it is a long list (converted from a json)
200
TRUE
"dec7f671-688e-41f7-b071-11cafede011f"
[1] NA
[1] NA
= "https://equity-tool-api.urban.org/api/v1/get-output-data/"
url = "71a22764-b236-4582-925c-ac91a1b526a4"
example_file_id = url + example_file_id + "/"
full_url = requests.get(full_url)
response
#Get a more clean output:
import pandas as pd
import geopandas as gpd
'display.max_columns', None)
pd.set_option(
#Get content from response and access geographic and demographic disparity scores
= json.loads(response.content)
content = content["results"]["result"]["geo_bias_data"]["features"]
geo = content["results"]["result"]["demographic_bias_data"]
dem
#Print content without bulky geo_bias_data and demographic_bias_data
"results"]["result"]["geo_bias_data"]= "Location of geographic bias data"
content["results"]["result"]["demographic_bias_data"]= "Location of demographic bias data"
content[= json.dumps(content, indent = 4)
content_for_print print(content_for_print)
#View Demographic data:
= pd.DataFrame(dem)
dem_df print(dem_df)
#View Geographic data:
= gpd.GeoDataFrame.from_features(geo)
geo_df geo_df.head()
{"next": null,
"previous": null,
"results": {
"result": {
"geo_bias_data": "Location of geographic bias data",
"demographic_bias_data": "Location of demographic bias data",
"messages": {
"updates": {
"started_processing": true,
"read_in_file": true,
"num_rows_file": 66,
"num_filter_rows_dropped": 0,
"num_null_rows_dropped": 0,
"num_rows_dropped_total": 2,
"num_rows_for_processing": 66,
"num_rows_processed": 66,
"num_rows_final": 64,
"num_sub_geo_total": null,
"num_sub_geo_data": null,
"g_disp": "Washington, DC",
"sjoin_started": true,
"finished": false,
"error-messages": false,
"tool_geo": "city",
"tool_sub_geo": "tract",
"g_disp_fips": "1150000",
"total_time": null
},"warnings": {
"multiple_geographies_flag": false,
"num_null_latlon_rows_dropped": 0,
"num_null_filter_rows_dropped": null,
"num_null_weight_rows_dropped": 0,
"num_out_of_geography_rows_dropped": 2,
"multiple_geographies_list": null,
"few_sub_geos_flag": false,
"geographic_cols_any_missing_values": [],
"geographic_dropped_over_half_values_greater_than_total_pop": [],
"geographic_values_greater_than_total_pop": [],
"geographic_dropped_over_half_values_negative": [],
"geographic_dropped_any_values_negative_margin": [],
"geographic_values_negative": [],
"geographic_float_values": [
"children_geographic_margin"
],"demographic_cols_any_missing_values": [],
"demographic_dropped_over_half_values_greater_than_total_pop": [],
"demographic_values_greater_than_total_pop": [
"nh_white_pop_demographic_margin"
],"demographic_dropped_over_half_values_negative": [],
"demographic_dropped_any_values_negative_margin": [],
"demographic_values_negative": [],
"demographic_float_values": []
},"error-messages": {
"form-data-parameter-validation-failed": false,
"data_readin_error": false,
"df_conversion_to_gdf_failed": false,
"filter_coltypes_mismatch": false,
"weight_coltypes_mismatch": false,
"filter_column_not_in_data": false,
"all_rows_filtered": false,
"pts_not_in_any_geography": false,
"sjoin_failed": false,
"unable_to_generate_presigned_urls": false
}
},"download_links" : {
"geo_bias_geojson" : "https://ui-sedt-prod.s3.amazonaws.com/output-data/geo-bias/geojson/...",
"geo_bias_csv" : "https://ui-sedt-prod.s3.amazonaws.com/output-data/geo-bias/csv/",
"demographic_bias_csv" : "'https://ui-sedt-prod.s3.amazonaws.com/output-data/demographic-bias/csv/..."
}, "bbox": [
-77.119759,
38.791645,
-76.909395,
38.99511
],"demographic_bias_sub_geo_list": []
},"fileid": "71a22764-b236-4582-925c-ac91a1b526a4",
"file_exists": true
} }
Rate Limiting
We only allow 300 API calls per hour (i.e., 1 every 12 seconds).