I'm using streamlit-folium
to visualize a map in Streamlit and let the user select a custom number of points.
The map has a default starting point but in my wish the user can explore the map with the help of a search bar.
import folium
import streamlit as st
from folium.plugins import Draw
from geopy.geocoders import Nominatim
from streamlit_folium import st_folium
# Default location
x, y = [41.00, 29.00]
# Search for another location
location_input = st.text_input("Search in the map")
if location_input:
location = Nominatim(user_agent="GetLoc")
getLocation = location.geocode(location_input)
x, y = getLocation.latitude, getLocation.longitude
# Draw the map centered in location
m = folium.Map(location=[x,y],zoom_start=12)
Draw(
draw_options={
'polyline': False, 'rectangle': False,
'circle': False, 'polygon': False,
'circlemarker': False
},
edit_options={'remove': False}
).add_to(m)
Map = st_folium(m, width = 700, height=500)
Hope someone can help. I will keep updating this post if I reach something on my own. Thank you very much.
I solved my problem. Here's the code:
import folium
import streamlit as st
from folium.plugins import Draw
from streamlit_folium import st_folium
from typing import Union
import geocoder
import requests
import urllib.parse
def latlon(address: str) -> tuple[float, float]:
url = f"https://nominatim.openstreetmap.org/search/{urllib.parse.quote(address)}?format=json"
response = requests.get(url).json()
return response[0]["lat"], response[0]["lon"]
def geolocalize() -> Union[tuple[float, float], None]:
try:
latitude, longitude = geocoder.ip('me').latlng
return latitude, longitude
except:
return None
def geo_map(
name: str,
search_hint: dict[str, str],
extra_hint: dict[str, str],
submit: dict[str, str],
lang: str
) -> dict[list[float],str]:
c1, c2 = st.columns(2)
with c1:
if "geolocalized" not in st.session_state:
st.session_state.geolocalized = geolocalize()
if f"location_input_{name}" not in st.session_state:
st.session_state[f"location_input_{name}"] = ""
location_input = st.text_input(
label="", placeholder=search_hint[lang], key=f"text_input_{name}"
)
try:
if location_input==st.session_state[f"location_input_{name}"]:
raise Exception
x, y = latlon(location_input)
st.session_state[f"location_input_{name}"]=location_input
st.session_state[f"location_coord_{name}"]=[x,y]
except:
last_clicked = None
if f"lastclicked_{name}" in st.session_state:
last_clicked = st.session_state[f"lastclicked_{name}"]
last_marker = None
if f"lastmarker_{name}" in st.session_state:
last_marker = st.session_state[f"lastmarker_{name}"]
if f"location_coord_{name}" in st.session_state and st.session_state[f"location_coord_{name}"]:
x, y = st.session_state[f"location_coord_{name}"]
elif last_marker or last_clicked:
x, y = last_marker[::-1] or [last_clicked["lat"], last_clicked["lng"]]
else:
x, y = [45.971750,13.639878]\
or st.session_state.geolocalized \
or [45.652020, 13.783930] # HQ
## Map
m = folium.Map(location=[x,y], zoom_start=15)
draw_options={foo: False for foo in ['polyline', 'rectangle', 'circle', 'polygon', 'circlemarker']}
##draw_options['marker'] = {'icon'=}
Draw(
draw_options=draw_options,
edit_options={'edit':False, 'remove': False}
).add_to(m)
if f"points_{name}" in st.session_state:
for point in st.session_state[f"points_{name}"]:
x, y = [float(n) for n in point[1:-1].split(',')]
folium.Marker(
#?
location=[y,x],
#?
tooltip = st.session_state[f"points_{name}"][point] or None
).add_to(m)
Map = st_folium(m, width = 700, height=500, key=f"map_{name}")
if f"points_{name}" not in st.session_state:
st.session_state[f"points_{name}"] = {}
if f"lastclicked_{name}" not in st.session_state:
st.session_state[f"lastclicked_{name}"] = None
if f"lastmarker_{name}" not in st.session_state:
st.session_state[f"lastmarker_{name}"] = None
with c2:
points = Map.get("all_drawings")
if points:
form = st.form(f"labels_{name}")
labels = []
for i, p in enumerate(points):
labels.append(form.text_input(
f"{extra_hint[lang]} {i+1}",
""
)
)
sub = form.form_submit_button(submit[lang])
if sub:
st.session_state[f"lastclicked_{name}"] = Map["last_clicked"]
st.session_state[f"lastmarker_{name}"] = \
Map["last_active_drawing"]["geometry"]["coordinates"]
points = Map.get("all_drawings")
for point, label in zip(points, labels):
coordinates_p = point["geometry"]["coordinates"]
st.session_state[f"points_{name}"][str(coordinates_p)] = label
return st.session_state[f"points_{name}"]
Usage example:
map_hint = {
'eng': 'Search in the map',
'ita': 'Cerca nella mappa',
'slo': 'Iskanje na zemljevidu'
}
extra_hint1 = {
'eng': 'Name or reason for favorite place',
'ita': 'Nome o motivo del posto preferito',
'slo': 'Ime ali razlog za najljubši kraj'
}
submit = {
'eng': 'Submit (click twice)',
'ita': 'Invia (clicca due volte)',
'slo': 'Pošlji (dvakrat kliknite)'
}
map1 = geo_map(
'map1',
search_hint=map_hint,
extra_hint=extra_hint1,
submit=submit,
lang='eng'
)