-
Notifications
You must be signed in to change notification settings - Fork 224
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
Integration with geopandas to plot shapely geometries #608
Comments
I prefer the first option:
Last year I made an accepted PR to support any objects with a It would be great to have similar possibilities for PyGMT! |
Ah cool, haven't heard of I haven't got much time recently, but if you (or someone else) are willing to start, I'm sure it will be much appreciated. Maybe start with a single geometry type (e.g. points or polygon) and we can gradually expand it from there. |
Here is the Python protocol: https://gist.github.com/sgillies/2217756. Its basically GeoJSON. I'm willing to make a start, once I can prioritise time for it! |
Little progress. Currently investigated an approach using geopandas and Fiona. While I'm typing this, I think that GMT might be using Somehow I'm not able to succeed using the import geopandas as gpd
import pygmt
import os geodataframe to pygmt (works)# read geodataframe
gdf = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
gdf = gdf[gdf.continent == 'Africa']
gdf = gdf[['name', 'geometry']]
# collect extent region
bound = gdf.total_bounds
region = [bound[0], bound[2], bound[1], bound[3]]
# write to (tmp) file
# !geopandas (fiona) is not able to overwrite this format
filename = 'example_gdf.gmt'
gdf.to_file(filename, driver='OGR_GMT')
# plot
fig = pygmt.Figure()
fig.basemap(region=region, projection="M20c", frame=True)
fig.plot(data='example_gdf.gmt')
fig.show() geodataframe to pygmt using GMTTempFile (does not work)from pygmt.helpers import GMTTempFile
with GMTTempFile() as tmpfile:
gdf.to_file(tmpfile.name, driver='OGR_GMT')
# plot
fig = pygmt.Figure()
fig.basemap(region=region, projection="M20c", frame=True)
fig.plot(data=tmpfile.name)
fig.show()
|
Wow, this is looking really promising! I was wondering how the GeoJSON -> GMT path would work but seems like you found a great solution here with OGR (never have I been so glad that this standard exists) 😆 On the |
Seems like we need to do import geopandas as gpd
import pygmt
import os
# read geodataframe
gdf = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
gdf = gdf[gdf.continent == "Africa"]
gdf = gdf[["name", "geometry"]]
# collect extent region
bound = gdf.total_bounds
region = [bound[0], bound[2], bound[1], bound[3]]
with pygmt.helpers.GMTTempFile(suffix=".gmt") as tmpfile:
os.remove(tmpfile.name)
gdf.to_file(filename=tmpfile.name, driver="OGR_GMT", mode="w")
# plot
fig = pygmt.Figure()
fig.basemap(region=region, projection="M20c", frame=True)
fig.plot(data=tmpfile.name)
fig.show() Perhaps we should use one of the other Python |
Sorry for not coming back earlier. Always busy end of year. Maybe I can find a moment between Christmas and New year otherwise early January again👍 |
I have been trying a bit with the OGR_GMT is flexible enough for all sorts of geometries, even when you are mixing types. import shapely
import geopandas as gpd
def instance(obj):
return type(obj).__name__
def plot(geom):
fig = pygmt.Figure()
if hasattr(geom, '__geo_interface__') is True:
with pygmt.helpers.GMTTempFile(suffix=".gmt") as tmp_ascii:
os.remove(tmp_ascii.name)
# when possible, use geopandas `to_file` fuction to save geom as OGR_GMT format
if instance(geom) == "GeoDataFrame":
# collect extent region
WSEN = geom.total_bounds
WESN = [WSEN[0], WSEN[2], WSEN[1], WSEN[3]]
geom.to_file(filename=tmp_ascii.name, driver="OGR_GMT", mode="w")
fig.basemap(region=WESN, projection="M20c", frame=True)
fig.plot(data=tmp_ascii.name, pen="2p,tomato,4_2:2p", color='blue', )
return fig.show()
a = shapely.geometry.LineString([(20, 15), (30, 15)])
b = shapely.geometry.Polygon([(20, 10), (23, 10), (23, 14), (20, 14)])
c = shapely.geometry.shape({
"type": "MultiPolygon",
"coordinates": [
[
[[0, 0], [20, 0], [10, 20], [0, 0]], # CCW
[[3, 2], [10, 16], [17, 2], [3, 2]], # CW
],
[
[[6, 4], [14, 4], [10, 12], [6, 4]] # CCW
],
[
[[25, 5], [30, 10], [35, 5], [25, 5]]
]
]
}) gdf = gpd.GeoDataFrame(geometry=[a, b, c]) # multipolygon first
gdf.plot() plot(gdf) gdf = gpd.GeoDataFrame(geometry=[a, b, c]) # linestring first
plot(gdf) I tried setting up the development environment to be able to start a PR, but failed miserably. Hopefully all above provides enough infofor someone more skilled than me to implement it. Two notes:
# store `OGR_GMT` ascii in binary format to reduce size.
with pygmt.helpers.GMTTempFile(suffix=".bf2") as tmp_bf2:
os.remove(tmp_bf2.name)
cnv = f'{tmp_ascii.name} -bo2f > {tmp_bf2.name}'
with pygmt.clib.Session() as session:
session.call_module('convert', cnv)
|
Definitely support the idea to integrate geopandas (geo) dataframes. I assume that the possibility to easily plot shape file stuff atop GMT maps allows us to attract lot's of new users to use PyGMT. |
FYI, I'm working on #961 which will lay the groundwork for |
Ok, the initial PyGMT-GeoPandas integration has been done in #1000! To try it out, do:
We'll still need to add some documentation around this, but we would appreciate it if people can test this out and give us feedback before PyGMT v0.4.0 release (~June 2021). I anticipate issues around complex multipolygon features, and mixed geometry types, but plotting basic points/lines/polygons should be ok 🤞. Just leave a comment below or start a new issue if you find anything that could be improved! |
Description of the desired feature
Geopandas is somewhat of a defacto geographic data structure in Python nowadays, and is used to hold vector shapes like Polygons, Lines and Points. What might be useful is if we can have PyGMT plot
geopandas
Data Structures (e.g.geopandas.GeoDataFrame
s) directly. Something like so:One way would be to change
plot
to acceptgeopandas
type objects, look for the 'geometry' column, and plot the 'Shapely' geometries.Currently, users need to go through a convoluted process such as with the following (adapted from https://forum.generic-mapping-tools.org/t/shapefile-to-gmt-python/834/21, also xref GenericMappingTools/foss4g2019oceania#7):
produces:
Using
data=geodataframe
seems like the easiest, but we could consider alternative ways of implementing thegeopandas
integration. There might need to be separate code pathways for handling Points, Lines, and Polygons.👋 Would be good to hear from the geo-community: What is your preferred way of putting data into a plot function?
fig.plot(data=geodata)
geodata.gmt.plot(style=...)
Are you willing to help implement and maintain this feature? Yes, but discuss first 😄
Related issues that may benefit from this:
#392, #493
The text was updated successfully, but these errors were encountered: