import streamlit as st import pandas as pd # package for database connection import folium # package for creating maps from streamlit_folium import folium_static # package for displaying maps on streamlit from geopy.geocoders import Nominatim # package for geolocation conversion import sqlite3 # package for database connection from datetime import datetime # package for timestamp from folium.features import CustomIcon # package for custom icons on map def pythonx_geomap(): # Initialize the database conn = sqlite3.connect('./files/student_locations.db') # Create a table to store student locations c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY AUTOINCREMENT, city TEXT, state TEXT, country TEXT, latitude REAL, longitude REAL, timestamp DATETIME)''') conn.commit() st.title("Lesson 4: Geographical Data Visualization") st.markdown(""" This lesson demonstrates how to handle geolocation data and visualize it using maps in Python. The main functionalities include: - **User Input for Location**: Users can input their city and state or city and country through a form. - **Geolocation Processing**: The input location is processed to obtain latitude and longitude coordinates. - **Data Storage**: The processed location data is saved to a [SQLite](https://www.geeksforgeeks.org/python-sqlite/) database. - **Map Visualization**: All stored student locations are displayed on an interactive map. - **Statistics Display**: The code also provides statistics on the total number of students, unique cities, and unique countries, along with the top 5 cities. """) # Display the source code with st.expander("See Source Code"): with open(__file__, "r", encoding="utf-8") as f: st.code(f.read(), language="python") st.subheader("Student Location Tracker") # Input form for student location with st.form("student_form"): input_city = st.text_input("Enter your City, State (e.g.: Amarillo,TX), or City, Country (Toronto, Canada):") submitted = st.form_submit_button("Submit") if submitted: # converting addresses (like "Mountain View, CA") into geographic # coordinates (like latitude 37.423021 and longitude -122.083739) lat, lon, city, state, country = get_location(input_city) # Save the location data to the database if lat and lon: save_student(conn, city, state, country, lat, lon) st.success(f"Location saved: {city}, {country}") else: st.error("Unable to find the location. Please try a different city name.") # Display all students on a map st.subheader('All Student Locations') df = get_all_students(conn) if not df.empty: m = create_map(df) folium_static(m) else: st.write("No student data available yet.") # Display student statistics st.subheader('Student Statistics') if not df.empty: st.write(f"Total students: {len(df)}") st.write(f"Total cities: {df['city'].nunique()}") st.write(f"Total countries: {df['country'].nunique()}") st.write("Top 5 cities:") st.write(df['city'].value_counts().head()) st.write("Top 5 countries:") st.write(df['country'].value_counts().head()) else: st.write("No student data available yet.") # Close the database connection conn.close() # convert address to latitude and longitude def get_location(city): geolocator = Nominatim(user_agent="student_location_app") try: location = geolocator.geocode(city, language="en") st.write(location) if location: location_str = str(location).split(",") state, country = location_str[2], location_str[-1] return location.latitude, location.longitude, location.raw.get('name'), state, country else: return None, None, None, None, None except Exception as e: st.write(e) return None, None, None, None, None # save student location to database def save_student(conn, city, state, country, lat, lon): c = conn.cursor() timestamp = datetime.now() c.execute("INSERT INTO students (city, state, country, latitude, longitude, timestamp) VALUES (?, ?, ?, ?, ?, ?)", (city, state, country, lat, lon, timestamp)) conn.commit() # get all student locations from database def get_all_students(conn): df = pd.read_sql_query("SELECT * from students", conn) return df # create map with student locations def create_map(df): # Create a map centered at the US m = folium.Map(location=[41.2706, -97.1749], zoom_start=4) # Group by city and count occurrences city_counts = df.groupby(['city', 'state', 'latitude', 'longitude', 'country']).size().reset_index(name='count') # Normalize marker sizes max_count = city_counts['count'].max() min_size, max_size = 5, 20 # min and max marker sizes # Add markers for each city for _, row in city_counts.iterrows(): # Create a custom icon icon = CustomIcon( icon_image='./images/BuffaloMarker.png', # Replace with the path to your icon file icon_size=(30, 30), # Adjust the size as needed icon_anchor=(15, 30), # Adjust anchor point if needed popup_anchor=(0, -30) # Adjust popup anchor if needed ) # Calculate marker size based on count folium.Marker( location=[row['latitude'], row['longitude']], popup=f"{row['city']}
{row['count']}", tooltip=f"{row['city']}, {row['country']}", icon=icon ).add_to(m) return m