Geographical diagrams¶
[1]:
from bokeh.io import output_notebook, show
output_notebook()
It is often useful to be able to relate datasets to their real-world context. You can plot geographic data like any other type of data, for example for Texas Unemployment example, but Bokeh also provides several specialised mechanisms for plotting data in geographic coordinates:
TileSource, specifically WMTSTileSource: allows you to overlay data from any map tile server, including Stamen, OpenStreetMap, ESRI, and custom servers.
GeoJSONDataSource: Allows data to be read in GeoJSON format for use with bokeh plots and glyphs, similar to
ColumnDataSource
.
WMTS Tile Source¶
WTMS is the most common web standard for tiled map data, meaning maps that are provided as standard sized image sections from which the full map can then be created at a specified zoom level. WTMS uses the Web Mercator format, measuring distances from Greenwich, England in a northerly and westerly direction. This is easy to calculate but distorts the global shape.
First we create an empty bokeh chart covering the USA, with the boundaries in metres:
[2]:
from bokeh.models import WMTSTileSource
from bokeh.plotting import figure
[3]:
# web mercator coordinates
USA = x_range, y_range = ((-13884029, -7453304), (2698291, 6455972))
p = figure(
tools="pan, wheel_zoom",
x_range=x_range,
y_range=y_range,
x_axis_type="mercator",
y_axis_type="mercator",
)
[4]:
url = "http://a.basemaps.cartocdn.com/rastertiles/voyager/{Z}/{X}/{Y}.png"
attribution = "Tiles by Carto, under CC BY 3.0. Data by OSM, under ODbL"
p.add_tile(WMTSTileSource(url=url, attribution=attribution))
[4]:
[5]:
show(p)
You can now add anything you would normally use in a bokeh diagram, as long as you get coordinates for it in the Web Mercator format, for example:
[6]:
import numpy as np
import pandas as pd
def wgs84_to_web_mercator(df, lon="lon", lat="lat"):
"""Converts decimal longitude/latitude to Web Mercator format"""
k = 6378137
df["x"] = df[lon] * (k * np.pi / 180.0)
df["y"] = np.log(np.tan((90 + df[lat]) * np.pi / 360.0)) * k
return df
df = pd.DataFrame(
dict(
name=["Austin", "NYC"],
lon=[-97.7431, -74.0059],
lat=[30.2672, 40.7128],
)
)
wgs84_to_web_mercator(df)
[6]:
name | lon | lat | x | y | |
---|---|---|---|---|---|
0 | Austin | -97.7431 | 30.2672 | -1.088071e+07 | 3.537942e+06 |
1 | NYC | -74.0059 | 40.7128 | -8.238299e+06 | 4.970072e+06 |
[7]:
p = figure(
tools="pan, wheel_zoom",
x_range=x_range,
y_range=y_range,
x_axis_type="mercator",
y_axis_type="mercator",
)
p.add_tile(WMTSTileSource(url=url, attribution=attribution))
p.circle(x=df["x"], y=df["y"], fill_color="orange", size=10)
show(p)