diff --git a/conda/environments/all_cuda-118_arch-x86_64.yaml b/conda/environments/all_cuda-118_arch-x86_64.yaml index 40a0a0ed4..080e66dbd 100644 --- a/conda/environments/all_cuda-118_arch-x86_64.yaml +++ b/conda/environments/all_cuda-118_arch-x86_64.yaml @@ -23,10 +23,12 @@ dependencies: - myst-parser - nbsphinx - ninja +- notebook - numpydoc - nvcc_linux-64=11.8 - pre-commit - pydata-sphinx-theme +- pydeck - pytest - pytest-cov - pytest-xdist @@ -34,6 +36,7 @@ dependencies: - rmm=23.04 - scikit-build>=0.13.1 - setuptools +- shapely - sphinx<6 - sysroot_linux-64==2.17 name: all_cuda-118_arch-x86_64 diff --git a/dependencies.yaml b/dependencies.yaml index 6346cae7a..18a26b864 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -14,6 +14,7 @@ files: - py_version - run_python - test_python + - notebooks test_cpp: output: none includes: @@ -172,6 +173,7 @@ dependencies: - ipython - notebook - shapely + - pydeck py_version: specific: - output_types: conda diff --git a/notebooks/README.md b/notebooks/README.md index bd1835dbb..d0c2f430c 100644 --- a/notebooks/README.md +++ b/notebooks/README.md @@ -14,6 +14,7 @@ documentation tree, Notebook Title | Data set(s) | Notebook Description | External Download (Size) --- | --- | --- | --- [NYC Taxi Years Correlation](nyc_taxi_years_correlation.ipynb) | [NYC Taxi Yellow 01/2016, 01/2017, taxi zone data](https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page) | Demonstrates using Point in Polygon to correlate the NYC Taxi datasets pre-2017 `lat/lon` locations with the post-2017 `LocationID` for cross format comparisons. | Yes (~3GB) +[Stop Sign Counting By Zipcode Boundary](ZipCodes_Stops_PiP_cuSpatial.ipynb) | [Stop Sign Locations](https://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop) [Zipcode Boundaries](https://catalog.data.gov/dataset/tiger-line-shapefile-2019-2010-nation-u-s-2010-census-5-digit-zip-code-tabulation-area-zcta5-na) [USA States Boundaries](https://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative) | Demonstrates Quadtree Point-in-Polygon to categorize stop signs by zipcode boundaries. | Yes (~1GB) ## For more details Many more examples can be found in the [RAPIDS Notebooks diff --git a/notebooks/ZipCodes_Stops_PiP_cuSpatial.ipynb b/notebooks/ZipCodes_Stops_PiP_cuSpatial.ipynb new file mode 100644 index 000000000..c47f47753 --- /dev/null +++ b/notebooks/ZipCodes_Stops_PiP_cuSpatial.ipynb @@ -0,0 +1,686 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "458fe838-b143-4d31-9ddd-8efd0217f4a7", + "metadata": {}, + "source": [ + "# Stop Sign Counting By Zipcode in California" + ] + }, + { + "cell_type": "markdown", + "id": "6931011f-0d83-45ce-b254-4b5424b82624", + "metadata": {}, + "source": [ + "This notebook demonstrates the use of geodataframe joins with point-in-polygon in cuSpatial\n", + "\n", + "## Prerequisite: Datasets\n", + "\n", + "Datasets used:\n", + "1. Stops (Signs and Stop lines) dataset from OpenStreetMap\n", + "2. USA ZipCode boundaries from US Census Bureau\n", + "3. USA States boundaries from OpenStreetMap\n", + "\n", + "- OpenStreetMap is open data, licensed under [Open Data Commons Open Database License (ODbL)](https://opendatacommons.org/licenses/odbl/) by the [OpenStreetMap Foundation (OSMF)](https://wiki.osmfoundation.org/wiki/Main_Page).\n", + "- US Census Bureau data is open and free to use: https://www.census.gov/about/policies/open-gov/open-data.html\n", + "- TIGER/Line Shapefile, 2019, 2010 nation, U.S., 2010 Census 5-Digit ZIP Code Tabulation Area (ZCTA5) National, Metadata Updated: November 1, 2022.\" Accessed March xx, 2023. https://catalog.data.gov/dataset/tiger-line-shapefile-2019-2010-nation-u-s-2010-census-5-digit-zip-code-tabulation-area-zcta5-na\n", + "\n", + "Disclaimer: Each user is responsible for checking the content of datasets and the applicable licenses and determining if suitable for the intended use." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "597750fe-518e-4944-8cbe-b84aea22481e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "USA_States.csv found\n", + "USA_Stops_Vertices.csv found\n", + "USA_Zipcodes_2019_Tiger.csv found\n" + ] + } + ], + "source": [ + "# Download the datasets and save as:\n", + "# 1. USA_Stops_Vertices.csv\n", + "# 2. USA_Zipcodes_2019_Tiger.csv\n", + "# 3. USA_States.csv\n", + "\n", + "!if [ ! -f \"USA_States.csv\" ]; then curl \"https://data.rapids.ai/cuspatial/benchmark/USA_States.csv\" -o USA_States.csv; else echo \"USA_States.csv found\"; fi\n", + "!if [ ! -f \"USA_Stops_Vertices.csv\" ]; then curl \"https://data.rapids.ai/cuspatial/benchmark/USA_Stops_Vertices.csv\" -o USA_Stops_Vertices.csv; else echo \"USA_Stops_Vertices.csv found\"; fi\n", + "!if [ ! -f \"USA_Zipcodes_2019_Tiger.csv\" ]; then curl \"https://data.rapids.ai/cuspatial/benchmark/USA_Zipcodes_2019_Tiger.csv\" -o USA_Zipcodes_2019_Tiger.csv; else echo \"USA_Zipcodes_2019_Tiger.csv found\"; fi" + ] + }, + { + "cell_type": "markdown", + "id": "497810f3-acf0-4472-a187-322413c9db11", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Stop signs are an important symbol of city and road development in geographical information systems. This notebook processes all stop sign locations from the dataset, using spatial joins to locate them within the zipcode boundaries located within California. This notebook performs the following steps:\n", + "\n", + "1. Filters the zipcode boundaries located in California with spatial join.\n", + "2. Filters the stop signs located in all the zipcodes with spatial join.\n", + "3. Counts the stop signs by zipcode.\n", + "4. Visualize the result on map." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "b2892e9a-ce32-4e5a-94a9-dd121d2a6ea3", + "metadata": {}, + "outputs": [], + "source": [ + "# Import Necessary Packages\n", + "import os\n", + "import cuspatial, cudf\n", + "import pandas as pd\n", + "import geopandas as gpd\n", + "import numpy as np\n", + "import cupy as cp\n", + "from shapely import wkt\n", + "import pydeck as pdk" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "086eda5a-8eda-46d8-8e90-54a2616799f8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Root folder for datasets\n", + "DATASET_ROOT = \"./\"\n", + "\n", + "def path_of(dataset):\n", + " return os.path.join(DATASET_ROOT, dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "044c84d9-2f82-4de5-a4c5-b7b9e5ef6b93", + "metadata": {}, + "source": [ + "## Load Dataset and Cleanup\n", + "\n", + "We load the datasets and store them as cuSpatial device dataframes. Note that the second cell below loads the dataset with cuDF, then adopts geopandas to parse the WKT (Well-Known Text) strings into shapely objects. This is a slow step performed on CPU and requires data transfer between device and host." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "fcb48a9c-f968-486c-8cb8-7e0de6cc7f1c", + "metadata": {}, + "outputs": [], + "source": [ + "# Import Stop Sign CSV\n", + "d_stops = cudf.read_csv(path_of(\"USA_Stops_Vertices.csv\"), usecols=[\"x\", \"y\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b12cfa00-ad8d-4b9c-93cf-c1a511f8d513", + "metadata": {}, + "outputs": [], + "source": [ + "#Import CSV of Zipcodes\n", + "d_zip = cudf.read_csv(\n", + " path_of(\"USA_Zipcodes_2019_Tiger.csv\"),\n", + " usecols=[\"WKT\", \"ZCTA5CE10\", \"INTPTLAT10\", \"INTPTLON10\"])\n", + "d_zip.INTPTLAT10 = d_zip.INTPTLAT10.astype(\"float\")\n", + "d_zip.INTPTLON10 = d_zip.INTPTLON10.astype(\"float\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "583856a2-0b29-48c1-ade7-3840f640c5e7", + "metadata": {}, + "outputs": [], + "source": [ + "# Load WKT as shapely objects\n", + "h_zip = d_zip.to_pandas()\n", + "h_zip[\"WKT\"] = h_zip[\"WKT\"].apply(wkt.loads)\n", + "h_zip = gpd.GeoDataFrame(h_zip, geometry=\"WKT\", crs='epsg:4326')\n", + "\n", + "# Transfer back to GPU with cuSpatial\n", + "d_zip = cuspatial.from_geopandas(h_zip)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "a13b228d-9a60-4f32-b548-fa6f4240e75e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Load State Boundaries\n", + "states = gpd.read_file(\"USA_States.csv\", geometry='WKT', crs='epsg:4326')\n", + "d_states = cuspatial.from_geopandas(states)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "33da801e-01a3-4c9f-bbba-0c61dc7677d9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "class QuadTree:\n", + " \"\"\"Helper class to use cuspatial quadtree interface\n", + " \"\"\"\n", + " def __init__(self,\n", + " df,\n", + " x_column,\n", + " y_column,\n", + " x_min=None,\n", + " x_max=None,\n", + " y_min=None,\n", + " y_max=None,\n", + " scale = -1,\n", + " max_depth = 15,\n", + " min_size = 12):\n", + "\n", + " self.x_min = df[x_column].min() if not x_min else x_min\n", + " self.x_max = df[x_column].max() if not x_max else x_max\n", + " self.y_min = df[y_column].min() if not y_min else y_min\n", + " self.y_max = df[y_column].max() if not y_max else y_max\n", + " \n", + " self.scale = scale\n", + " self.max_depth = max_depth\n", + " self.min_size = min_size\n", + "\n", + " self.point_df = df\n", + " self.x_column = x_column\n", + " self.y_column = y_column\n", + " \n", + " self.polygon_point_mapping = None\n", + " \n", + " self.d_points = cuspatial.GeoSeries.from_points_xy(\n", + " cudf.DataFrame({\"x\": df[x_column], \"y\": df[y_column]}\n", + " ).interleave_columns())\n", + " \n", + " self.point_indices, self.quadtree = (\n", + " cuspatial.quadtree_on_points(self.d_points,\n", + " self.x_min,\n", + " self.x_max,\n", + " self.y_min,\n", + " self.y_max,\n", + " self.scale,\n", + " self.max_depth,\n", + " self.min_size))\n", + "\n", + " def set_polygon(self, df, poly_column):\n", + " polys = df[poly_column]\n", + "\n", + " parts = polys.polygons.part_offset\n", + " rings = polys.polygons.ring_offset\n", + " x = polys.polygons.x\n", + " y = polys.polygons.y\n", + " \n", + " single_polys = cuspatial.GeoSeries.from_polygons_xy(\n", + " polys.polygons.xy, rings, parts, cp.arange(len(parts))\n", + " )\n", + " \n", + " geometries = cudf.Series(polys.polygons.geometry_offset)\n", + " \n", + " poly_bboxes = cuspatial.polygon_bounding_boxes(single_polys)\n", + " intersections = cuspatial.join_quadtree_and_bounding_boxes(\n", + " self.quadtree, poly_bboxes, self.x_min, self.x_max, self.y_min, self.y_max, self.scale, self.max_depth\n", + " )\n", + " polygon_point_mapping = cuspatial.quadtree_point_in_polygon(\n", + " intersections,\n", + " self.quadtree,\n", + " self.point_indices,\n", + " self.d_points,\n", + " single_polys\n", + " )\n", + "\n", + " # Update Polygon Index to MultiPolygon Index\n", + " polygon_index = geometries.searchsorted(polygon_point_mapping.polygon_index, side=\"right\")-1\n", + " polygon_point_mapping.polygon_index = polygon_index\n", + "\n", + " self.polygon_point_mapping = polygon_point_mapping.reset_index(drop=True)\n", + " \n", + " # Remap point indices\n", + " idx_of_idx = self.point_indices.take(\n", + " self.polygon_point_mapping.point_index\n", + " ).reset_index(drop=True)\n", + " self.polygon_point_mapping.point_index = idx_of_idx\n", + "\n", + " self.polygon_df = df\n", + "\n", + " def _subset_geodf(self, geodf, columns):\n", + " res = cudf.DataFrame()\n", + " for col in columns:\n", + " res[col] = geodf[col]\n", + " return res\n", + "\n", + " def points(self, columns = None):\n", + " if self.polygon_point_mapping is None:\n", + " raise ValueError(\"First set polygon dataframe.\")\n", + " \n", + " if not columns:\n", + " df = self.point_df\n", + " else:\n", + " df = self._subset_geodf(self.point_df, columns)\n", + "\n", + " if any(dtype == \"geometry\" for dtype in df.dtypes):\n", + " df = cuspatial.GeoDataFrame(df)\n", + " \n", + " mapping = self.polygon_point_mapping\n", + " res = df.iloc[mapping.point_index]\n", + " res = res.reset_index(drop=True)\n", + " res[\"polygon_index\"] = mapping.polygon_index\n", + " res[\"point_index\"] = mapping.point_index\n", + " return res\n", + "\n", + " def polygons(self, columns = None):\n", + " if self.polygon_point_mapping is None:\n", + " raise ValueError(\"First set polygon dataframe.\")\n", + " \n", + " if not columns:\n", + " df = self.polygon_df\n", + " else:\n", + " df = self._subset_geodf(self.polygon_df, columns)\n", + " \n", + " if any(dtype == \"geometry\" for dtype in df.dtypes):\n", + " df = cuspatial.GeoDataFrame(df)\n", + " \n", + " mapping = self.polygon_point_mapping\n", + " res = df.iloc[mapping.polygon_index]\n", + " res = res.reset_index(drop=True)\n", + " res[\"polygon_index\"] = mapping.polygon_index\n", + " res[\"point_index\"] = mapping.point_index\n", + " return res\n", + " \n", + " def point_left_join_polygon(self, point_columns=None, polygon_columns=None):\n", + " points = self.points(point_columns)\n", + " polygons = self.polygons(polygon_columns)\n", + " joined = points.merge(polygons, on=[\"polygon_index\", \"point_index\"], how=\"left\")\n", + " joined = joined.drop([\"polygon_index\", \"point_index\"], axis=1)\n", + " return cuspatial.GeoDataFrame(joined)" + ] + }, + { + "cell_type": "markdown", + "id": "eda8fb4c-39ec-44e2-9163-cbbdd91eeb1d", + "metadata": {}, + "source": [ + "## Filtering Zipcode by its Geometric Center\n", + "\n", + "The Zipcode Dataset contains boundaries for all zipcodes in the US. The below uses the geometric center (encoded in `INTPTLON10` and `INTPTLAT10` column) for each zipcode and uses cuspatial's quadtree interface to filter zipcodes located only in California." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c0cadafb-acae-41d6-bbca-c10a8201699c", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/raid/wangm/dev/rapids/cuspatial/python/cuspatial/cuspatial/core/spatial/indexing.py:174: UserWarning: scale -1 is less than required minimum scale 0.009837776664632286. Clamping to minimum scale\n", + " warnings.warn(\n", + "/raid/wangm/dev/rapids/cuspatial/python/cuspatial/cuspatial/core/spatial/join.py:150: UserWarning: scale -1 is less than required minimum scale 0.009837776664632286. Clamping to minimum scale\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "# Use quadtree to filter zip codes\n", + "\n", + "# Build a point quadtree using the geometric center of the zip code region\n", + "zipcode_quadtree = QuadTree(d_zip, x_column=\"INTPTLON10\", y_column=\"INTPTLAT10\")\n", + "\n", + "# Pass boundary\n", + "zipcode_quadtree.set_polygon(d_states, poly_column='geometry')\n", + "\n", + "# Join state and zip code boundaries\n", + "zipcode_by_state = zipcode_quadtree.point_left_join_polygon([\"WKT\", \"ZCTA5CE10\"], [\"STUSPS\"])\n", + "\n", + "# Get Californian zipcodes\n", + "CA_zipcode = zipcode_by_state[zipcode_by_state.STUSPS == 'CA']" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d2571a4a-a898-4e04-9fd2-21eb6b7a7f3e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1762, 33144)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(CA_zipcode), len(d_zip)" + ] + }, + { + "cell_type": "markdown", + "id": "ab387f5a-cf7e-49d4-b3c8-c5b4b059cd4d", + "metadata": {}, + "source": [ + "From the 33K zipcode dataset, 1.7K of them belong to California." + ] + }, + { + "cell_type": "markdown", + "id": "6446d81b-006a-4a0b-995b-a001c9b7766f", + "metadata": {}, + "source": [ + "## Join stop signs dataset with California Zipcode boundaries\n", + "\n", + "The below joins the stop sign dataset (460K data points) with all zip code boundaries in California (1700 data points)." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "370ee37c-1311-4f54-9b0c-afd862c489aa", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/raid/wangm/dev/rapids/cuspatial/python/cuspatial/cuspatial/core/spatial/indexing.py:174: UserWarning: scale -1 is less than required minimum scale 0.0029100948550503493. Clamping to minimum scale\n", + " warnings.warn(\n", + "/raid/wangm/dev/rapids/cuspatial/python/cuspatial/cuspatial/core/spatial/join.py:150: UserWarning: scale -1 is less than required minimum scale 0.0029100948550503493. Clamping to minimum scale\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "# Build a second quadtree with all stop signs in the US\n", + "stop_quadtree = QuadTree(d_stops, x_column='x', y_column='y')\n", + "\n", + "# Pass zip code polygons\n", + "stop_quadtree.set_polygon(CA_zipcode, poly_column=\"WKT\")\n", + "\n", + "# Join the stop signs and the zip code dataframe\n", + "stop_by_zipcode = stop_quadtree.point_left_join_polygon([\"x\", \"y\"], [\"ZCTA5CE10\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "5674f74a-9315-4e1f-ac0d-c45a1b97ae3e", + "metadata": { + "tags": [] + }, + "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", + "
xyZCTA5CE10
0-121.85809437.28078795136
1-121.85664837.27829595136
2-121.85544137.28037595136
3-121.85634337.28319595136
4-121.85660437.28100595136
\n", + "
" + ], + "text/plain": [ + " x y ZCTA5CE10\n", + "0 -121.858094 37.280787 95136\n", + "1 -121.856648 37.278295 95136\n", + "2 -121.855441 37.280375 95136\n", + "3 -121.856343 37.283195 95136\n", + "4 -121.856604 37.281005 95136\n", + "(GPU)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stop_by_zipcode.head()" + ] + }, + { + "cell_type": "markdown", + "id": "4b61f534-faa4-4465-b47b-fb717169f30e", + "metadata": {}, + "source": [ + "## Zipcode counting with cuDF\n", + "\n", + "The below uses [cuDF](https://docs.rapids.ai/api/cudf/stable/index.html) to count the number of stop signs per zip code. Then merge the geometry information from the zipcode dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "247d716c-4718-4aba-8d4f-5f816852194d", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ZCTA5CE10\n", + "94901 131\n", + "94535 205\n", + "95112 103\n", + "95407 126\n", + "93933 205\n", + "Name: stop_count, dtype: int32" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Count the Stop Signs by California Zip Codes\n", + "stop_counts = stop_by_zipcode.groupby(\"ZCTA5CE10\").x.count().rename(\"stop_count\")\n", + "stop_counts.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ccf31694-275d-4987-a318-79bc1ea79e73", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DataFrame Size: 1762\n" + ] + } + ], + "source": [ + "# Fetch the polygon boundaries\n", + "stop_counts_and_bounds = cuspatial.GeoDataFrame(CA_zipcode.merge(stop_counts, on=\"ZCTA5CE10\", how=\"left\"))\n", + "stop_counts_and_bounds[\"stop_count\"] = stop_counts_and_bounds[\"stop_count\"].astype(\"int\").fillna(0)\n", + "print(\"DataFrame Size: \", len(stop_counts_and_bounds))" + ] + }, + { + "cell_type": "markdown", + "id": "d1f2af42-affb-4e9e-ac24-b5583641a366", + "metadata": {}, + "source": [ + "## Visualization\n", + "\n", + "Now, we visualize the stop sign count results using [PyDeck](https://deckgl.readthedocs.io/en/latest/index.html).\n", + "Uncomment to run below:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "6a9cb2d6-c7d3-4063-9b24-47101dba0044", + "metadata": {}, + "outputs": [], + "source": [ + "# # Visualize the Dataset\n", + "\n", + "# # Move dataframe to host for visualization\n", + "# host_df = stop_counts_and_bounds.to_geopandas()\n", + "# host_df = host_df.rename({\"WKT\": \"geometry\"}, axis=1)\n", + "# host_df.head()\n", + "\n", + "# # Geo Center of CA: 120°4.9'W 36°57.9'N\n", + "# view_state = pdk.ViewState(\n", + "# **{\"latitude\": 33.96500, \"longitude\": -118.08167, \"zoom\": 6, \"maxZoom\": 16, \"pitch\": 95, \"bearing\": 0}\n", + "# )\n", + "\n", + "# gpd_layer = pdk.Layer(\n", + "# \"GeoJsonLayer\",\n", + "# data=host_df[[\"geometry\", \"stop_count\", \"ZCTA5CE10\"]],\n", + "# get_polygon=\"geometry\",\n", + "# get_elevation=\"stop_count\",\n", + "# extruded=True,\n", + "# elevation_scale=50,\n", + "# get_fill_color=[227,74,51],\n", + "# get_line_color=[255, 255, 255],\n", + "# auto_highlight=True,\n", + "# filled=True,\n", + "# wireframe=True,\n", + "# pickable=True\n", + "# )\n", + "\n", + "# tooltip = {\"html\": \"Stop Sign Count: {stop_count}
ZipCode: {ZCTA5CE10}\"}\n", + "\n", + "# r = pdk.Deck(\n", + "# gpd_layer,\n", + "# initial_view_state=view_state,\n", + "# map_style=pdk.map_styles.LIGHT,\n", + "# tooltip=tooltip,\n", + "# )\n", + "\n", + "# r.to_html(\"geopandas_layer.html\", notebook_display=False)" + ] + }, + { + "cell_type": "markdown", + "id": "e05fc526-c935-417f-9f53-0f13a0c6d02a", + "metadata": {}, + "source": [ + "### Open geopandas_layer.html to see visualization result\n", + "\n", + "![stop_per_state_map](https://github.com/isVoid/cuspatial/raw/notebook/zipcode_counting/notebooks/stop_states.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7611be2-6dbe-40a5-ae9e-51283737d3f2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/stop_states.png b/notebooks/stop_states.png new file mode 100644 index 000000000..1fb3b1b5a Binary files /dev/null and b/notebooks/stop_states.png differ