☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Multipolygons in Bokeh

Community Support
Lefteris_Koulierakis
Lefteris_Koulierakis

Hello everyone.

I have to make a choropleth map and I have a shapefile for this. I read the geometry of this shapefile and the geometry is a MultiPolygon, which I don’t know how to use it.

import geopandas as gpd

shape_adress = r"C:\Users\DIRECTORY\Bokeh"

geodf = gpd.read_file(shape_adress)

According to this link I used the following function:

def getPolyCoords(row, geom, coord_type):
    """Returns the coordinates ('x' or 'y') of edges of a Polygon exterior"""

    # Parse the exterior of the coordinate
    exterior = row[geom].exterior

    if coord_type == 'x':
        # Get the x coordinates of the exterior
        return list( exterior.coords.xy[0] )
    elif coord_type == 'y':
        # Get the y coordinates of the exterior
        return list( exterior.coords.xy[1] )
Then I wrote the following:
geodf['x'] = geodf.apply(getPolyCoords, geom='geometry', coord_type='x', axis=1)
geodf['y'] = geodf.apply(getPolyCoords, geom='geometry', coord_type='y', axis=1)

And I recieved this error:

AttributeError: ("‘MultiPolygon’ object has no attribute ‘exterior’", ‘occurred at index 0’)

Is there a way to overcome this? I have also attached a print screen of my shapefile. The color column is the one that I want to visualize and the PC4 column is the postal code distric that I want to visualize.
Thanks in advance!


<img src='//bokeh-discourse-uploads.s3.dualstack.us-east-1.amazonaws.com/original/1X/d16af1204de79e90bb828548e6e02511bca75b8b.png' width='711' height='292'>
⌁   Link to post
Rutger_Kassies
Rutger_Kassies

Hey,

You should be able to export your GeoPandas DataFrame directly to json, and load that with Bokeh. See this for a full example:

It basically comes down to:

from bokeh.models import GeoJSONDataSource

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

p.patches(‘xs’, ‘ys’, source=geo_source)

``


I hope this gets you on the right track.

Regards,
Rutger

···

On Wednesday, November 8, 2017 at 3:33:03 PM UTC+1, Lefteris Koulierakis wrote:

Hello everyone.

I have to make a choropleth map and I have a shapefile for this. I read the geometry of this shapefile and the geometry is a MultiPolygon, which I don’t know how to use it.

import geopandas as gpd

shape_adress = r"C:\Users\DIRECTORY\Bokeh"

geodf = gpd.read_file(shape_adress)

According to this link I used the following function:

def getPolyCoords(row, geom, coord_type):
    """Returns the coordinates ('x' or 'y') of edges of a Polygon exterior"""

    # Parse the exterior of the coordinate
    exterior = row[geom].exterior

    if coord_type == 'x':
        # Get the x coordinates of the exterior
        return list( exterior.coords.xy[0] )
    elif coord_type == 'y':
        # Get the y coordinates of the exterior
        return list( exterior.coords.xy[1] )
Then I wrote the following:
geodf['x'] = geodf.apply(getPolyCoords, geom='geometry', coord_type='x', axis=1)
geodf['y'] = geodf.apply(getPolyCoords, geom='geometry', coord_type='y', axis=1)

And I recieved this error:

AttributeError: (“‘MultiPolygon’ object has no attribute ‘exterior’”, ‘occurred at index 0’)

Is there a way to overcome this? I have also attached a print screen of my shapefile. The color column is the one that I want to visualize and the PC4 column is the postal code distric that I want to visualize.
Thanks in advance!

⌁   Link to post
Lefteris_Koulierakis
Lefteris_Koulierakis

Thanks for the help! It actually worked! I’ve been struggling a lot with this!

Unfortunately, the graph that I get from matplotlib is different from the bokeh graph and I can’t understand why… You can see the picture below. The column that defines the color is called ‘Color’.

[External image unavailable in archive]

This is the code that I wrote:

shape_adress = r"C:DIRECTORY\Bokeh\shp_brabant_lim.shp"

counties = gpd.read_file(shape_adress)

geojson = counties.to_json()

color_column = ‘Color’

geo_source = GeoJSONDataSource(geojson=geojson)

p = figure(title=“Accumulated”)

p.patches(‘xs’, ‘ys’, fill_alpha=0.7,

fill_color={‘field’: color_column, ‘transform’: LogColorMapper(palette=‘Blues8’)},

line_color=‘black’, line_width=0.5, source=geo_source)

show(p)

⌁   Link to post
Rutger_Kassies
Rutger_Kassies

Hey,

