arashm
March 29, 2023, 11:43pm
1
Hi,
I’ve searched for a working example of overlaying a map with h3 hexagons using Bokeh. There are a lot of examples using other rendering libraries like Folium but not with Bokeh. If anyone has done this before and can share an example, I’d appreciate it.
Thanks
Arash
arashm
March 30, 2023, 10:57pm
3
H3 is Uber’s Hexagonal Hierarchical Geospatial Indexing System in Python:
https://uber.github.io/h3-py/intro.html
For example, the hexagonal in which the following point belongs to is:
import h3
lat, lng = 37.769377, -122.388903
h3_resolution = 9
h3index = h3.geo_to_h3(lat, lng, h3_resolution)
polygon = h3.h3_to_geo_boundary(h3index
The polygon is a list of 6 pairs of long/lats. I want to decorate (overlay) several of these hexagons on a map.
Bryan
March 31, 2023, 6:11pm
4
If that’s the case, then I think you can:
convert the lat/lon coordinates to web mercator coordinates
pass the converted coordinates to patches
or multi_polygons
arashm
April 5, 2023, 8:11pm
5
Thanks for the tip. This is what I came up. It runs a bit slow for large dataframes so if anyone knows how to speed it up, please let me know.
import h3
import h3pandas
import pandas as pd
import geopandas as gpd
from bokeh.plotting import figure, show
from bokeh.tile_providers import get_provider
import xyzservices.providers as xyz
lat, lng = 32.733801, -117.193394
h3_resolution = 9
h3index = h3.geo_to_h3(lat, lng, h3_resolution)
h3index = list(h3.k_ring(h3index, 1))
df = pd.DataFrame(index=h3index)
df = df.h3.h3_to_geo_boundary()
df.reset_index(inplace=True)
df.rename(columns={'geometry': 'Polygon'}, inplace=True)
df['Polygon'].set_crs(crs='epsg:4324', allow_override=True, inplace=True)
def extract_xy(df):
xx, yy = df['geometry'].exterior.coords.xy
df['xx'] = xx.tolist()
df['yy'] = yy.tolist()
return df
df['geometry'] = df['Polygon'].to_crs('epsg:3857')
# line below is quite slow when dataframe size is large
df = df.apply(extract_xy, axis=1)
x_min = min(min(df['xx'].tolist(), key=min))
x_max = max(max(df['xx'].tolist(), key=max))
y_min = min(min(df['yy'].tolist(), key=min))
y_max = max(max(df['yy'].tolist(), key=max))
tile_provider = get_provider(xyz.OpenStreetMap.Mapnik)
TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select,hover"
p = figure(width=800, height=800,
x_range = (x_min,x_max), y_range=(y_min,y_max),
x_axis_type="mercator", y_axis_type="mercator",
tools = TOOLS)
p.add_tile(tile_provider)
p.patches(df['xx'].tolist(), df['yy'].tolist(), color=["firebrick"]*df.shape[0], alpha=[0.2]*df.shape[0], line_width=2)
show(p)
Bryan
April 5, 2023, 8:43pm
6
It runs a bit slow for large dataframes
@arashm That’s pretty vague, you’ll have to elaborate, or ideally, provide a Minimal Reproducible Example to actually run and investigate for any possible performance tweeks.
Otherwise, there is a new involved WebGL maintainer, so there is some hope that WebGL Patches · Issue #5057 · bokeh/bokeh · GitHub may get implemented at some point in the not-distant future.