Create an app showing an interactive NYC map visualization. Mock data: - Food truck locations (100 points) - Pedestrian activity heatmap Features: - Interactive map centered on NYC - Toggle layers: * Food trucks with popups * Pedestrian heatmap * Animated routes * Taxi clusters Controls: - Time slider - Borough filters - Color schemes - Map style (street/satellite) - Heatmap and cluster settings Include zoom/pan and stats panel showing data summaries.
To upload files, please first save the app
import streamlit as st
import pandas as pd
import numpy as np
import folium
from streamlit_folium import st_folium
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime, timedelta
import random
# Set page config
st.set_page_config(page_title="NYC Interactive Map", layout="wide")
# Generate mock data
@st.cache_data
def generate_food_truck_data():
np.random.seed(42)
random.seed(42)
# NYC bounds approximately
lat_bounds = (40.4774, 40.9176)
lon_bounds = (-74.2591, -73.7004)
# Borough centers for clustering
boroughs = {
'Manhattan': (40.7831, -73.9712),
'Brooklyn': (40.6782, -73.9442),
'Queens': (40.7282, -73.7949),
'Bronx': (40.8448, -73.8648),
'Staten Island': (40.5795, -74.1502)
}
food_trucks = []
truck_names = ['Joe\'s Pizza', 'Halal Guys', 'Taco Bell Truck', 'Ice Cream Van', 'Hot Dog Stand',
'Coffee Cart', 'Pretzel Stand', 'Burger Truck', 'Falafel Cart', 'Smoothie Stand']
for i in range(100):
borough = random.choice(list(boroughs.keys()))
center_lat, center_lon = boroughs[borough]
# Add some random offset around borough centers
lat = center_lat + np.random.normal(0, 0.02)
lon = center_lon + np.random.normal(0, 0.02)
# Ensure within NYC bounds
lat = max(lat_bounds[0], min(lat_bounds[1], lat))
lon = max(lon_bounds[0], min(lon_bounds[1], lon))
food_trucks.append({
'id': i,
'name': f"{random.choice(truck_names)} #{i+1}",
'lat': lat,
'lon': lon,
'borough': borough,
'rating': round(random.uniform(3.0, 5.0), 1),
'price_range': random.choice(['$', '$$', '$$$']),
'cuisine': random.choice(['American', 'Mexican', 'Middle Eastern', 'Italian', 'Asian', 'Mediterranean']),
'hours': f"{random.randint(6, 10)}AM - {random.randint(8, 11)}PM"
})
return pd.DataFrame(food_trucks)
@st.cache_data
def generate_pedestrian_data():
np.random.seed(123)
# Generate heatmap data points
pedestrian_data = []
# Manhattan hotspots
manhattan_hotspots = [
(40.7589, -73.9851), # Times Square
(40.7505, -73.9934), # Herald Square
(40.7484, -73.9857), # Empire State Building
(40.7614, -73.9776), # Central Park South
(40.7484, -73.9857), # Penn Station area
]
for center_lat, center_lon in manhattan_hotspots:
for _ in range(20):
lat = center_lat + np.random.normal(0, 0.003)
lon = center_lon + np.random.normal(0, 0.003)
intensity = np.random.randint(50, 200)
pedestrian_data.append({
'lat': lat,
'lon': lon,
'intensity': intensity,
'time_hour': np.random.randint(6, 23)
})
return pd.DataFrame(pedestrian_data)
@st.cache_data
def generate_taxi_data():
np.random.seed(456)
taxi_data = []
# Major taxi pickup locations
pickup_spots = [
(40.7589, -73.9851), # Times Square
(40.6892, -74.0445), # Wall Street
(40.7505, -73.9934), # Herald Square
(40.7614, -73.9776), # Central Park
(40.7648, -73.9808), # Lincoln Center
]
for i, (center_lat, center_lon) in enumerate(pickup_spots):
cluster_size = np.random.randint(15, 30)
for j in range(cluster_size):
lat = center_lat + np.random.normal(0, 0.005)
lon = center_lon + np.random.normal(0, 0.005)
taxi_data.append({
'lat': lat,
'lon': lon,
'cluster_id': i,
'fare': round(np.random.uniform(8.0, 45.0), 2),
'time_hour': np.random.randint(0, 24)
})
return pd.DataFrame(taxi_data)
@st.cache_data
def generate_route_data():
np.random.seed(789)
# Sample animated routes (simplified)
routes = []
route_paths = [
[(40.7589, -73.9851), (40.7505, -73.9934), (40.7484, -73.9857)], # Times Sq to Empire State
[(40.6892, -74.0445), (40.7505, -73.9934), (40.7614, -73.9776)], # Wall St to Central Park
]
for i, path in enumerate(route_paths):
for j, (lat, lon) in enumerate(path):
routes.append({
'route_id': i,
'lat': lat,
'lon': lon,
'sequence': j,
'timestamp': j * 5 # 5 minute intervals
})
return pd.DataFrame(routes)
# Load data
food_trucks_df = generate_food_truck_data()
pedestrian_df = generate_pedestrian_data()
taxi_df = generate_taxi_data()
routes_df = generate_route_data()
# Sidebar controls
st.sidebar.title("🗽 NYC Map Controls")
# Layer toggles
st.sidebar.subheader("Map Layers")
show_food_trucks = st.sidebar.checkbox("🚛 Food Trucks", value=True)
show_pedestrian = st.sidebar.checkbox("🚶 Pedestrian Heatmap", value=True)
show_taxi_clusters = st.sidebar.checkbox("🚕 Taxi Clusters", value=False)
show_routes = st.sidebar.checkbox("🛣️ Animated Routes", value=False)
# Time controls
st.sidebar.subheader("Time Controls")
time_hour = st.sidebar.slider("Hour of Day", 0, 23, 12)
# Borough filter
st.sidebar.subheader("Location Filters")
selected_boroughs = st.sidebar.multiselect(
"Select Boroughs",
options=food_trucks_df['borough'].unique(),
default=food_trucks_df['borough'].unique()
)
# Map style
map_style = st.sidebar.selectbox(
"Map Style",
["OpenStreetMap", "Stamen Terrain", "Stamen Toner", "CartoDB positron"]
)
# Color scheme
color_scheme = st.sidebar.selectbox(
"Color Scheme",
["Default", "Viridis", "Plasma", "Inferno"]
)
# Heatmap settings
if show_pedestrian:
st.sidebar.subheader("Heatmap Settings")
heatmap_radius = st.sidebar.slider("Heatmap Radius", 10, 50, 25)
heatmap_blur = st.sidebar.slider("Heatmap Blur", 10, 30, 15)
# Main content
st.title("🗽 NYC Interactive Map Visualization")
st.markdown("Explore food truck locations, pedestrian activity, and taxi patterns across New York City")
# Create main layout
col1, col2 = st.columns([3, 1])
with col1:
# Create base map
m = folium.Map(
location=[40.7831, -73.9712], # NYC center
zoom_start=11,
tiles=map_style if map_style != "Default" else "OpenStreetMap"
)
# Filter data based on selections
filtered_food_trucks = food_trucks_df[food_trucks_df['borough'].isin(selected_boroughs)]
filtered_pedestrian = pedestrian_df[pedestrian_df['time_hour'] == time_hour]
filtered_taxi = taxi_df[taxi_df['time_hour'] == time_hour]
# Add food truck markers
if show_food_trucks:
for _, truck in filtered_food_trucks.iterrows():
color = 'red' if color_scheme == 'Default' else 'blue'
folium.Marker(
[truck['lat'], truck['lon']],
popup=folium.Popup(f"""
<b>{truck['name']}</b><br>
Rating: {truck['rating']} ⭐<br>
Price: {truck['price_range']}<br>
Cuisine: {truck['cuisine']}<br>
Hours: {truck['hours']}
""", max_width=200),
tooltip=truck['name'],
icon=folium.Icon(color=color, icon='cutlery', prefix='fa')
).add_to(m)
# Add pedestrian heatmap
if show_pedestrian and not filtered_pedestrian.empty:
from folium.plugins import HeatMap
heat_data = [[row['lat'], row['lon'], row['intensity']] for _, row in filtered_pedestrian.iterrows()]
HeatMap(
heat_data,
radius=heatmap_radius,
blur=heatmap_blur,
gradient={0.2: 'blue', 0.4: 'lime', 0.6: 'orange', 1: 'red'}
).add_to(m)
# Add taxi clusters
if show_taxi_clusters and not filtered_taxi.empty:
from folium.plugins import MarkerCluster
taxi_cluster = MarkerCluster().add_to(m)
for _, taxi in filtered_taxi.iterrows():
folium.Marker(
[taxi['lat'], taxi['lon']],
popup=f"Fare: ${taxi['fare']}",
icon=folium.Icon(color='yellow', icon='taxi', prefix='fa')
).add_to(taxi_cluster)
# Add routes
if show_routes:
colors = ['red', 'blue', 'green', 'purple', 'orange']
for route_id in routes_df['route_id'].unique():
route_data = routes_df[routes_df['route_id'] == route_id].sort_values('sequence')
coordinates = [[row['lat'], row['lon']] for _, row in route_data.iterrows()]
folium.PolyLine(
coordinates,
color=colors[route_id % len(colors)],
weight=3,
opacity=0.8
).add_to(m)
# Display map
map_data = st_folium(m, width=700, height=500)
with col2:
st.subheader("📊 Data Summary")
# Stats panel
total_trucks = len(filtered_food_trucks)
avg_rating = filtered_food_trucks['rating'].mean() if not filtered_food_trucks.empty else 0
st.metric("Food Trucks", total_trucks)
st.metric("Avg Rating", f"{avg_rating:.1f} ⭐" if avg_rating > 0 else "N/A")
st.metric("Active Hour", f"{time_hour}:00")
if show_pedestrian:
avg_pedestrian = filtered_pedestrian['intensity'].mean() if not filtered_pedestrian.empty else 0
st.metric("Avg Pedestrian Activity", f"{avg_pedestrian:.0f}")
if show_taxi_clusters:
total_taxis = len(filtered_taxi)
avg_fare = filtered_taxi['fare'].mean() if not filtered_taxi.empty else 0
st.metric("Active Taxis", total_taxis)
st.metric("Avg Fare", f"${avg_fare:.2f}" if avg_fare > 0 else "N/A")
# Borough breakdown
st.subheader("🏙️ By Borough")
borough_counts = filtered_food_trucks['borough'].value_counts()
for borough, count in borough_counts.items():
st.write(f"**{borough}**: {count} trucks")
# Cuisine breakdown
if not filtered_food_trucks.empty:
st.subheader("🍕 Popular Cuisines")
cuisine_counts = filtered_food_trucks['cuisine'].value_counts().head(5)
for cuisine, count in cuisine_counts.items():
st.write(f"**{cuisine}**: {count}")
# Additional analytics
st.subheader("📈 Analytics Dashboard")
col3, col4 = st.columns(2)
with col3:
# Borough distribution chart
if not filtered_food_trucks.empty:
fig_borough = px.pie(
values=filtered_food_trucks['borough'].value_counts().values,
names=filtered_food_trucks['borough'].value_counts().index,
title="Food Trucks by Borough"
)
st.plotly_chart(fig_borough, use_container_width=True)
with col4:
# Ratings distribution
if not filtered_food_trucks.empty:
fig_ratings = px.histogram(
filtered_food_trucks,
x='rating',
title="Rating Distribution",
nbins=10
)
st.plotly_chart(fig_ratings, use_container_width=True)
# Data tables
with st.expander("📋 View Raw Data"):
tab1, tab2, tab3 = st.tabs(["Food Trucks", "Pedestrian Data", "Taxi Data"])
with tab1:
st.dataframe(filtered_food_trucks)
with tab2:
st.dataframe(filtered_pedestrian)
with tab3:
st.dataframe(filtered_taxi)
# Footer
st.markdown("---")
st.markdown("💡 **Tip**: Use the sidebar controls to filter data and toggle map layers. Click on markers for detailed information!")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?