{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# UBER H3\n", "\n", "- [H3 at Uber Engineering](https://eng.uber.com/h3/)\n", "- [H3 library main web site](https://h3geo.org/)\n", "- [H3 Docs](https://h3geo.org/docs/)\n", "\n", "## Use case\n", "\n", "Main use case of H3 in Uber was discretization, bucketing/binning into same grids for data aggregation and unified analysis (https://h3geo.org/docs/highlights/aggregation/).\n", "\n", "Analysis of location data, such as locations of cars in a city, can be done by bucketing locations ([Sahr et al., 2003](http://webpages.sou.edu/~sahrk/sqspc/pubs/gdggs03.pdf)). Using a regular grid provides smooth gradients and the ability to measure differences between cells.\n", "\n", "## Installation\n", "\n", "```bash\n", "pip install h3\n", "```\n", "\n", "or\n", "\n", "```bash\n", "conda install -c conda-forge h3-py\n", "```\n", "\n", "## Quick start\n", "\n", "- API: https://h3geo.org/docs/api/indexing\n", "\n", "- Resolutions: https://h3geo.org/docs/core-library/restable\n", "\n", "- notebooks: https://github.com/uber/h3-py-notebooks/blob/master/notebooks/usage.ipynb" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "from h3 import h3" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "881136a71dfffff\n" ] } ], "source": [ "lat, lng, resolution = 58.377, 26.722, 8\n", "\n", "h3_idx = h3.geo_to_h3(lat, lng, resolution)\n", "\n", "print(h3_idx)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(h3_idx)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(58.37383782604051, 26.726606704737367)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_to_geo(h3_idx)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((58.37265919040021, 26.719193761937298),\n", " (58.36941510290893, 26.724448738875658),\n", " (58.37059334962475, 26.73186159096133),\n", " (58.375016120837024, 26.734020692856625),\n", " (58.378260578119715, 26.728765243488915),\n", " (58.37708189435829, 26.721351164561042))" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_to_geo_boundary(h3_idx, geo_json=False)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((58.37265919040021, 26.719193761937298),\n", " (58.36941510290893, 26.724448738875658),\n", " (58.37059334962475, 26.73186159096133),\n", " (58.375016120837024, 26.734020692856625),\n", " (58.378260578119715, 26.728765243488915),\n", " (58.37708189435829, 26.721351164561042))" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_to_geo_boundary(h3_idx, geo_json=False)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "from shapely.geometry import Polygon" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Polygon(h3.h3_to_geo_boundary(h3_idx, geo_json=True))" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Polygon(h3.h3_to_geo_boundary(h3_idx, geo_json=False))" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "import folium\n", "\n", "def visualize_polygon(polyline, color):\n", " polyline.append(polyline[0])\n", " lat = [p[0] for p in polyline]\n", " lng = [p[1] for p in polyline]\n", " m = folium.Map(location=[sum(lat)/len(lat), sum(lng)/len(lng)], zoom_start=13, tiles='cartodbpositron')\n", " my_PolyLine=folium.PolyLine(locations=polyline,weight=8,color=color)\n", " m.add_child(my_PolyLine)\n", " return m" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "def visualize_hexagons(hexagons, color=\"red\", folium_map=None):\n", " \"\"\"\n", " hexagons is a list of hexcluster. Each hexcluster is a list of hexagons. \n", " eg. [[hex1, hex2], [hex3, hex4]]\n", " \"\"\"\n", " polylines = []\n", " lat = []\n", " lng = []\n", " for hex in hexagons:\n", " polygons = h3.h3_set_to_multi_polygon([hex], geo_json=False)\n", " # flatten polygons into loops.\n", " outlines = [loop for polygon in polygons for loop in polygon]\n", " polyline = [outline + [outline[0]] for outline in outlines][0]\n", " lat.extend(map(lambda v:v[0],polyline))\n", " lng.extend(map(lambda v:v[1],polyline))\n", " polylines.append(polyline)\n", " \n", " if folium_map is None:\n", " m = folium.Map(height=600, width=800, location=[sum(lat)/len(lat), sum(lng)/len(lng)], zoom_start=13, tiles='cartodbpositron')\n", " else:\n", " m = folium_map\n", " for polyline in polylines:\n", " my_PolyLine=folium.PolyLine(locations=polyline,weight=8,color=color)\n", " m.add_child(my_PolyLine)\n", " return m" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_get_resolution(h3_idx)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'871136a71ffffff'" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_to_parent(h3_idx)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h3.h3_get_resolution('871136a71ffffff')" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Make this Notebook Trusted to load map: File -> Trust Notebook" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "m = visualize_hexagons(['871136a31ffffff'])\n", "display(m)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Make this Notebook Trusted to load map: File -> Trust Notebook" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "geoJson = {'type': 'Polygon',\n", " 'coordinates': [[[37.813318999983238, -122.4089866999972145], [ 37.7866302000007224, -122.3805436999997056 ], [37.7198061999978478, -122.3544736999993603], [ 37.7076131999975672, -122.5123436999983966 ], [37.7835871999971715, -122.5247187000021967], [37.8151571999998453, -122.4798767000009008]]] }\n", "\n", "polyline = geoJson['coordinates'][0]\n", "polyline.append(polyline[0])\n", "lat = [p[0] for p in polyline]\n", "lng = [p[1] for p in polyline]\n", "m = folium.Map(location=[sum(lat)/len(lat), sum(lng)/len(lng)], zoom_start=13, tiles='cartodbpositron')\n", "my_PolyLine=folium.PolyLine(locations=polyline,weight=8,color=\"green\")\n", "m.add_child(my_PolyLine)\n", "\n", "hexagons = list(h3.polyfill(geoJson, 8))\n", "polylines = []\n", "lat = []\n", "lng = []\n", "for hex in hexagons:\n", " polygons = h3.h3_set_to_multi_polygon([hex], geo_json=False)\n", " # flatten polygons into loops.\n", " outlines = [loop for polygon in polygons for loop in polygon]\n", " polyline = [outline + [outline[0]] for outline in outlines][0]\n", " lat.extend(map(lambda v:v[0],polyline))\n", " lng.extend(map(lambda v:v[1],polyline))\n", " polylines.append(polyline)\n", "for polyline in polylines:\n", " my_PolyLine=folium.PolyLine(locations=polyline,weight=8,color='red')\n", " m.add_child(my_PolyLine)\n", "display(m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Make this Notebook Trusted to load map: File -> Trust Notebook" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ " \n", "hex_center_coordinates = h3.h3_to_geo(h3_idx) # array of [lat, lng] \n", "hex_boundary = h3.h3_to_geo_boundary(h3_idx) # array of arrays of [lat, lng] \n", "m = visualize_hexagons(list(h3.k_ring_distances(h3_idx, 4)[3]), color=\"purple\")\n", "m = visualize_hexagons(list(h3.k_ring_distances(h3_idx, 4)[2]), color=\"blue\", folium_map=m)\n", "m = visualize_hexagons(list(h3.k_ring_distances(h3_idx, 4)[1]), color=\"green\", folium_map=m)\n", "m = visualize_hexagons(list(h3.k_ring_distances(h3_idx, 4)[0]), color = \"red\", folium_map=m)\n", "display(m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "daskgeo2022a", "language": "python", "name": "daskgeo2022a" }, "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.6" } }, "nbformat": 4, "nbformat_minor": 4 }