import geopandas as gpd
import numpy as np
import lonboard
from core.utils import used_keys
from lonboard.colormap import apply_continuous_cmap
import matplotlib as mpl
from mapclassify import classify
from sidecar import Sidecar
Visualize data on an interactive map
This notebook uses lonboard
for interactive visualisation of data.
Define data path
= "/data/uscuni-eurofab/processed_data/chars/" chars_dir
Define region
= 65806 region
Buildings
Load building data and ensure the geometries are all valid Polygons.
= gpd.read_parquet(f"{chars_dir}buildings_chars_{region}.parquet").to_crs(4326).reset_index()
buildings
= buildings.make_valid()
buildings.geometry
= buildings[buildings.geom_type.str.contains("Polygon")] buildings
Create a lonboard layer
%%time
= lonboard.PolygonLayer.from_geopandas(buildings, opacity=.3) layer
CPU times: user 2.05 s, sys: 226 ms, total: 2.28 s
Wall time: 2.27 s
Create a Sidecar view (assumes JupyterLab) for more comfortable experience.
= Sidecar(title='buildings') sc
Create a Map object
= lonboard.Map(layer) m
Display map within the sidecar plugin
with sc:
display(m)
List avaialable columns
buildings.columns
Index(['index', 'type', 'properties', 'x', 'y', 'id', 'iid', 'geometry',
'ssbCCo', 'ssbCor', 'ssbSqu', 'ssbCCM', 'ssbCCD', 'sdbAre', 'sdbPer',
'sdbCoA', 'ssbERI', 'ssbElo', 'stbOri', 'mtbSWR', 'libNCo', 'ldbPWL',
'mibCou', 'mibLen', 'mibAre', 'mibElo', 'mibERI', 'mibCCo', 'mibLAL',
'mibFR', 'mibSCo', 'ltcBuA', 'mtbAli', 'mtbNDi', 'ltbIBD', 'stbCeA',
'nID', 'stbSAl', 'nodeID'],
dtype='object')
Specify a column and pass its values into a choropleth representation within the map.
# buildings.explore()
= 'sdbAre'
column used_keys[column]
'area of building'
= classify(buildings[column], 'quantiles', k=20)
classifier = mpl.colors.Normalize(0, classifier.bins.shape[0])
normalizer = normalizer(classifier.yb)
vals = apply_continuous_cmap(vals, mpl.colormaps['viridis']) layer.get_fill_color
1:] buildings[column].describe().iloc[
mean 200.075974
std 772.615975
min 4.158652
25% 30.744129
50% 88.798078
75% 188.380757
max 103513.595948
Name: sdbAre, dtype: float64
Tessellation
Load tessellation data and ensure the geometries are all valid Polygons.
= gpd.read_parquet(f"{chars_dir}tessellations_chars_{region}.parquet").to_crs(4326)
tess 'geometry'] = tess.geometry.make_valid()
tess[
= tess[tess.geom_type.str.contains("Polygon")] tess
Create a lonboard layer
%%time
= lonboard.SolidPolygonLayer.from_geopandas(tess, opacity=.2) layer
CPU times: user 5.13 s, sys: 406 ms, total: 5.53 s
Wall time: 5.52 s
Create a Sidecar view (assumes JupyterLab) for more comfortable experience.
= Sidecar(title='tess') sc
Create a Map object
= lonboard.Map(layer) m
Display map within the sidecar plugin
with sc:
display(m)
List avaialable columns
tess.columns
Index(['enclosure_index', 'geometry', 'stcOri', 'sdcLAL', 'sdcAre', 'sscCCo',
'sscERI', 'mtcWNe', 'mdcAre', 'ltcWRB', 'sicCAR', 'stcSAl', 'nID',
'nodeID'],
dtype='object')
= 'mtcWNe'
column used_keys[column]
'perimeter-weighted neighbours of ETC'
Specify a column and pass its values into a choropleth representation within the map.
= classify(tess[column], 'quantiles', k=20)
classifier = mpl.colors.Normalize(0, classifier.bins.shape[0])
normalizer = normalizer(classifier.yb)
vals = apply_continuous_cmap(vals, mpl.colormaps['viridis']) layer.get_fill_color
Enclosures
Load data and ensure the geometries are all valid Polygons.
= gpd.read_parquet(f"{chars_dir}enclosures_chars_{region}.parquet").to_crs(4326)
enc
= enc.make_valid()
enc.geometry
= enc[enc.geom_type.str.contains("Polygon")] enc
Create a lonboard layer
%%time
= lonboard.SolidPolygonLayer.from_geopandas(enc, opacity=.3) layer
CPU times: user 168 ms, sys: 31.9 ms, total: 200 ms
Wall time: 200 ms
Create a Sidecar view (assumes JupyterLab) for more comfortable experience.
= Sidecar(title='enclosures') sc
Create a Map object
= lonboard.Map(layer) m
Display map within the sidecar plugin
with sc:
display(m)
List avaialable columns
enc.columns
Index(['eID', 'geometry', 'ldkAre', 'ldkPer', 'lskCCo', 'lskERI', 'lskCWA',
'ltkOri', 'ltkWNB', 'likWCe', 'likWBB'],
dtype='object')
= 'ldkPer'
column used_keys[column]
'perimeter of enclosure'
Specify a column and pass its values into a choropleth representation within the map.
= classify(enc[column], 'quantiles', k=20)
classifier = mpl.colors.Normalize(0, classifier.bins.shape[0])
normalizer = normalizer(classifier.yb)
vals = apply_continuous_cmap(vals, mpl.colormaps['viridis']) layer.get_fill_color
Streets
Load data and ensure the geometries are all valid Polygons.
= gpd.read_parquet(f"{chars_dir}streets_chars_{region}.parquet")
streets
= streets.make_valid() streets.geometry
Create a lonboard layer
%%time
= lonboard.PathLayer.from_geopandas(streets.to_crs(4326), width_min_pixels=1) layer
CPU times: user 250 ms, sys: 23.2 ms, total: 273 ms
Wall time: 272 ms
Create a Sidecar view (assumes JupyterLab) for more comfortable experience.
= Sidecar(title='streets') sc
Create a Map object
= lonboard.Map(layer) m
Display map within the sidecar plugin
with sc:
display(m)
List avaialable columns
assert np.allclose(streets['sdsLen'] , streets.geometry.length)
if 'mm_len' in streets.columns:
assert np.allclose(streets['mm_len'] , streets.geometry.length)
streets.columns
Index(['geometry', '_status', 'mm_len', 'cdsbool', 'node_start', 'node_end',
'sdsLen', 'sssLin', 'ldsMSL', 'sdsAre', 'ldsRea', 'ldsAre', 'sisBpM',
'sdsSPW', 'sdsSPO', 'sdsSWD', 'nID'],
dtype='object')
'sdsLen', 'sssLin', 'ldsMSL', 'sdsAre', 'ldsRea', 'ldsAre',
streets[['sisBpM', 'sdsSPW', 'sdsSPO', 'sdsSWD']].describe()
sdsLen | sssLin | ldsMSL | sdsAre | ldsRea | ldsAre | sisBpM | sdsSPW | sdsSPO | sdsSWD | |
---|---|---|---|---|---|---|---|---|---|---|
count | 77374.000000 | 77374.000000 | 77374.000000 | 5.267900e+04 | 77374.000000 | 6.464400e+04 | 52397.000000 | 77374.000000 | 77374.000000 | 57729.000000 |
mean | 183.432278 | 0.959614 | 196.258464 | 2.242239e+04 | 136.501137 | 3.738741e+05 | 0.064995 | 32.483240 | 0.702718 | 4.339666 |
std | 363.929170 | 0.106236 | 170.058588 | 4.710648e+04 | 119.552318 | 3.704621e+05 | 0.071708 | 13.008305 | 0.250935 | 1.994679 |
min | 2.000000 | 0.000000 | 3.741196 | 4.152421e-02 | 0.000000 | 4.002875e+01 | 0.000262 | 0.000000 | 0.000000 | 0.000000 |
25% | 58.894980 | 0.977297 | 103.906101 | 3.563385e+03 | 40.000000 | 1.548616e+05 | 0.027475 | 21.761670 | 0.500000 | 3.055577 |
50% | 97.801325 | 0.998925 | 134.558532 | 8.524029e+03 | 122.000000 | 2.476303e+05 | 0.052702 | 30.189255 | 0.701923 | 4.544631 |
75% | 170.871458 | 1.000000 | 214.998976 | 2.084422e+04 | 202.000000 | 4.465998e+05 | 0.085624 | 50.000000 | 1.000000 | 5.754629 |
max | 11193.707415 | 1.000000 | 5524.818599 | 1.276722e+06 | 1788.000000 | 4.554284e+06 | 3.977393 | 50.000000 | 1.000000 | 12.135564 |
Specify a column and pass its values into a choropleth representation within the map.
= 'sdsSPW'
column used_keys[column]
'width of street profile'
= streets[column].fillna(0) streets[column]
= classify(streets[column].astype(int), 'equalinterval', k=20)
classifier = mpl.colors.Normalize(0, classifier.bins.shape[0])
normalizer = normalizer(classifier.yb)
vals = apply_continuous_cmap(vals, mpl.colormaps['viridis']) layer.get_color
Nodes
Load data and ensure the geometries are all valid Polygons.
= gpd.read_parquet(f"{chars_dir}nodes_chars_{region}.parquet").to_crs(4326) nodes
Create a lonboard layer
%%time
= lonboard.ScatterplotLayer.from_geopandas(nodes, radius_min_pixels=2) layer
CPU times: user 69.3 ms, sys: 4.83 ms, total: 74.2 ms
Wall time: 73.6 ms
Create a Sidecar view (assumes JupyterLab) for more comfortable experience.
= Sidecar(title='nodes') sc
Create a Map object
= lonboard.Map(layer, basemap_style=lonboard.basemap.CartoBasemap.Positron) m
Display map within the sidecar plugin
with sc:
display(m)
List avaialable columns
nodes.columns
Index(['x', 'y', 'mtdDeg', 'lcdMes', 'linP3W', 'linP4W', 'linPDE', 'lcnClo',
'lddNDe', 'linWID', 'ldsCDL', 'xcnSCl', 'mtdMDi', 'nodeID', 'geometry',
'sddAre', 'midRea', 'midAre'],
dtype='object')
Specify a column and pass its values into a choropleth representation within the map.
'mtdDeg', 'lcdMes', 'linP3W', 'linP4W', 'linPDE', 'lcnClo',
nodes[['lddNDe', 'linWID', 'ldsCDL', 'xcnSCl', 'mtdMDi', 'nodeID', 'geometry',
'sddAre', 'midRea', 'midAre']].describe()
mtdDeg | lcdMes | linP3W | linP4W | linPDE | lcnClo | lddNDe | linWID | ldsCDL | xcnSCl | mtdMDi | nodeID | sddAre | midRea | midAre | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 61838.000000 | 61838.000000 | 61838.000000 | 61838.000000 | 61838.000000 | 6.183800e+04 | 61838.000000 | 61838.000000 | 61838.000000 | 61838.000000 | 61838.000000 | 61838.00000 | 4.654500e+04 | 61838.000000 | 4.908000e+04 |
mean | 2.567418 | 0.105057 | 0.683189 | 0.130161 | 0.183928 | 1.004460e-06 | 0.005973 | 0.009984 | 319.454293 | 0.027892 | 183.852532 | 30918.50000 | 2.587954e+04 | 20.845176 | 6.426385e+04 |
std | 1.005752 | 0.060368 | 0.116292 | 0.098865 | 0.115463 | 6.709700e-07 | 0.007673 | 0.005341 | 612.723878 | 0.053212 | 280.458199 | 17851.23731 | 4.584542e+04 | 23.542853 | 8.924184e+04 |
min | 1.000000 | -1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000e+00 | 0.000396 | 0.000000 | 0.000000 | 0.000000 | 2.311779 | 0.00000 | 1.159084e+00 | 0.000000 | 1.221930e+01 |
25% | 1.000000 | 0.061856 | 0.625000 | 0.058824 | 0.111111 | 4.621507e-07 | 0.003492 | 0.005882 | 73.066534 | 0.000000 | 74.482961 | 15459.25000 | 5.936987e+03 | 3.000000 | 1.793014e+04 |
50% | 3.000000 | 0.098592 | 0.695652 | 0.111111 | 0.169492 | 8.682536e-07 | 0.005624 | 0.009957 | 181.984598 | 0.000000 | 109.536100 | 30918.50000 | 1.170070e+04 | 16.000000 | 3.585703e+04 |
75% | 3.000000 | 0.142857 | 0.757576 | 0.181818 | 0.238095 | 1.420323e-06 | 0.007255 | 0.013344 | 364.331816 | 0.047619 | 170.624712 | 46377.75000 | 2.549037e+04 | 31.000000 | 7.125945e+04 |
max | 6.000000 | 0.800000 | 1.000000 | 0.777778 | 1.000000 | 7.283451e-06 | 0.534588 | 0.119944 | 22877.000260 | 1.000000 | 11193.902019 | 61837.00000 | 1.170909e+06 | 583.000000 | 1.806340e+06 |
= 'mtdMDi'
column used_keys[column]
'mean distance to neighbouring nodes of street network'
= classify(nodes[column], 'quantiles', k=20)
classifier = mpl.colors.Normalize(0, classifier.bins.shape[0])
normalizer = normalizer(classifier.yb)
vals = apply_continuous_cmap(vals, mpl.colormaps['viridis']) layer.get_fill_color
Compare buildings across the pipeline
import geopandas as gpd
= gpd.read_parquet(f'/data/uscuni-eurofab/microsoft_buildings/ms_ce.pq') all_gdf
= "/data/uscuni-eurofab/"
regions_datadir = gpd.read_parquet(
region_hulls + "regions/" + "ms_ce_region_hulls.parquet"
regions_datadir
) region_hulls.shape
(474, 1)
%%time
= all_gdf.sindex.query(region_hulls.loc[65806, 'convex_hull'], predicate='intersects') bidxs
CPU times: user 11.3 s, sys: 1.68 s, total: 12.9 s
Wall time: 12.8 s
= all_gdf.iloc[bidxs] plotting
%%time
'geometry'] = plotting.simplify(1) plotting[
CPU times: user 1.28 s, sys: 52.6 ms, total: 1.33 s
Wall time: 1.34 s
/home/krasen/eurofab_morphometrics/.pixi/envs/default/lib/python3.12/site-packages/geopandas/geodataframe.py:1819: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
super().__setitem__(key, value)
from lonboard import SolidPolygonLayer, Map
from lonboard.basemap import CartoBasemap
from lonboard.colormap import apply_categorical_cmap
from palettable.colorbrewer.qualitative import Set3_12
from core.cluster_validation import get_color
= SolidPolygonLayer.from_geopandas(
layer =plotting, opacity=0.15
gdf )
/home/krasen/eurofab_morphometrics/.pixi/envs/default/lib/python3.12/site-packages/lonboard/_geoarrow/ops/reproject.py:97: UserWarning: Input being reprojected to EPSG:4326 CRS
warnings.warn("Input being reprojected to EPSG:4326 CRS")
= Map(layer, basemap_style=CartoBasemap.Positron)
m m
= 65806
region_id = '/data/uscuni-eurofab/regions/buildings/'
regions_buildings_dir = gpd.read_parquet(regions_buildings_dir + f'buildings_{region_id}.pq') buildings
= SolidPolygonLayer.from_geopandas(
layer =buildings, opacity=0.15
gdf
)= Map(layer, basemap_style=CartoBasemap.Positron)
m m
/home/krasen/eurofab_morphometrics/.pixi/envs/default/lib/python3.12/site-packages/lonboard/_geoarrow/ops/reproject.py:97: UserWarning: Input being reprojected to EPSG:4326 CRS
warnings.warn("Input being reprojected to EPSG:4326 CRS")
= 65806
region_id = '/data/uscuni-eurofab/processed_data/simplified_buildings/'
buildings_dir = gpd.read_parquet(buildings_dir + f'buildings_{region_id}.parquet') buildings
= SolidPolygonLayer.from_geopandas(
layer =buildings, opacity=0.15
gdf
)= Map(layer, basemap_style=CartoBasemap.Positron)
m m
/home/krasen/eurofab_morphometrics/.pixi/envs/default/lib/python3.12/site-packages/lonboard/_geoarrow/ops/reproject.py:97: UserWarning: Input being reprojected to EPSG:4326 CRS
warnings.warn("Input being reprojected to EPSG:4326 CRS")
= 65806
region_id = '/data/uscuni-eurofab/processed_data/buildings/'
buildings_dir = gpd.read_parquet(buildings_dir + f'buildings_{region_id}.parquet') buildings
# layer = SolidPolygonLayer.from_geopandas(
# gdf=buildings, opacity=0.15
# )
# m = Map(layer, basemap_style=CartoBasemap.Positron)
# m