Hello,
Looking to understand a method for downloading data from a geo dataframe? Want to download data as geojson.
Have not found any help articles that work with geojson for file downloads. Any suggestions are appreciated.
Hello,
Looking to understand a method for downloading data from a geo dataframe? Want to download data as geojson.
Have not found any help articles that work with geojson for file downloads. Any suggestions are appreciated.
Hi, so you have a geodataframe already and you want to save it as a geojson?
You can use geopandas for that
https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoDataFrame.to_json.html
Correct - I already have a geodataframe setup and can save it as a shapefile or geojson.
For the purposes of Streamlit, I am looking to allow a user to download using st.download_button. I have been unable to find any help articles describing how to allows a user to download as geojson.
Ah that makes sense, sorry I was a bit slow there.
Does the code below work for you?
import io
import streamlit as st
import geopandas as gpd
def save_geojson_with_bytesio(dataframe):
#Function to return bytesIO of the geojson
shp = io.BytesIO()
dataframe.to_file(shp, driver='GeoJSON')
return shp
#########################################################
#get a geodataframe, this one is inbuilt in geopandas
path_to_data = gpd.datasets.get_path("nybb")
gdf = gpd.read_file(path_to_data)
#########################################################
#########################################################
#download the geodataframe
st.download_button(
label="Download data",
data=save_geojson_with_bytesio(gdf),
file_name='my_geojson.geojson',
mime='application/geo+json',
)
#########################################################
Hey Luke, Do you know of a way to convert a gdf to a shapefile using the download_button method?
See in the docs how to save a gdf in different formats:
using the default driver to save as a shapfile results in an empty file
Sorry, I’m on holiday for two weeks so I’m not near my computer.
I have done this before. You have to zip the shapefile files (for a shapefile there are multiple files) and then download the zip file.
If you can’t get it to work please DM me and I’ll get back to you with some code, but unfortunately it won’t be for two weeks
I don’t know how you ended up with an empty shapefile or that RuntimeError
but indeed making this work was harder that I expected. I was unable to write the shapefile to a buffer. First I tried using the default driver, which is supposed to write a shapefile.
buf = io.BytesIO()
gdf.to_file(buf)
Raised TypeError: expected str, bytes or os.PathLike object, not BytesIO
. So apparently in only works with paths. Then I tried with an explicit driver.
gdf.to_file(buf, driver="ESRI Shapefile")
This didn’t raise any errors and actually wrote something to the buffer, but it was just the .shp
file, I couldn’t find a way to get the other files.
So the only way I found was writing the shapefile to the file system, then read from there and pass the data to st.download_button()
. I wrote a simple streamlit application demonstrating the idea.
import tempfile
from pathlib import Path
import geopandas as gpd
import pandas as pd
import streamlit as st
def gdf_to_shz(gdf, name):
with tempfile.TemporaryDirectory() as tmpdir:
path = Path(tmpdir, f"{name}.shz")
gdf.to_file(path, driver="ESRI Shapefile")
return path.read_bytes()
def main():
ds_name = st.selectbox(label="Select a dataset", options=gpd.datasets.available)
gdf = gpd.read_file(gpd.datasets.get_path(ds_name))
st.dataframe(pd.DataFrame(gdf.to_numpy(), columns=gdf.columns))
st.pyplot(gdf.plot().figure)
st.download_button(
label="Download shapefile",
data=gdf_to_shz(gdf, name=ds_name),
file_name=f"{ds_name}.shz",
)
if __name__ == "__main__":
main()
Hi, apologies for the delay. Just got back from holiday.
Did you manage to get this working? If not, here is code that works for me. I tested and the created shapefile opens and displays in Arcpro.
import io
import streamlit as st
import geopandas as gpd
from zipfile import ZipFile
import tempfile
def save_shapefile_with_bytesio(dataframe,directory):
dataframe.to_file(f"{directory}/user_shapefiles.shp", driver='ESRI Shapefile')
zipObj = ZipFile(f"{directory}/user_shapefiles_zip.zip", 'w')
zipObj.write(f"{directory}/user_shapefiles.shp",arcname = 'user_shapefiles.shp')
zipObj.write(f"{directory}/user_shapefiles.cpg",arcname = 'user_shapefiles.cpg')
zipObj.write(f"{directory}/user_shapefiles.dbf",arcname = 'user_shapefiles.dbf')
zipObj.write(f"{directory}/user_shapefiles.prj",arcname = 'user_shapefiles.prj')
zipObj.write(f"{directory}/user_shapefiles.shx",arcname = 'user_shapefiles.shx')
zipObj.close()
#########################################################
#get a geodataframe, this one is inbuilt in geopandas
path_to_data = gpd.datasets.get_path("naturalearth_cities")
gdf = gpd.read_file(path_to_data)
#########################################################
#########################################################
#download the geodataframe
#we first create a temporary directory
with tempfile.TemporaryDirectory() as tmp:
#create the shape files in the temporary directory
st.write('creating temporary shape file...')
save_shapefile_with_bytesio(gdf,tmp)
with open(f"{tmp}/user_shapefiles_zip.zip", "rb") as file:
st.download_button(
label="Download data",
data=file,
file_name='my_shapefile.zip',
mime='application/zip',
)
#########################################################
The key thing is that we have to save all of the necessary files to get a working shapefile (.shp, .cpg, .dbf, .prj, .shx). Possibly you don’t need all of these, I’m not 100% sure, but for now it works.
We save these files by converting the geodataframe to the files, but we need a place to store them. So for that we have to use the tempfile import to create a temporary directory. Note that I have only tested this on local computers, not on, for example, streamlit cloud.
Then we can add the files in the temp directory into a zip file, and download.
Please let me know if it works for you.
Thanks.
Ah nice! I only read this after I posted my most recent reply. I could have just said, “see above”
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.