diff --git a/code/interactive_exploration.ipynb b/code/interactive_exploration.ipynb new file mode 100644 index 0000000..462db6f --- /dev/null +++ b/code/interactive_exploration.ipynb @@ -0,0 +1,849 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualize data on an interactive map\n", + "\n", + "This notebook uses `lonboard` for interactive visualisation of data." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "import lonboard\n", + "from lonboard.colormap import apply_continuous_cmap\n", + "import matplotlib as mpl\n", + "from mapclassify import classify\n", + "\n", + "from sidecar import Sidecar" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define data path" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "chars_dir = \"/data/uscuni-ulce/processed_data/chars/\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define region" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "region = 69300" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Buildings\n", + "Load building data and ensure the geometries are all valid Polygons." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "buildings = gpd.read_parquet(f\"{chars_dir}buildings/chars_{region}.parquet\").to_crs(4326)\n", + "\n", + "buildings.geometry = buildings.make_valid()\n", + "\n", + "buildings = buildings[buildings.geom_type.str.contains(\"Polygon\")]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a lonboard layer" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.39 s, sys: 500 ms, total: 3.89 s\n", + "Wall time: 3.89 s\n" + ] + } + ], + "source": [ + "%%time\n", + "layer = lonboard.PolygonLayer.from_geopandas(buildings)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Sidecar view (assumes JupyterLab) for more comfortable experience." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "sc = Sidecar(title='buildings')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Map object" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "m = lonboard.Map(layer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display map within the sidecar plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "with sc:\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List avaialable columns" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['index', 'id', 'geometry', 'sdbAre', 'sdbPer', 'sdbCoA', 'ssbCCo',\n", + " 'ssbCor', 'ssbSqu', 'ssbERI', 'ssbElo', 'ssbCCM', 'ssbCCD', 'stbOri',\n", + " 'mtbSWR', 'libNCo', 'ldbPWL', 'ltcBuA', 'mtbAli', 'mtbNDi', 'ltbIBD',\n", + " 'stbCeA', 'nID', 'stbSAl', 'nodeID'],\n", + " dtype='object')" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "buildings.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify a column and pass its values into a choropleth representation within the map. " + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [], + "source": [ + "column = 'stbCeA'\n", + "\n", + "classifier = classify(buildings[column], 'quantiles', k=20)\n", + "normalizer = mpl.colors.Normalize(0, classifier.bins.shape[0])\n", + "vals = normalizer(classifier.yb)\n", + "layer.get_fill_color = apply_continuous_cmap(vals, mpl.colormaps['viridis'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tessellation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load tessellation data and ensure the geometries are all valid Polygons." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "tess = gpd.read_parquet(f\"{chars_dir}tessellations/chars_{region}.parquet\").to_crs(4326)\n", + "\n", + "tess.geometry = tess.make_valid()\n", + "\n", + "tess = tess[tess.geom_type.str.contains(\"Polygon\")]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a lonboard layer" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.28 s, sys: 424 ms, total: 3.7 s\n", + "Wall time: 3.7 s\n" + ] + } + ], + "source": [ + "%%time\n", + "layer = lonboard.PolygonLayer.from_geopandas(tess)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Sidecar view (assumes JupyterLab) for more comfortable experience." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [], + "source": [ + "sc = Sidecar(title='tess')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Map object" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "m = lonboard.Map(layer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display map within the sidecar plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "with sc:\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List avaialable columns" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['enclosure_index', 'geometry', 'stcOri', 'sdcLAL', 'sdcAre', 'sscCCo',\n", + " 'sscERI', 'mtcWNe', 'mdcAre', 'ltcWRB', 'sicCAR', 'stcSAl', 'nodeID'],\n", + " dtype='object')" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tess.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify a column and pass its values into a choropleth representation within the map. " + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [], + "source": [ + "column = 'stcSAl'\n", + "\n", + "classifier = classify(tess[column], 'quantiles', k=20)\n", + "normalizer = mpl.colors.Normalize(0, classifier.bins.shape[0])\n", + "vals = normalizer(classifier.yb)\n", + "layer.get_fill_color = apply_continuous_cmap(vals, mpl.colormaps['viridis'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Enclosures" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data and ensure the geometries are all valid Polygons." + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [], + "source": [ + "enc = gpd.read_parquet(f\"{chars_dir}enclosures/chars_{region}.parquet\").to_crs(4326)\n", + "\n", + "enc.geometry = enc.make_valid()\n", + "\n", + "enc = enc[enc.geom_type.str.contains(\"Polygon\")]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a lonboard layer" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 273 ms, sys: 44.1 ms, total: 317 ms\n", + "Wall time: 316 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "layer = lonboard.PolygonLayer.from_geopandas(enc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Sidecar view (assumes JupyterLab) for more comfortable experience." + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [], + "source": [ + "sc = Sidecar(title='enclosures')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Map object" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [], + "source": [ + "m = lonboard.Map(layer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display map within the sidecar plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [], + "source": [ + "with sc:\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List avaialable columns" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['eID', 'geometry', 'ldkAre', 'ldkPer', 'lskCCo', 'lskERI', 'lskCWA',\n", + " 'ltkOri', 'ltkWNB', 'likWBB'],\n", + " dtype='object')" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "enc.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify a column and pass its values into a choropleth representation within the map. " + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/martin/mambaforge/envs/urban_taxonomy/lib/python3.12/site-packages/mapclassify/classifiers.py:1592: UserWarning: Not enough unique values in array to form 20 classes. Setting k to 7.\n", + " self.bins = quantile(y, k=k)\n" + ] + } + ], + "source": [ + "column = 'likWBB'\n", + "\n", + "classifier = classify(enc[column], 'quantiles', k=20)\n", + "normalizer = mpl.colors.Normalize(0, classifier.bins.shape[0])\n", + "vals = normalizer(classifier.yb)\n", + "layer.get_fill_color = apply_continuous_cmap(vals, mpl.colormaps['viridis'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Streets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data and ensure the geometries are all valid Polygons." + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [], + "source": [ + "streets = gpd.read_parquet(f\"{chars_dir}streets/chars_{region}.parquet\").to_crs(4326)\n", + "\n", + "streets.geometry = streets.make_valid()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a lonboard layer" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 188 ms, sys: 47.5 ms, total: 235 ms\n", + "Wall time: 235 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "layer = lonboard.PathLayer.from_geopandas(streets, width_min_pixels=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Sidecar view (assumes JupyterLab) for more comfortable experience." + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [], + "source": [ + "sc = Sidecar(title='streets')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Map object" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [], + "source": [ + "m = lonboard.Map(layer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display map within the sidecar plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [], + "source": [ + "with sc:\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List avaialable columns" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['osm_id', 'geometry', 'mm_len', 'cdsbool', 'node_start', 'node_end',\n", + " 'sdsLen', 'sssLin', 'ldsMSL', 'ldsRea', 'ldsAre', 'sisBpM', 'sdsSPW',\n", + " 'sdsSPO', 'sdsSWD', 'nID'],\n", + " dtype='object')" + ] + }, + "execution_count": 118, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "streets.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify a column and pass its values into a choropleth representation within the map. " + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": {}, + "outputs": [], + "source": [ + "column = 'sdsSPW'\n", + "\n", + "classifier = classify(streets[column], 'equalinterval', k=20)\n", + "normalizer = mpl.colors.Normalize(0, classifier.bins.shape[0])\n", + "vals = normalizer(classifier.yb)\n", + "layer.get_color = apply_continuous_cmap(vals, mpl.colormaps['viridis'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Nodes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data and ensure the geometries are all valid Polygons." + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": {}, + "outputs": [], + "source": [ + "nodes = gpd.read_parquet(f\"{chars_dir}nodes/chars_{region}.parquet\").to_crs(4326)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a lonboard layer" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 142 ms, sys: 0 ns, total: 142 ms\n", + "Wall time: 141 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "layer = lonboard.ScatterplotLayer.from_geopandas(nodes, radius_min_pixels=2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Sidecar view (assumes JupyterLab) for more comfortable experience." + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [], + "source": [ + "sc = Sidecar(title='nodes')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Map object" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": {}, + "outputs": [], + "source": [ + "m = lonboard.Map(layer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display map within the sidecar plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [], + "source": [ + "with sc:\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List avaialable columns" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['x', 'y', 'mtdDeg', 'lcdMes', 'linP3W', 'linP4W', 'linPDE', 'lcnClo',\n", + " 'lddNDe', 'linWID', 'ldsCDL', 'xcnSCl', 'mtdMDi', 'nodeID', 'geometry',\n", + " 'sddAre', 'midRea', 'midAre'],\n", + " dtype='object')" + ] + }, + "execution_count": 140, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nodes.columns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify a column and pass its values into a choropleth representation within the map. " + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": {}, + "outputs": [], + "source": [ + "column = 'midAre'\n", + "\n", + "classifier = classify(nodes[column], 'quantiles', k=20)\n", + "normalizer = mpl.colors.Normalize(0, classifier.bins.shape[0])\n", + "vals = normalizer(classifier.yb)\n", + "layer.get_fill_color = apply_continuous_cmap(vals, mpl.colormaps['viridis'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "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.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}