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 pydeck as pdk
import plotly.express as px
from datetime import datetime, time
import random
# Set page config
st.set_page_config(page_title="NYC Interactive Map", layout="wide")
# Load data
@st.cache_data
def load_data():
# Generate food truck locations
np.random.seed(42)
# NYC bounds
lat_min, lat_max = 40.4774, 40.9176
lon_min, lon_max = -74.2591, -73.7004
# Food trucks
food_trucks = pd.DataFrame({
'lat': np.random.uniform(lat_min, lat_max, 100),
'lon': np.random.uniform(lon_min, lon_max, 100),
'name': [f'Food Truck {i+1}' for i in range(100)],
'cuisine': np.random.choice(['Mexican', 'Italian', 'Asian', 'American', 'Mediterranean'], 100),
'rating': np.random.uniform(3.0, 5.0, 100),
'hour': np.random.randint(6, 22, 100)
})
# Pedestrian activity heatmap
pedestrian_data = pd.DataFrame({
'lat': np.random.uniform(lat_min, lat_max, 500),
'lon': np.random.uniform(lon_min, lon_max, 500),
'activity': np.random.exponential(50, 500),
'hour': np.random.randint(0, 24, 500)
})
# Taxi clusters
taxi_data = pd.DataFrame({
'lat': np.random.uniform(lat_min, lat_max, 200),
'lon': np.random.uniform(lon_min, lon_max, 200),
'pickup_count': np.random.poisson(15, 200),
'hour': np.random.randint(0, 24, 200)
})
# Animated routes
route_data = []
for i in range(10):
start_lat = np.random.uniform(lat_min, lat_max)
start_lon = np.random.uniform(lon_min, lon_max)
end_lat = np.random.uniform(lat_min, lat_max)
end_lon = np.random.uniform(lon_min, lon_max)
# Create route points
steps = 20
for step in range(steps):
progress = step / (steps - 1)
route_data.append({
'route_id': i,
'lat': start_lat + (end_lat - start_lat) * progress,
'lon': start_lon + (end_lon - start_lon) * progress,
'step': step,
'hour': np.random.randint(0, 24)
})
routes_df = pd.DataFrame(route_data)
return food_trucks, pedestrian_data, taxi_data, routes_df
# Load all data
food_trucks, pedestrian_data, taxi_data, routes_df = load_data()
# Sidebar controls
st.sidebar.title("Map Controls")
# Time slider
st.sidebar.subheader("Time Filter")
hour_range = st.sidebar.slider("Hour of Day", 0, 23, (8, 18), step=1)
# Borough filters (simplified - using coordinate ranges)
st.sidebar.subheader("Area Filter")
borough_filter = st.sidebar.selectbox(
"Focus Area",
["All NYC", "Manhattan", "Brooklyn", "Queens", "Bronx", "Staten Island"]
)
# Layer toggles
st.sidebar.subheader("Map Layers")
show_food_trucks = st.sidebar.checkbox("Food Trucks", True)
show_pedestrian_heatmap = st.sidebar.checkbox("Pedestrian Heatmap", True)
show_taxi_clusters = st.sidebar.checkbox("Taxi Clusters", False)
show_routes = st.sidebar.checkbox("Animated Routes", False)
# Color schemes
st.sidebar.subheader("Styling")
color_scheme = st.sidebar.selectbox(
"Color Scheme",
["Default", "Viridis", "Plasma", "Inferno"]
)
map_style = st.sidebar.radio(
"Map Style",
["mapbox://styles/mapbox/streets-v11", "mapbox://styles/mapbox/satellite-v9"]
)
# Heatmap settings
st.sidebar.subheader("Heatmap Settings")
heatmap_radius = st.sidebar.slider("Heatmap Radius", 100, 1000, 500)
heatmap_intensity = st.sidebar.slider("Heatmap Intensity", 0.1, 2.0, 1.0)
# Cluster settings
st.sidebar.subheader("Cluster Settings")
cluster_radius = st.sidebar.slider("Cluster Radius", 50, 500, 200)
# Filter data based on time
filtered_food_trucks = food_trucks[
(food_trucks['hour'] >= hour_range[0]) &
(food_trucks['hour'] <= hour_range[1])
]
filtered_pedestrian = pedestrian_data[
(pedestrian_data['hour'] >= hour_range[0]) &
(pedestrian_data['hour'] <= hour_range[1])
]
filtered_taxi = taxi_data[
(taxi_data['hour'] >= hour_range[0]) &
(taxi_data['hour'] <= hour_range[1])
]
filtered_routes = routes_df[
(routes_df['hour'] >= hour_range[0]) &
(routes_df['hour'] <= hour_range[1])
]
# Define color mapping
color_maps = {
"Default": [255, 140, 0],
"Viridis": [68, 1, 84],
"Plasma": [240, 249, 33],
"Inferno": [252, 255, 164]
}
# Create layers
layers = []
if show_food_trucks and not filtered_food_trucks.empty:
layers.append(
pdk.Layer(
"ScatterplotLayer",
data=filtered_food_trucks,
get_position=["lon", "lat"],
get_color=color_maps[color_scheme] + [160],
get_radius=50,
pickable=True,
)
)
if show_pedestrian_heatmap and not filtered_pedestrian.empty:
layers.append(
pdk.Layer(
"HeatmapLayer",
data=filtered_pedestrian,
get_position=["lon", "lat"],
get_weight="activity",
radius_pixels=heatmap_radius,
intensity=heatmap_intensity,
)
)
if show_taxi_clusters and not filtered_taxi.empty:
layers.append(
pdk.Layer(
"HexagonLayer",
data=filtered_taxi,
get_position=["lon", "lat"],
get_elevation_weight="pickup_count",
radius=cluster_radius,
elevation_scale=4,
elevation_range=[0, 1000],
pickable=True,
extruded=True,
)
)
if show_routes and not filtered_routes.empty:
layers.append(
pdk.Layer(
"PathLayer",
data=filtered_routes.groupby('route_id').apply(
lambda x: pd.Series({
'path': [[row['lon'], row['lat']] for _, row in x.iterrows()]
})
).reset_index(),
get_path="path",
get_width=5,
get_color=[255, 0, 0, 200],
width_min_pixels=2,
)
)
# Main content
st.title("NYC Interactive Map Visualization")
# Create two columns for map and stats
col1, col2 = st.columns([3, 1])
with col1:
# Create the map
view_state = pdk.ViewState(
latitude=40.7831,
longitude=-73.9712,
zoom=11,
pitch=45,
bearing=0
)
if layers:
r = pdk.Deck(
layers=layers,
initial_view_state=view_state,
map_style=map_style,
tooltip={
"html": "<b>Name:</b> {name}<br/>"
"<b>Cuisine:</b> {cuisine}<br/>"
"<b>Rating:</b> {rating:.1f}<br/>"
"<b>Activity:</b> {activity}<br/>"
"<b>Pickups:</b> {pickup_count}",
"style": {"backgroundColor": "steelblue", "color": "white"}
}
)
st.pydeck_chart(r)
else:
st.info("Please select at least one layer to display the map.")
with col2:
st.subheader("Data Summary")
# Stats panel
if show_food_trucks:
st.metric(
"Food Trucks Active",
len(filtered_food_trucks),
delta=len(filtered_food_trucks) - len(food_trucks) // 2
)
if not filtered_food_trucks.empty:
avg_rating = filtered_food_trucks['rating'].mean()
st.metric("Average Rating", f"{avg_rating:.1f}⭐")
# Cuisine distribution
cuisine_counts = filtered_food_trucks['cuisine'].value_counts()
st.write("**Cuisine Types:**")
for cuisine, count in cuisine_counts.items():
st.write(f"• {cuisine}: {count}")
if show_pedestrian_heatmap:
st.metric(
"Pedestrian Activity Points",
len(filtered_pedestrian)
)
if not filtered_pedestrian.empty:
avg_activity = filtered_pedestrian['activity'].mean()
st.metric("Average Activity", f"{avg_activity:.0f}")
if show_taxi_clusters:
st.metric(
"Taxi Pickup Locations",
len(filtered_taxi)
)
if not filtered_taxi.empty:
total_pickups = filtered_taxi['pickup_count'].sum()
st.metric("Total Pickups", total_pickups)
if show_routes:
unique_routes = filtered_routes['route_id'].nunique()
st.metric("Active Routes", unique_routes)
# Time distribution chart
if show_food_trucks and not filtered_food_trucks.empty:
st.subheader("Food Truck Activity by Hour")
hourly_counts = food_trucks['hour'].value_counts().sort_index()
st.bar_chart(hourly_counts)
# Additional information
st.subheader("Map Information")
st.write(f"**Current Time Range:** {hour_range[0]}:00 - {hour_range[1]}:00")
st.write(f"**Map Style:** {map_style.split('/')[-1].replace('-', ' ').title()}")
st.write(f"**Color Scheme:** {color_scheme}")
if show_pedestrian_heatmap:
st.write(f"**Heatmap Radius:** {heatmap_radius}px")
st.write(f"**Heatmap Intensity:** {heatmap_intensity}")
if show_taxi_clusters:
st.write(f"**Cluster Radius:** {cluster_radius}m")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?