import streamlit as st import geopandas as gpd import folium from streamlit_folium import folium_static from shapely.geometry import box import requests import json from io import BytesIO import zipfile from PIL import Image import numpy as np # Liste des couches de données Swisstopo LAYERS = { "Bâtiments": "ch.swisstopo.vec25-gebaeude", "Bâtiments 3D": "ch.swisstopo.swissbuildings3d_2", "Réseau hydrographique": "ch.swisstopo.vec25-gewaessernetz", "Réseau routier": "ch.swisstopo.vec25-strassen", "Couverture du sol": "ch.swisstopo.vec25-landesbedeckung", "Limites administratives": "ch.swisstopo.swissboundaries3d", "Modèle numérique de terrain": "ch.swisstopo.swissalti3d", "Carte nationale 1:25'000": "ch.swisstopo.pixelkarte-farbe-pk25.noscale", "Carte nationale 1:50'000": "ch.swisstopo.pixelkarte-farbe-pk50.noscale", "Carte nationale 1:100'000": "ch.swisstopo.pixelkarte-farbe-pk100.noscale", "Orthophoto SWISSIMAGE": "ch.swisstopo.swissimage-product", "Noms géographiques": "ch.swisstopo.swissnames3d", } def extract_swisstopo_data(min_x, min_y, max_x, max_y, layer): bbox = box(min_x, min_y, max_x, max_y) api_url = "https://api3.geo.admin.ch/rest/services/api/MapServer/identify" params = { "geometry": f"{bbox.bounds[0]},{bbox.bounds[1]},{bbox.bounds[2]},{bbox.bounds[3]}", "geometryType": "esriGeometryEnvelope", "layers": f"all:{layer}", "mapExtent": f"{bbox.bounds[0]},{bbox.bounds[1]},{bbox.bounds[2]},{bbox.bounds[3]}", "imageDisplay": "1000,1000,96", "tolerance": "0", "lang": "fr", "sr": "2056" } response = requests.get(api_url, params=params) response.raise_for_status() data = response.json() features = [feature["geometry"] for feature in data["results"]] gdf = gpd.GeoDataFrame.from_features(features, crs="EPSG:2056") return gdf def download_swissimage(min_x, min_y, max_x, max_y): api_url = "https://data.geo.admin.ch/api/stac/v0.9/collections/ch.swisstopo.swissimage-dop10/items" params = { "bbox": f"{min_x},{min_y},{max_x},{max_y}", "datetime": "2022-01-01T00:00:00Z/..", "limit": 1 } response = requests.get(api_url, params=params) response.raise_for_status() data = response.json() if data['features']: asset_url = data['features'][0]['assets']['rgb']['href'] image_response = requests.get(asset_url) image_response.raise_for_status() with zipfile.ZipFile(BytesIO(image_response.content)) as zf: image_file = [f for f in zf.namelist() if f.endswith('.tif')][0] with zf.open(image_file) as file: image = Image.open(file) return np.array(image) return None # Interface utilisateur Streamlit st.title("Extracteur de données Swisstopo") # Sélection de la couche selected_layer_name = st.selectbox( "Sélectionnez la couche de données", list(LAYERS.keys()) ) layer = LAYERS[selected_layer_name] # Entrée des coordonnées col1, col2 = st.columns(2) with col1: min_x = st.number_input("Coordonnée X minimale", value=2600000) min_y = st.number_input("Coordonnée Y minimale", value=1200000) with col2: max_x = st.number_input("Coordonnée X maximale", value=2601000) max_y = st.number_input("Coordonnée Y maximale", value=1201000) if st.button("Extraire les données"): try: # Extraction des données Swisstopo gdf = extract_swisstopo_data(min_x, min_y, max_x, max_y, layer) # Affichage des données st.subheader("Aperçu des données") st.write(gdf.head()) # Visualisation sur une carte st.subheader("Visualisation des données") m = folium.Map(location=[gdf.geometry.centroid.y.mean(), gdf.geometry.centroid.x.mean()], zoom_start=14) folium.GeoJson(gdf).add_to(m) folium_static(m) # Téléchargement des données st.download_button( label="Télécharger les données (GeoJSON)", data=gdf.to_json(), file_name=f"{selected_layer_name.lower().replace(' ', '_')}.geojson", mime="application/json" ) # Téléchargement et affichage de l'image SWISSIMAGE if layer == "ch.swisstopo.swissimage-product": st.subheader("Image SWISSIMAGE") image = download_swissimage(min_x, min_y, max_x, max_y) if image is not None: st.image(image, caption="Image SWISSIMAGE", use_column_width=True) else: st.warning("Aucune image SWISSIMAGE disponible pour cette zone.") except Exception as e: st.error(f"Une erreur s'est produite : {str(e)}") # Informations supplémentaires st.sidebar.markdown("## À propos") st.sidebar.markdown("Cet outil permet d'extraire des données géospatiales de Swisstopo.") st.sidebar.markdown("Développé par Vertdure") st.sidebar.markdown("[Code source](https://huggingface.co/spaces/Vertdure/Streamlit/tree/main)")