On Nov 1, 2017, at 07:45, [email protected] wrote:
The problem seems to be the islands that certain European countries hold – seems like the way I’m currently converting the multiploygons (which happen because of these islands, which define the overall shape of the country as they appear in the geopandas dataset) results in all these separate territories being connected into one messy clump.
And original ideas on how to deal with this rather silly predicament?
On Tuesday, October 31, 2017 at 5:13:00 PM UTC, limor.g…@gmail.com wrote:
Thanks for the prompt reply Bryan!
Here’s the full spec plus my entire code.
system - OSX El Capitan, version 10.11.6, python 2.7.13, Bokeh 0.12.10 (just ran another pip install upgrade now). The browser is Chrome Version 61.0.3163.100 (Official Build) (64-bit).
import pandas as pd
import numpy as np
from bokeh.io import show
from bokeh.models import (
ColumnDataSource,
HoverTool,
LogColorMapper
)
import geopandas as gpd
from bokeh.palettes import Viridis6 as palette
from bokeh.plotting import figure
from bokeh.sampledata.us_counties import data as counties
from bokeh.sampledata.unemployment import data as unemployment
#obtain countries shapes
world = gpd.read_file(gpd.datasets.get_path(‘naturalearth_lowres’))
europe = (world.loc[world[‘continent’] == ‘Europe’])
def convert_GeoPandas_to_Bokeh_format(gdf):
“”"
Function to convert a GeoPandas GeoDataFrame to a Bokeh
ColumnDataSource object.
:param: (GeoDataFrame) gdf: GeoPandas GeoDataFrame with polygon(s) under
the column name 'geometry.'
:return: ColumnDataSource for Bokeh.
"""
gdf_new = gdf.drop('geometry', axis=1).copy()
gdf_new['x'] = gdf.apply(getCoords,
geom_col='geometry',
coord_type='x',
axis=1)
gdf_new['y'] = gdf.apply(getCoords,
geom_col='geometry',
coord_type='y',
axis=1)
return ColumnDataSource(gdf_new)
def getXYCoords(geometry, coord_type):
“”" Returns either x or y coordinates from geometry coordinate sequence. Used with LineString and Polygon geometries.“”"
if coord_type == ‘x’:
return geometry.coords.xy[0]
elif coord_type == ‘y’:
return geometry.coords.xy[1]
def getPolyCoords(geometry, coord_type):
“”" Returns Coordinates of Polygon using the Exterior of the Polygon.“”"
ext = geometry.exterior
return getXYCoords(ext, coord_type)
def getLineCoords(geometry, coord_type):
“”" Returns Coordinates of Linestring object.“”"
return getXYCoords(geometry, coord_type)
def getPointCoords(geometry, coord_type):
“”" Returns Coordinates of Point object.“”"
if coord_type == ‘x’:
return geometry.x
elif coord_type == ‘y’:
return geometry.y
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
“”"
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
def getCoords(row, geom_col, coord_type):
“”"
Returns coordinates (‘x’ or ‘y’) of a geometry (Point, LineString or Polygon) as a list (if geometry is LineString or Polygon).
Can handle also MultiGeometries.
“”"
# Get geometry
geom = row[geom_col]
# Check the geometry type
gtype = geom.geom_type
# "Normal" geometries
# -------------------
if gtype == "Point":
return getPointCoords(geom, coord_type)
elif gtype == "LineString":
return list( getLineCoords(geom, coord_type) )
elif gtype == "Polygon":
return list( getPolyCoords(geom, coord_type) )
# Multi geometries
# ----------------
else:
return list( multiGeomHandler(geom, coord_type, gtype) )
def getGeometryCoords(row, geom, coord_type, shape_type):
“”"
Returns the coordinates (‘x’ or ‘y’) of edges of a Polygon exterior.
:param: (GeoPandas Series) row : The row of each of the GeoPandas DataFrame.
:param: (str) geom : The column name.
:param: (str) coord_type : Whether it’s ‘x’ or ‘y’ coordinate.
:param: (str) shape_type
“”"
# Parse the exterior of the coordinate
if 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] )
# elif shape_type == 'point':
# exterior = row[geom]
# if coord_type == 'x':
# # Get the x coordinates of the exterior
# return exterior.coords.xy[0][0]
# elif coord_type == 'y':
# # Get the y coordinates of the exterior
# return exterior.coords.xy[1][0]
Europe_Source = convert_GeoPandas_to_Bokeh_format(europe)
p = figure(title=“Europe”)
print(Europe_Source)
p.multi_line(‘x’, ‘y’, source=Europe_Source, color=“gray”, line_width=1)
show(p)
(This is evolving code, sorry it’s not pretty yet).
(np.nan was the original value, which would result in the error: ValueError: Out of range float values are not JSON compliant: nan.
When changing np.nan with the empty list I get the map with the awkward lines, as seen above).
Am I missing any detail?
On Tuesday, October 31, 2017 at 4:37:56 PM UTC, Bryan Van de ven wrote:
Hi,
Do you have a very old version of Bokeh? Bokeh has serialized NumPy arrays either using a Base64 encoding for standalone documents, or a pure binary transport or Bokeh server apps, for quite some time now. Alternatively, are you converting the arrays to plain python lists at some point before passing to Bokeh? More information is needed in order to help: system, library, browser versions, etc, and really, a complete example with instructions to run that could be investigated.
Thanks,
Bryan
On Oct 31, 2017, at 11:31, [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
“”"
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.
–
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/cac321ef-8364-498c-8646-bc8a3a27fca5%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
–
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/5897c708-8a3e-493d-8950-54a7645dfcf6%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.