-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Enable GeoPandas drawing #296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -241,6 +241,14 @@ def __init__(self, data, style_function=None): | |||
else: # This is a filename | |||
self.embed = False | |||
self.data = data | |||
elif hasattr(data, 'to_crs'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use isinstance
I have a few custom object with to_crs()
defined 😉
Also, if we use geopandas.geodataframe.GeoDataFrame
we can probably drop the next if
below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My goal was to avoid importing geopandas explicitely in folium.
Otherwise, we'll have another dependency.
Maybe there's some other way to filter that.
'geopandas' in data.__class__().__str__()
is ugly, but may work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know what would be the best approach 😑
Sometimes I think that empowering users by showing how to convert a GeoDataFrame
to GeoJSON
, and its pyproj like crs to EPSG would be better than wrapping all that in folium...
How about we do something like this: if/elif(s) and at the else:
else:
from geopandas import GeoDataFrame, GeoSeries
self.embed = True
if isinstance(data, GeoDataFrame):
self.data = json.loads(data.to_crs(epsg='4326').to_json())
elif isinstance(data, GeoSeries):
self.data = json.loads(data.__geo_interface__)
else:
raise ValueError('Unhandled data type {!r}.'.format(data)) This is untested, but I prefer this patter because the If you disagree let's at least put the |
@ocefpaf
Yet with your piece of code, if I have not installed
Well, this is a matter of readability ; I'll try to think to it further in the coming days. |
@BibMartin you are right. My way can hinder some other failure unrelated to the optional dependency. However, one might argue that whatever we supported was already tested. An alternative would be to use a Anyway, this is not crucial to this PR. I guess that the main goal is to avoid the need of Geopandas as a core dependency. If that starts to get in the way we might try to make this external in a different way. Not sure how yet. I trust your judgement here. Just let me know when you are OK with this so I can merge it. |
@ocefpaf Please tell me if you're okay with this ; I'll squash commits then. |
if hasattr(data, '__geo_interface__'): | ||
# We have a GeoPandas 0.2 object | ||
self.embed = True | ||
self.data = json.loads(json.dumps(data.to_crs(epsg='4326').__geo_interface__)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The self.embed = True
and data.to_crs(epsg='4326')
could be up one level to avoid repetition.
PS: __geo_interface__
is a dict
, right? Just making sure that we need the json.dumps
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
self.embed = True
could be up one level to avoid repetition
True. I do it.
data.to_crs(epsg='4326')
could be up one level to avoid repetition
No, otherwise, the Exception 'Unable to transform this object to a GeoJSON.'
will be replaced by Unknown method 'to_crs'
(or something like this).
PS: geo_interface is a dict, right? Just making sure that we need the json.dumps.
__geo_interface__
is a dict. But we need to do a deep copy of the object here ; otherwise, we'll have unintended side effects : further folium computation (like styling) may modify the geopandas
object...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, otherwise, the Exception 'Unable to transform this object to a GeoJSON.' will be replaced by Unknown method 'to_crs' (or something like this).
I was thinking of a copy like:
a = data.to_crs(epsg='4326')
and then
a.__geo_interface__
or a.to_json()
But that way is fine.
Some minor comments. Will merge as soon as you ping me back. |
@ocefpaf Answers are in the code. Squashed and ready for merge if all is ok to you. |
Awesome @BibMartin! I always learn a lot by reviewing your PRs. Thanks! |
Addresses #34.
Note that it only works with
GeoDataFrame
, becauseGeoSeries.to_json
method fails (it's inherited frompandas.Series
and does not link to the feature transformation code).As for example notebook, the link is here :
http://nbviewer.ipython.org/github/bibmartin/folium/blob/geopandas/examples/GeoPandas.ipynb