How to download GeoJSON

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.

1 Like

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:

https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoDataFrame.to_file.html#geopandas.GeoDataFrame.to_file

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()