{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Access S2S API\n", "\n", "This notebook walks through an example of sending an API call directly" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from typing import Dict\n", "\n", "import folium as flm # Comment out if you have not installed, or run pip install folium matplotlib mapclassify\n", "import geopandas as gpd\n", "import numpy as np\n", "import pandas as pd\n", "import requests\n", "from geojson_pydantic import Feature, Polygon\n", "from lonboard import Map, ScatterplotLayer\n", "from shapely import from_geojson" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "BASE_URL = \"https://space2stats.ds.io\"\n", "FIELDS_ENDPOINT = f\"{BASE_URL}/fields\"\n", "SUMMARY_ENDPOINT = f\"{BASE_URL}/summary\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Available Fields: ['pop_flood_pct', 'ogc_fid', 'sum_pop_f_0_2020', 'sum_pop_f_10_2020', 'sum_pop_f_15_2020', 'sum_pop_f_1_2020', 'sum_pop_f_20_2020', 'sum_pop_f_25_2020', 'sum_pop_f_30_2020', 'sum_pop_f_35_2020', 'sum_pop_f_40_2020', 'sum_pop_f_45_2020', 'sum_pop_f_50_2020', 'sum_pop_f_55_2020', 'sum_pop_f_5_2020', 'sum_pop_f_60_2020', 'sum_pop_f_65_2020', 'sum_pop_f_70_2020', 'sum_pop_f_75_2020', 'sum_pop_f_80_2020', 'sum_pop_m_0_2020', 'sum_pop_m_10_2020', 'sum_pop_m_15_2020', 'sum_pop_m_1_2020', 'sum_pop_m_20_2020', 'sum_pop_m_25_2020', 'sum_pop_m_30_2020', 'sum_pop_m_35_2020', 'sum_pop_m_40_2020', 'sum_pop_m_45_2020', 'sum_pop_m_50_2020', 'sum_pop_m_55_2020', 'sum_pop_m_5_2020', 'sum_pop_m_60_2020', 'sum_pop_m_65_2020', 'sum_pop_m_70_2020', 'sum_pop_m_75_2020', 'sum_pop_m_80_2020', 'sum_pop_m_2020', 'sum_pop_f_2020', 'sum_pop_2020', 'pop', 'pop_flood']\n" ] } ], "source": [ "response = requests.get(FIELDS_ENDPOINT)\n", "if response.status_code != 200:\n", " raise Exception(f\"Failed to get fields: {response.text}\")\n", "\n", "available_fields = response.json()\n", "print(\"Available Fields:\", available_fields)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "AOIModel = Feature[Polygon, Dict]\n", "\n", "# ~burundi\n", "minx, miny, maxx, maxy = 29.038924, -4.468958, 30.850461, -2.310523\n", "\n", "aoi = {\n", " \"type\": \"Feature\",\n", " \"geometry\": {\n", " \"type\": \"Polygon\",\n", " \"coordinates\": [\n", " [\n", " [minx, maxy],\n", " [minx, miny],\n", " [maxx, miny],\n", " [maxx, maxy],\n", " [minx, maxy],\n", " ]\n", " ],\n", " },\n", " \"properties\": {\"name\": \"Updated AOI\"},\n", "}\n", "\n", "\n", "feat = AOIModel(**aoi)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Define the Request Payload\n", "request_payload = {\n", " \"aoi\": aoi,\n", " \"spatial_join_method\": \"touches\",\n", " \"fields\": [\"sum_pop_2020\"],\n", " \"geometry\": \"polygon\",\n", "}\n", "\n", "# Get Summary Data\n", "response = requests.post(SUMMARY_ENDPOINT, json=request_payload)\n", "if response.status_code != 200:\n", " raise Exception(f\"Failed to get summary: {response.text}\")\n", "\n", "summary_data = response.json()\n", "df = pd.DataFrame(summary_data)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
hex_idgeometrysum_pop_2020
0866ad8087ffffffPOLYGON ((30.10399 -2.3257, 30.11745 -2.29278,...25345.874701
1866ad808fffffffPOLYGON ((30.16219 -2.34876, 30.17563 -2.31584...11870.360712
2866ad8097ffffffPOLYGON ((30.05471 -2.36355, 30.06817 -2.33062...19034.332476
3866ad809fffffffPOLYGON ((30.11291 -2.38662, 30.12636 -2.35369...14700.551092
4866ad80c7ffffffPOLYGON ((30.26964 -2.33398, 30.28307 -2.30106...12067.935215
\n", "
" ], "text/plain": [ " hex_id geometry \\\n", "0 866ad8087ffffff POLYGON ((30.10399 -2.3257, 30.11745 -2.29278,... \n", "1 866ad808fffffff POLYGON ((30.16219 -2.34876, 30.17563 -2.31584... \n", "2 866ad8097ffffff POLYGON ((30.05471 -2.36355, 30.06817 -2.33062... \n", "3 866ad809fffffff POLYGON ((30.11291 -2.38662, 30.12636 -2.35369... \n", "4 866ad80c7ffffff POLYGON ((30.26964 -2.33398, 30.28307 -2.30106... \n", "\n", " sum_pop_2020 \n", "0 25345.874701 \n", "1 11870.360712 \n", "2 19034.332476 \n", "3 14700.551092 \n", "4 12067.935215 " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"geometry\"] = df[\"geometry\"].apply(lambda geom: from_geojson(geom))\n", "gdf = gpd.GeoDataFrame(df, geometry=\"geometry\", crs=\"EPSG:4326\")\n", "gdf.head()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = gdf.explore(\n", " column=\"sum_pop_2020\",\n", " tooltip=\"sum_pop_2020\",\n", " cmap=\"YlGnBu\",\n", " legend=True,\n", " scheme=\"naturalbreaks\",\n", " legend_kwds=dict(colorbar=True, caption=\"Population\", interval=False),\n", " style_kwds=dict(weight=0, fillOpacity=0.8),\n", " name=\"Population by Hexagon\",\n", ")\n", "flm.LayerControl(\"topright\", collapsed=False).add_to(m)\n", "m" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "gdf.loc[:, \"geometry\"] = gdf.geometry.representative_point()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Define custom breaks and corresponding RGBA colors\n", "breaks = [\n", " gdf[\"sum_pop_2020\"].min(),\n", " 1,\n", " 1000,\n", " 10000,\n", " 50000,\n", " 100000,\n", " 200000,\n", " gdf[\"sum_pop_2020\"].max(),\n", "]\n", "colors = np.array(\n", " [\n", " [211, 211, 211, 255], # Light gray for 0\n", " [255, 255, 0, 255], # Yellow for 1-1000\n", " [255, 165, 0, 255], # Orange for 1000-10000\n", " [255, 0, 0, 255], # Red for 10000-50000\n", " [128, 0, 128, 255], # Purple for 50000-100000\n", " [0, 0, 255, 255], # Blue for 100000-200000\n", " [0, 0, 139, 255], # Dark blue for 200000+\n", " ]\n", ")\n", "\n", "# Function to assign colors based on custom bins\n", "\n", "\n", "def assign_color(value, breaks, colors):\n", " for i in range(len(breaks) - 1):\n", " if breaks[i] <= value < breaks[i + 1]:\n", " return colors[i]\n", " return colors[-1] # In case value exceeds all breaks\n", "\n", "\n", "# Map sum_pop_2020 values to colors using the custom function\n", "gdf[\"color\"] = gdf[\"sum_pop_2020\"].apply(lambda x: assign_color(x, breaks, colors))\n", "colors = np.uint8(gdf[\"color\"].tolist())\n", "\n", "# Create the scatterplot layer with the assigned colors\n", "layer = ScatterplotLayer.from_geopandas(gdf, get_radius=2000, get_fill_color=colors)\n", "\n", "m = Map(layer)\n", "m" ] } ], "metadata": { "kernelspec": { "display_name": "book", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.10" } }, "nbformat": 4, "nbformat_minor": 4 }