Mapping Europe with Bokeh (using GeoPandas, and handling MultiPolygons)

Hey,

You can significantly simply your code by using Bokeh’s “GeoJSONDataSource”. Not only will it save you from manually creating the coordinate lists, which is quite error prone as you’ve noticed. It will also be a nice separation between GIS tools and Bokeh (plotting) with geojson being a clean interface. This benefit will be obvious when for example you change GeoPandas for some other tool like OGR, Shapely, PostGIS etc. All serious GIS tools allow exporting to geojson, which then will plugin instantly into you Bokeh plotting code.

import pandas as pd
import numpy as np
from bokeh.io import show, output_notebook
from bokeh.models import GeoJSONDataSource, LinearColorMapper
import geopandas as gpd
from bokeh.palettes import Viridis6 as palette
from bokeh.plotting import figure

output_notebook()

#obtain countries shapes
world = gpd.read_file(gpd.datasets.get_path(‘naturalearth_lowres’))
europe = (world.loc[world[‘continent’] == ‘Europe’])

geo_source = GeoJSONDataSource(geojson=europe.to_json())

p = figure(title=“Europe”, x_range=(-30,60), y_range=(30,85))

p.patches(‘xs’, ‘ys’, fill_alpha=0.7,
fill_color={‘field’: ‘gdp_md_est’, ‘transform’: LinearColorMapper(palette=palette)},
line_color=‘black’, line_width=0.5, source=geo_source)

show(p)

``

Regards,
Rutger

···

On Tuesday, October 31, 2017 at 5:31:30 PM UTC+1, [email protected] wrote:

Dear Bokeh-ers,

Sorry if this is a silly question, but I’m trying to create some graphics which will include coloring a map of Europe, and I’m stuck on a seemingly basic problem.

I’m trying to use the GeoPandas naturalearth_lowres database of countries to extract the ones I’m interested in. The countries geometries are stored mostly as Polygon objects, but occasionally as MultiPolygons. Which is where my problem starts.

I’m trying to tease out the x and y coordinates in the way bokeh requires, but get stuck trying to extract them from MultiPolygons. I found the following helper function (from https://automating-gis-processes.github.io/Lesson5-interactive-map-Bokeh-advanced-plotting.html):

def multiGeomHandler(multi_geometry, coord_type, geom_type):
    """
    Function for handling multi-geometries. Can be MultiPoint, MultiLineString or MultiPolygon.
    Returns a list of coordinates where all parts of Multi-geometries are merged into a single list.
    Individual geometries are separated with np.nan which is how Bokeh wants them.
    # Bokeh documentation regarding the Multi-geometry issues can be found here (it is an open issue)
    # [https://github.com/bokeh/bokeh/issues/2321](https://github.com/bokeh/bokeh/issues/2321)
    """

    for i, part in enumerate(multi_geometry):
        # On the first part of the Multi-geometry initialize the coord_array (np.array)
        if i == 0:
            if geom_type == "MultiPoint":
                coord_arrays = np.append(getPointCoords(part, coord_type), np.nan)
            elif geom_type == "MultiLineString":
                coord_arrays = np.append(getLineCoords(part, coord_type), np.nan)
            elif geom_type == "MultiPolygon":
                coord_arrays = np.append(getPolyCoords(part, coord_type), np.nan)
        else:
            if geom_type == "MultiPoint":
                coord_arrays = np.concatenate([coord_arrays, np.append(getPointCoords(part, coord_type), np.nan)])
            elif geom_type == "MultiLineString":
                coord_arrays = np.concatenate([coord_arrays, np.append(getLineCoords(part, coord_type), np.nan)])
            elif geom_type == "MultiPolygon":
                coord_arrays = np.concatenate([coord_arrays, np.append(getPolyCoords(part, coord_type), np.nan)])

    # Return the coordinates
    return coord_arrays


However, these np.nans, unlike what’s stated at the comment, are throwing errors: They are not recognized by JSON. I tried replacing them with None, other meaningless values (inf), empty lists or tuples, or just 0. This is the closest I got (when replacing np.nan with the empty list ):

Any advice on what I might be missing, or how to get rid of those superfluous lines? I can imagine why they appear, but can’t find a way to simply make it work.

Thanks in advance for any thought! I know it shouldn’t be this difficult.