Streamlit / pages /Vertbox.py
Vertdure's picture
Update pages/Vertbox.py
1b5eabb verified
raw
history blame
5.65 kB
import streamlit as st
import folium
from streamlit_folium import folium_static
import pyproj
from folium.plugins import Draw
import json
import leafmap.foliumap as leafmap
st.set_page_config(layout="wide")
@st.cache_data
def get_coordinate_systems():
return {
"EPSG:4326": "WGS 84",
"EPSG:3857": "Web Mercator",
"EPSG:2154": "RGF93 / Lambert-93 (France)",
"EPSG:27572": "NTF (Paris) / Lambert zone II (France)",
"EPSG:25832": "ETRS89 / UTM zone 32N (Germany)",
}
def convert_coordinates(bbox, from_crs, to_crs):
transformer = pyproj.Transformer.from_crs(from_crs, to_crs, always_xy=True)
min_x, min_y = transformer.transform(bbox[0], bbox[1])
max_x, max_y = transformer.transform(bbox[2], bbox[3])
return [min_x, min_y, max_x, max_y]
# Styles CSS
st.markdown("""
<style>
.main { padding-top: 0; }
.stApp { margin-top: -80px; }
.css-1kyxreq { justify-content: center; }
.css-5rimss { font-size: 14px; }
</style>
""", unsafe_allow_html=True)
# Sidebar
st.sidebar.title("About")
st.sidebar.info(
"This app is an improved version of the BBox Finder, "
"inspired by bboxfinder.com and using Streamlit."
)
st.sidebar.title("Contact")
st.sidebar.info(
"Your Name\n"
"[GitHub](https://github.com/yourusername) | "
"[LinkedIn](https://www.linkedin.com/in/yourprofile)"
)
# Main layout
col1, col2 = st.columns([4, 1])
with col1:
st.title("Improved BBox Finder")
# Map
m = leafmap.Map(center=[46.2, 6.15], zoom=8) # Centered on Geneva
draw = Draw(
export=True,
position='topleft',
draw_options={'polyline': False, 'polygon': False, 'circle': False, 'marker': False, 'circlemarker': False},
edit_options={'edit': False}
)
draw.add_to(m)
# JavaScript to handle drawing and coordinate updates
m.add_child(folium.Element("""
<script>
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
map.on(L.Draw.Event.CREATED, function (event) {
drawnItems.clearLayers();
var layer = event.layer;
drawnItems.addLayer(layer);
var bounds = layer.getBounds();
var bbox = [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
var bboxString = bbox.join(',');
window.parent.postMessage({
type: 'streamlit:set_widget_value',
key: 'bbox_coords',
value: bboxString
}, '*');
});
</script>
"""))
m.to_streamlit(height=600)
with col2:
st.markdown("<h3 style='text-align: center;'>Coordinates</h3>", unsafe_allow_html=True)
bbox_coords = st.text_input("", key="bbox_coords", label_visibility="collapsed")
# CRS selection
coordinate_systems = get_coordinate_systems()
selected_crs = st.selectbox("Select Coordinate Reference System", options=list(coordinate_systems.keys()), format_func=lambda x: f"{x} - {coordinate_systems[x]}")
if bbox_coords:
try:
bbox = [float(coord.strip()) for coord in bbox_coords.split(',')]
if len(bbox) == 4:
st.markdown(f"<b>Selected CRS: {selected_crs}</b>", unsafe_allow_html=True)
converted_bbox = convert_coordinates(bbox, "EPSG:4326", selected_crs)
result = f"{converted_bbox[0]:.6f},{converted_bbox[1]:.6f},{converted_bbox[2]:.6f},{converted_bbox[3]:.6f}"
st.code(result, language="plaintext")
if st.button(f"Copy {selected_crs}"):
st.write(f"{selected_crs} coordinates copied!")
# Display in other common CRSs
st.markdown("<b>Other common CRSs:</b>", unsafe_allow_html=True)
for epsg, name in coordinate_systems.items():
if epsg != selected_crs:
converted_bbox = convert_coordinates(bbox, "EPSG:4326", epsg)
result = f"{converted_bbox[0]:.6f},{converted_bbox[1]:.6f},{converted_bbox[2]:.6f},{converted_bbox[3]:.6f}"
st.code(f"{epsg}: {result}", language="plaintext")
# Additional formats (GeoJSON, WKT)
st.markdown("<b>GeoJSON</b>", unsafe_allow_html=True)
geojson = json.dumps({
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [[
[bbox[0], bbox[1]],
[bbox[2], bbox[1]],
[bbox[2], bbox[3]],
[bbox[0], bbox[3]],
[bbox[0], bbox[1]]
]]
}
}, indent=2)
st.code(geojson, language="json")
if st.button("Copy GeoJSON"):
st.write("GeoJSON copied!")
st.markdown("<b>WKT</b>", unsafe_allow_html=True)
wkt = f"POLYGON(({bbox[0]} {bbox[1]}, {bbox[2]} {bbox[1]}, {bbox[2]} {bbox[3]}, {bbox[0]} {bbox[3]}, {bbox[0]} {bbox[1]}))"
st.code(wkt, language="plaintext")
if st.button("Copy WKT"):
st.write("WKT copied!")
else:
st.error("Please enter 4 coordinates separated by commas.")
except ValueError:
st.error("Please enter valid coordinates (numbers separated by commas).")
# Footer
st.markdown("<div style='text-align: center; color: gray;'>Created with Streamlit - Inspired by bboxfinder.com</div>", unsafe_allow_html=True)