How to plot a polygon on an interactive map using Bokeh in Python ?

Published: February 12, 2024

Tags: Python; Bokeh;

Introduction

Bokeh provides a powerful framework for creating interactive data visualizations. Through the import of geographical toolkits like GeoPandas, Bokeh enables mapping points on a canvas with a simple and effective interface.

Assuming you have the necessary packages installed (Bokeh, Pandas, and Geopandas), here's a step-by-step guide to plotting a polygon to a map using Bokeh:

In a previous article, we explored the process of adding points to a bokeh map. Now, let's delve into plotting polygons. As an example, we'll take on the challenge of plotting the Bermuda Triangle on a map.

Creating a Bokeh map

To begin, let's create a map using Bokeh. There are multiple approaches and tile options available. For this example, let's use the "OpenStreetMap Mapnik" tile:

````from bokeh.plotting import figure, show, output_file`

`p = figure(x_range=(-10000000, -6000000), y_range=(-1000000, 6000000),`
`           x_axis_type="mercator", y_axis_type="mercator")`

`p.add_tile("OpenStreetMap Mapnik")`

`p.grid.visible = False`

`show(p)`
```

The plot above will generate the following visualization:

To accurately plot a polygon on a map, it is crucial to determine the projection system being used. In this case, our map utilizes the Mercator projection. To properly plot our polygon, we must convert the longitudes and latitudes to the appropriate coordinate system. A highly effective tool for accomplishing this task in Python is a geopandas dataframe. In the following example, we will illustrate how to store your data in a geopandas dataframe and convert the coordinate system to ultimately plot our polygon.

Defining the Bermuda Triangle

The Bermuda Triangle can be roughly defined by three points corresponding to three cities: Miami ([25.7617° N, 80.1918° W]), San Juan, Puerto Rico ([18.4671° N, 66.1185° W]), and Hamilton, Bermuda ([32.2951° N, 64.7842° W]):

````data = {'Location':['Miami Florida','San-Juan Puerto-Rico','Hamilton Bermuda'],`
`       'longitude':[-80.1918,-66.118,-64.7842],`
`       'latitude':[25.7617,18.4671,32.2951]}`
```

Creating a GeoPandas DataFrame

To plot a polygon on an interactive map using Bokeh in Python, we must begin by creating a GeoPandas DataFrame.

First, let's store our data in a pandas DataFrame:

````import pandas as pd`

`df = pd.DataFrame(data)`
```

and conver it into a GeoPandas DataFrame

````import geopandas`

`gdf = geopandas.GeoDataFrame(`
`    df, `
`    geometry=geopandas.points_from_xy(df.longitude, df.latitude), `
`    crs="EPSG:4326"`
`)`
```

To determine the coordinate system CRS associated with our DataFrame, we can execute the following command:

````print( gdf.crs )`
```

The code presented here does not correspond to Mercator:

````EPSG:4326`
```

In order to convert our GeoPandas into the Mercator-projection we can do:

````gdf = gdf.to_crs("epsg:3857") # Mercator-projection`
```

At last, our dataset has transformed into the following format:

````               Location  longitude  latitude                          geometry`
`0         Miami Florida   -80.1918   25.7617  POINT (-8926910.342 2969596.279)`
`1  San-Juan Puerto-Rico   -66.1180   18.4671  POINT (-7360222.092 2092294.925)`
`2      Hamilton Bermuda   -64.7842   32.2951  POINT (-7211744.155 3802109.728)`
```

Extracting the coordinates in the Mercator projection

We will now extract the coordinates in the Mercator projection that correspond to the given longitudes and latitudes

````gdf['longitude_x'] = gdf['geometry'].x`
`gdf['latitude_y'] = gdf['geometry'].y`
```

Now, the GeoPandas DataFrame has two new columns that will be used to plot our polygon:

````               Location  longitude  latitude  \`
`0         Miami Florida   -80.1918   25.7617   `
`1  San-Juan Puerto-Rico   -66.1180   18.4671   `
`2      Hamilton Bermuda   -64.7842   32.2951`

`                           geometry   longitude_x    latitude_y  `
`0  POINT (-8926910.342 2969596.279) -8.926910e+06  2.969596e+06  `
`1  POINT (-7360222.092 2092294.925) -7.360222e+06  2.092295e+06  `
`2  POINT (-7211744.155 3802109.728) -7.211744e+06  3.802110e+06`
```

Plotting a polygon on a Bokeh map

To achieve this, we can store the longitudes and latitudes in a list as follows:

````gdf['longitude_x'].to_list()`
`gdf['latitude_y'].to_list()`
```

This will give us the following output:

````[-8926910.341796037, -7360222.092269662, -7211744.155449593]`
`[2969596.2785174837, 2092294.9247172303, 3802109.727954972]`
```

respectively.

We can now visualize our polygon on the map by using the patches() function:

````from bokeh.plotting import figure, show, output_file`

`p = figure(x_range=(-10000000, -6000000), y_range=(-1000000, 6000000),`
`           x_axis_type="mercator", y_axis_type="mercator")`

`p.add_tile("OpenStreetMap Mapnik")`

`lons = gdf['longitude_x'].to_list()`

`lats = gdf['latitude_y'].to_list()`

`p.patches([lons], `
`          [lats],`
`          color=["firebrick"], alpha=[0.4], line_width=4)`

`p.grid.visible = False`

`show(p)`
```