Google Maps tiles in Streamlit

TL;DR

Use Google Maps 2D satellite, road and terrain tiles with Plotly in Streamlit, for production.

  1. Make a Google Cloud account to get an API_KEY [link]
  2. Generate a SESSION_KEY of the desired map type [link]
  3. Set the layer source to the tile URL
fig = go.Figure(layout=go.Layout(mapbox=dict(
            style="white-bg",
            layers=[{"below": 'traces',
                     "sourcetype": "raster",
                     "sourceattribution": "Google",
                     "source": [URL]}],

In a bit more detail

Most maps plotted in Python use tiles.
These tiles are typically streamed from a server on request.

Quick and Dirty

You can access Google’s tiles directly without using a KEY.
Use one of these URLs and the above code snippet to set the tile source.

However, this violates Google’s Terms of Service.

ROADMAPS_URL = 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}'
SATELLITE_URL = 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}'
TERRAIN_URL = 'https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}'
SATELLITE_HYBRID_URL = 'https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}'

Production Ready

This requires your to enable billing, don’t worry Google provide enough free requests to cover small projects.

Getting an API key

  1. Make Google Cloud Account + Project + enable billing [docs]
  2. Navigate to the Console → APIs & Services → Library
  3. Select and Enable Map Tiles API
  4. Navigate to the Console → APIs & Services → Credentials
  5. Select Create Credentials → API key
  6. Restrict the API key to Map Tiles only (optional)

Code: getting a session key & plotting

  1. Using python’s requests package we can retrieve a session key and assemble a URL that will plot and conform to Googles T&Cs.
  2. Using Streamlit’s session state we can store the session URL.
  3. Set the Plotly layout to use the URL & plot data
import requests
import plotly.graph_objects as go
from streamlit import session_state as ss
import streamlit as st


def get_session_url(api_key):
    create_session_url = "https://tile.googleapis.com/v1/createSession"

    payload = {
        "mapType": "satellite",
        "language": "en-US",
        "region": "US",
        }

    headers = {'Content-Type': 'application/json'}

    response = requests.post(create_session_url,
                             json=payload,
                             headers=headers,
                             params={'key': api_key})

    if response.status_code == 200:
        session_token = response.json().get('session')
        print("Session token:", session_token)
    else:
        print("Failed to create session:", response.text)

    return ("https://tile.googleapis.com/v1/2dtiles/{z}/{x}/{y}?session="
            + session_token
            + "&key="
            + api_key)

def set_tile_layout(tile_url, lat, lon, zoom=15):
    return go.Layout(
        width=640,
        height=640,
        mapbox=dict(
            style="white-bg",
            layers=[{"below": 'traces',
                     "sourcetype": "raster",
                     "sourceattribution": "Google",
                     "source": [tile_url] }],
            center=dict(lat=lat,
                        lon=lon),
            zoom=15))

if 'tiles_url' not in ss:
       ss.tiles_url = get_session_url(GOOGLE_API_KEY)

fig = go.Figure(layout=set_tile_layout(ss.tiles_url,
                                       df[lat_key].mean(),
                                       df[lon_key].mean()))

fig.add_trace(go.Scattermapbox(
          mode="markers",
          lat=df[lat_key],
          lon=df[lon_key],
          name='Data'))

fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})

st.plotly_chart(fig)
4 Likes