Not being able to look at the data itself, i’m having to guess here. First of all, one of the colormaps seems to be reversed compared to the other. All standard Matplotlib colormaps have a reversed counterpart which you can use by adding the ‘_r’ postfix in the name. I’m not sure how that would work in Bokeh. Its possible of course, but reversing in Matplotlib might be easiest.

Secondly, did you notice that my Bokeh example uses the “LogColorMapper”. Your Matplotlib colorbar looks linear, so you might want to use the “LinearColorMapper” with Bokeh as well.

If this doesn’t solve it, it might help if you share the source of the data so i can try it myself (or use some other public dataset). It looks like standard CBS data, but i assume you manually joined some tabular data to the ‘gemeenten’ shapefile?

Regards,
Rutger

···

On Thursday, November 9, 2017 at 9:49:51 AM UTC+1, Lefteris Koulierakis wrote:

Thanks for the help! It actually worked! I’ve been struggling a lot with this!

Unfortunately, the graph that I get from matplotlib is different from the bokeh graph and I can’t understand why… You can see the picture below. The column that defines the color is called ‘Color’.

This is the code that I wrote:

shape_adress = r"C:DIRECTORY\Bokeh\shp_brabant_lim.shp"

counties = gpd.read_file(shape_adress)

geojson = counties.to_json()

color_column = ‘Color’

geo_source = GeoJSONDataSource(geojson=geojson)

p = figure(title=“Accumulated”)

p.patches(‘xs’, ‘ys’, fill_alpha=0.7,

fill_color={‘field’: color_column, ‘transform’: LogColorMapper(palette=‘Blues8’)},

line_color=‘black’, line_width=0.5, source=geo_source)

show(p)

⌁   Link to post
Bryan
Bryan

Hi,

I can't say for certain, but I very much doubt that it is the precision (i.e. the number of decimal positions) that would be an issue. Rather, it is almost certainly the total number of points being contributing to slowness.

Bokeh has a notion of "Level of Detail" (LOD) downsampling, that can help maintain interactivity when there are a large number of points. Basically, while there is a pan, zoom, etc Bokeh only draws a fraction of the points. But Bokeh only looks a the "top" level number of points to determine if it should turn LOD on. If you have a "smallish" number of patches, that each have a lot of points (or add up to alot points) Bokeh will not turn on LOD because it's only counting the number of polygons, which is not large.

However this is configurable. You can lower the LOD threshold to be less than your number of patches you have, then Bokeh will turn it on for interactive use:

  https://bokeh.pydata.org/en/dev/docs/user_guide/tools.html#controlling-level-of-detail

The other option would be to reduce the number of points in the polygons themselves, before plotting. There are libraries and utilities that will do this kind if simplification but I am not personally familiar with them (others here may know).

Thanks,

Bryan

···

On Nov 9, 2017, at 08:04, Lefteris Koulierakis <elkoulierakis.n@gmail.com> wrote:

I have one more question about this:
The interactive map produced by bokeh is quite slow to use (zoom, move, hover) and I think that this is because my shapefile has 15 decimal points. Do you know if there is a way to reduce the decimal points to five?
I have tried several things but I wasn't successful so far.

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.
To post to this group, send email to bokeh@continuum.io.
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/5175b3f1-1be4-4967-b4d2-4ddf05c8ef07%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

⌁   Link to post
Lefteris_Koulierakis
Lefteris_Koulierakis

The name of my columns now is yyyy-mm.

Unfortunately, my HoverTool doesn’t display the data I want to. This is how my data looks like:

And this is what I get:

You see that the “Numbers” are not displayed correctly. This is my code for the hovertool:

hover = p.select_one(HoverTool)

hover.point_policy = “follow_mouse”

hover.tooltips = [

("Municipality", "@Municipality"),

("Numbers", "@2012-02"),

]

Bokeh probably things that there is a subtraction taking place here (“Numbers”, “@2012-02”)?

⌁   Link to post
Bryan
Bryan

Use braces around the column name, e.g

  @{var-name}

For column names that are not valid JS identifies (i.e. if they have dashes inside them).

Thanks,

Bryan

···

On Nov 16, 2017, at 03:31, Lefteris Koulierakis <elkoulierakis.n@gmail.com> wrote:

The name of my columns now is yyyy-mm.
Unfortunately, my HoverTool doesn't display the data I want to. This is how my data looks like:

And this is what I get:

You see that the "Numbers" are not displayed correctly. This is my code for the hovertool:

hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
    ("Municipality", "@Municipality"),
    ("Numbers", "@2012-02"),
    ]
Bokeh probably things that there is a subtraction taking place here ("Numbers", "@2012-02")?

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.
To post to this group, send email to bokeh@continuum.io.
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/98a8a5a9-914f-47a1-8b51-87fbf8709323%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

⌁   Link to post

End of archived discussion · Replies are disabled