Here we are going through step by step on how to spatially place the responses from API requests on a plot using Python
Open you preferable Python IDE or Python console and initially import the required libraries. This example is quite more complex than the previous example Simple climatic variables plotting. Beside the standard libraries also imported in the previous example, we are going to need a couple of geospatial related libraries to better handle coordinates.
import requestsimport jsonimport numpy as npimport geopandas as gpdimport matplotlib.pyplot as pltimport shapely.geometry
After importing the libraries, we define all the needed variables to proceed. Email, password, climatic_variable_1 and coordinates are the essential variables needed to get your responses from the API. The input coordinates of the API are single points, i.e. to time a call is made on the API it refers to specific location requested. Thus to have a collection of spatially distributed points, multiple requests are needed.
It's a good idea to bring all variables that you are going to use up, in order to avoid "hard coding" values later in the code
# Define the user credentialsemail ='YOUR ACCOUNT EMAIL'password ='YOUR PASSWORD'# Define the climatic variable to plotclimatic_variable_1 ='a-frost-days'# Average Frost Days# Define the coordinates of the polygonlat_point_list = [50.854457,52.518172,50.072651,48.853033,50.854457]lon_point_list = [4.377184,13.407759,14.435935,2.349553,4.377184]# Create a geopandas structure with the coordinatespolygon_geom = shapely.geometry.Polygon(zip(lon_point_list, lat_point_list))gdf = gpd.GeoDataFrame(index=[0], crs='epsg:4326', geometry=[polygon_geom])# total area for the gridxmin, ymin, xmax, ymax= gdf.total_bounds# Define the gridn_cells=5cell_size = (xmax-xmin)/n_cells# Projection of the gridcrs ="+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs"
So far, the polygon, bounding box and projection are defined. Following a grid is defined within this polygon. This grid contains the point coordinates to be used in the API calls
# Create the cells in a loopgrid_cells = []for x0 in np.arange(xmin, xmax+cell_size, cell_size):for y0 in np.arange(ymin, ymax+cell_size, cell_size):# bounds x1 = x0-cell_size y1 = y0+cell_size grid_cells.append(shapely.geometry.box(x0, y0, x1, y1))cell = gpd.GeoDataFrame(grid_cells, columns=['geometry'], crs=crs)lng = cell.centroid.xlat = cell.centroid.y
Following the process, the user needs to generate the temporally authkey to interact with the rest endpoints.
# Step 1: Generate a temporal API key to authentic the other API endpointsheaders ={'accept':'application/json',# Already added when you pass json= but not when you pass data=# 'Content-Type': 'application/json',}json_data ={'email': email,'password': password,}# This the variable that holds the temporally API keyauth_response = requests.post('https://api.answr.space/api:auth/auth/login', headers=headers, json=json_data)
A for loop is used to loop over all points, make the calls to the API and store the responses into a list.
authkey = json.loads(auth_response.content)for i inrange(len(cell)):# Step 2: Loop over the points and get the data from the answr.space API headers ={'accept':'application/json','Authorization':'Bearer '+ authkey['authToken']+'',} params ={'Input_point':'{"type":"point","data":{"lng":'+str(lng[i])+',"lat":'+str(lat[i])+'}}',} response_1 = requests.get('https://api.answr.space/api:climate-variables/' + climatic_variable_1 + '', params=params,headers=headers)
# Convert byte responses to json format climatic_variable_response = json.loads(response_1.content)if response_1.content !=b'null': # Rename json to key to months for better plot visualization. You can find the response keys in the API reference documentation for each endpoint
new_key = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
old_key = {"CV76_M1", "CV76_M2", "CV76_M3", "CV76_M4", "CV76_M5", "CV76_M6", "CV76_M7", "CV76_M8", "CV76_M9", "CV76_M10", "CV76_M11", "CV76_M12"}
responses.append(dict(zip(new_key, list(climatic_variable_response.values()))))else: responses.append(dict(zip(new_key, [0]*12)))
Finally, we can plot the points to spatially understand the variation of the climate statistics.
df_responses = pd.DataFrame(responses)plt.scatter(lng, lat, c = df_responses['March'], cmap='viridis')
In case you want to run the entire process with a single command, bellow you can find the entire code.
import requestsimport jsonimport numpy as npimport geopandas as gpdimport matplotlib.pyplot as pltimport shapely.geometryimport pandas as pd# Define the user credentialsemail ='YOUR ACCOUNT EMAIL'password ='YOUR PASSWORD'# Define the climatic variable to plotclimatic_variable_1 ='a-frost-days'# Average Frost Days# Define the coordinates of the polygonlat_point_list = [50.854457,52.518172,50.072651,48.853033,50.854457]lon_point_list = [4.377184,13.407759,14.435935,2.349553,4.377184]# Create a geopandas structure with the coordinatespolygon_geom = shapely.geometry.Polygon(zip(lon_point_list, lat_point_list))gdf = gpd.GeoDataFrame(index=[0], crs='epsg:4326', geometry=[polygon_geom])# total area for the gridxmin, ymin, xmax, ymax= gdf.total_bounds# Define the gridn_cells=5cell_size = (xmax-xmin)/n_cells# Projection of the gridcrs ="+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs"# Create the cells in a loopgrid_cells = []for x0 in np.arange(xmin, xmax+cell_size, cell_size):for y0 in np.arange(ymin, ymax+cell_size, cell_size):# bounds x1 = x0-cell_size y1 = y0+cell_size grid_cells.append(shapely.geometry.box(x0, y0, x1, y1))cell = gpd.GeoDataFrame(grid_cells, columns=['geometry'], crs=crs)lng = cell.centroid.xlat = cell.centroid.y# Step 1: Generate a temporal API key to authentic the other API endpointsheaders ={'accept':'application/json',# Already added when you pass json= but not when you pass data=# 'Content-Type': 'application/json',}json_data ={'email': email,'password': password,}# This the variable that holds the temporally API keyauth_response = requests.post('https://api.answr.space/api:auth/auth/login', headers=headers, json=json_data)responses = []if auth_response.status_code ==200: authkey = json.loads(auth_response.content)for i inrange(len(cell)):# Step 2: Loop over the points and get the data from the answr.space API headers ={'accept':'application/json','Authorization':'Bearer '+ authkey['authToken']+'',} params ={'Input_point':'{"type":"point","data":{"lng":'+str(lng[i])+',"lat":'+str(lat[i])+'}}',} response_1 = requests.get('https://api.answr.space/api:climate-variables/'+ climatic_variable_1 +'', params=params, headers=headers)# Convert byte responses to json format climatic_variable_response = json.loads(response_1.content)if response_1.content !=b'null': # Rename json to key to months for better plot visualization. You can find the response keys in the API reference documentation for each endpoint
new_key = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October",
"November","December"} old_key ={"CV76_M1","CV76_M2","CV76_M3","CV76_M4","CV76_M5","CV76_M6","CV76_M7","CV76_M8","CV76_M9","CV76_M10","CV76_M11","CV76_M12"} responses.append(dict(zip(new_key, list(climatic_variable_response.values()))))else: responses.append(dict(zip(new_key, [0]*12)))# Convert responses to data frame df_responses = pd.DataFrame(responses) plt.scatter(lng, lat, c = df_responses['March'], cmap='viridis')else:print('Return status code: '+str(auth_response.status_code))print(auth_response.content)