Geographical diagrams

[1]:
from bokeh.io import output_notebook, show


output_notebook()
Loading BokehJS ...

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:

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]:
TileRenderer(
id = 'p1046', …)
[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)