Spaces:
Sleeping
Sleeping
Commit ·
a73fc0d
1
Parent(s): a88db08
Add Application to hg
Browse files- .gitattributes +6 -0
- README.md +145 -9
- app.py +385 -0
- data/GreenDataResize.csv +3 -0
- data/GreenVTC_Zone_Freq.csv +3 -0
- data/YellowDataResize.csv +3 -0
- data/YellowVTC_Zone_Freq.csv +3 -0
- data/grouped_by_minute.csv +3 -0
- data/vtc_zone_freq.geojson +3 -0
- images/final_image_dropoff_yellow.png +0 -0
- images/final_image_pickup_green.png +0 -0
- images/final_image_pickup_yellow.png +0 -0
- requirements.txt +7 -0
- src/first.png +0 -0
- src/images.png +0 -0
- src/last.png +0 -0
- src/second.png +0 -0
- src/third.png +0 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
data/GreenDataResize.csv filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
data/GreenVTC_Zone_Freq.csv filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
data/grouped_by_minute.csv filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
data/vtc_zone_freq.geojson filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
data/YellowDataResize.csv filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
data/YellowVTC_Zone_Freq.csv filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,12 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Taxi Data Visualization
|
| 3 |
+
|
| 4 |
+
🚖 **Taxi Data Visualization** is an interactive Streamlit application designed for exploring and analyzing taxi pickup and dropoff data, along with temporal and spatial trends of taxi rides in New York City. This tool provides powerful insights into differences between Green and Yellow taxis, as well as ride-hailing services (VTCs), by leveraging various advanced visualization techniques.
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 📝 Features
|
| 9 |
+
|
| 10 |
+
1. **Pickup and Dropoff Zones Analysis with Datashader**:
|
| 11 |
+
- High-density pickup and dropoff zones are emphasized using pixel intensity on interactive maps. These maps are dynamic, allowing zooming, panning, and resetting to default views using the "home" icon.
|
| 12 |
+
- **Why Datashader?**
|
| 13 |
+
- Datashader efficiently visualizes millions or even billions of data points by aggregating data based on screen resolution. It ensures high performance using NumPy and Dask, making it ideal for large datasets without overloading graphical resources.
|
| 14 |
+
|
| 15 |
+

|
| 16 |
+
|
| 17 |
+
2. **Global Taxi Map**:
|
| 18 |
+
- A comprehensive map showcasing all pickup and dropoff data for both Green and Yellow taxis.
|
| 19 |
+
- Highlights service areas for each type of taxi, allowing users to explore and interact with the map legends to filter specific data.
|
| 20 |
+
|
| 21 |
+

|
| 22 |
+
|
| 23 |
+
3. **Ride-Hailing (VTC) Pickup Zone Analysis**:
|
| 24 |
+
- A vibrant visualization displaying activity levels across VTC zones.
|
| 25 |
+
- Saturated colors represent high activity, while pale colors indicate lower activity.
|
| 26 |
+
- Provides insights into VTC market share compared to traditional taxi services.
|
| 27 |
+
|
| 28 |
+

|
| 29 |
+
|
| 30 |
+
4. **Taxi Activity Trends by Hour and Day**:
|
| 31 |
+
- A line chart summarizing average pickups for each day of the week in 2015.
|
| 32 |
+
- Reveals distinct patterns:
|
| 33 |
+
- **Weekdays**: Activity peaks during commute hours (morning and evening).
|
| 34 |
+
- **Weekends**: Spread throughout the day, with significant nighttime activity (except for Sunday night, which tapers off).
|
| 35 |
+
|
| 36 |
+

|
| 37 |
+
|
| 38 |
+
5. **Image Layer Adjustment**:
|
| 39 |
+
- Users can blend and adjust map layer opacity for a deeper exploration of spatial trends.
|
| 40 |
+
|
| 41 |
+

|
| 42 |
+
|
| 43 |
+
---
|
| 44 |
+
|
| 45 |
+
## 📂 Project Structure
|
| 46 |
+
|
| 47 |
+
```bash
|
| 48 |
+
├── app.py # Main application script
|
| 49 |
+
├── data/ # Data folder containing CSV and GeoJSON files
|
| 50 |
+
│ ├── GreenDataResize.csv
|
| 51 |
+
│ ├── YellowDataResize.csv
|
| 52 |
+
│ ├── vtc_zone_freq.geojson
|
| 53 |
+
│ ├── YellowVTC_Zone_Freq.csv
|
| 54 |
+
│ ├── GreenVTC_Zone_Freq.csv
|
| 55 |
+
│ ├── grouped_by_minute.csv
|
| 56 |
+
├── images/ # Processed images folder
|
| 57 |
+
│ ├── final_image_dropoff_yellow.png
|
| 58 |
+
│ ├── final_image_pickup_yellow.png
|
| 59 |
+
│ ├── final_image_pickup_green.png
|
| 60 |
+
├── .gitignore # Ignored files for Git
|
| 61 |
+
├── README.md # Project README file
|
| 62 |
+
├── requirements.txt # Python dependencies
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
## 🚀 Deployment
|
| 68 |
+
|
| 69 |
+
This project is deployed on **Render**. You can access the live application using the following link:
|
| 70 |
+
**[Taxi Data Visualization on Render](https://cabflownyc.onrender.com/)**
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## 🌟 Local Installation
|
| 75 |
+
|
| 76 |
+
1. Clone this repository:
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
git clone https://github.com/ilyesdjerfaf/CabFlowNYC.git
|
| 80 |
+
cd CabFlowNYC
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
2. Install required Python dependencies:
|
| 84 |
+
|
| 85 |
+
```bash
|
| 86 |
+
pip install -r requirements.txt
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
3. Run the application:
|
| 90 |
+
|
| 91 |
+
```bash
|
| 92 |
+
streamlit run app.py
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
## 📊 Data Sources
|
| 98 |
+
|
| 99 |
+
- **Taxi Data**: Processed CSV files for Green and Yellow taxis, including pickup and dropoff details.
|
| 100 |
+
- **Spatial Data**: GeoJSON file for taxi zones and their frequencies.
|
| 101 |
+
- **Images**: High-resolution images illustrating NYC taxi trends.
|
| 102 |
+
|
| 103 |
---
|
| 104 |
+
|
| 105 |
+
## 🌟 Usage
|
| 106 |
+
|
| 107 |
+
- **Interactive Datashader Maps**:
|
| 108 |
+
- Analyze high-density pickup and dropoff zones interactively.
|
| 109 |
+
- Zoom and filter dynamically for detailed exploration.
|
| 110 |
+
- **Sidebar Tools**:
|
| 111 |
+
- Blend and adjust map layers to visualize spatial overlaps and patterns.
|
| 112 |
+
- **Temporal Trends**:
|
| 113 |
+
- Explore activity trends by hour and weekday for insightful temporal analysis.
|
| 114 |
+
|
| 115 |
---
|
| 116 |
|
| 117 |
+
## 🛠 Requirements
|
| 118 |
+
|
| 119 |
+
- Python 3.8+
|
| 120 |
+
- Streamlit
|
| 121 |
+
- Plotly
|
| 122 |
+
- Pandas
|
| 123 |
+
- Datashader
|
| 124 |
+
- PIL (Pillow)
|
| 125 |
+
- colorcet
|
| 126 |
+
|
| 127 |
+
---
|
| 128 |
+
|
| 129 |
+
## 📜 License
|
| 130 |
+
|
| 131 |
+
This project is not licensed yet.
|
| 132 |
+
|
| 133 |
+
---
|
| 134 |
+
|
| 135 |
+
## 🏗 Future Enhancements
|
| 136 |
+
|
| 137 |
+
- Real-time data integration for live updates.
|
| 138 |
+
- Extend the application to analyze taxi trends in other cities.
|
| 139 |
+
- Introduce advanced time-series models for better temporal forecasting.
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
## 📬 Contact
|
| 144 |
+
|
| 145 |
+
For any inquiries or suggestions, please contact:
|
| 146 |
+
|
| 147 |
+
- **Ilyes DJERFAF**: [ilyes.djerfaf@etu-upsaclay.fr]
|
| 148 |
+
- **Armand BIDAULD**: [armand.bidauld@etu-upsaclay.fr]
|
app.py
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
###############################################
|
| 2 |
+
# Importer les bibliothèques
|
| 3 |
+
###############################################
|
| 4 |
+
import streamlit as st
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import datashader as ds
|
| 7 |
+
import datashader.transfer_functions as tf
|
| 8 |
+
import plotly.graph_objects as go
|
| 9 |
+
from colorcet import fire
|
| 10 |
+
from PIL import Image
|
| 11 |
+
import plotly.express as px
|
| 12 |
+
import json
|
| 13 |
+
|
| 14 |
+
###############################################
|
| 15 |
+
# Step 2 : Configurer la mise en page Streamlit
|
| 16 |
+
###############################################
|
| 17 |
+
st.set_page_config(layout="wide", page_title="Taxi Data Visualization", page_icon="🚖")
|
| 18 |
+
left_column, right_column = st.columns([7, 3])
|
| 19 |
+
|
| 20 |
+
###############################################
|
| 21 |
+
# Step 3 : Colonne gauche --> Carte principale
|
| 22 |
+
###############################################
|
| 23 |
+
|
| 24 |
+
with left_column:
|
| 25 |
+
st.header("Taxi Data Visualization")
|
| 26 |
+
|
| 27 |
+
# Load datasets
|
| 28 |
+
gtaxi = pd.read_csv('data/GreenDataResize.csv', low_memory=False)
|
| 29 |
+
ytaxi = pd.read_csv('data/YellowDataResize.csv', low_memory=False)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# ======== Combined Visualization: Pickup and Dropoff Locations ========
|
| 33 |
+
st.subheader("Comparison of Green and Yellow Taxi")
|
| 34 |
+
|
| 35 |
+
# First Row: Pickup Locations
|
| 36 |
+
st.markdown("#### Pickup Locations")
|
| 37 |
+
pickup_col1, pickup_col2 = st.columns(2) # Create two columns for pickups
|
| 38 |
+
|
| 39 |
+
# Green Taxi Pickup Visualization
|
| 40 |
+
with pickup_col1:
|
| 41 |
+
st.write("**Green Taxi Pickup Locations**")
|
| 42 |
+
# Prepare data
|
| 43 |
+
df = gtaxi.rename(columns={'Pickup_latitude': 'Lat', 'Pickup_longitude': 'Lon'})
|
| 44 |
+
df['Lat'] = pd.to_numeric(df['Lat'], errors='coerce')
|
| 45 |
+
df['Lon'] = pd.to_numeric(df['Lon'], errors='coerce')
|
| 46 |
+
dff = df.query('Lat < 40.92').query('Lat > 40.60').query('Lon > -74.15').query('Lon < -73.75')
|
| 47 |
+
|
| 48 |
+
# Datashader grid
|
| 49 |
+
cvs = ds.Canvas(plot_width=1500, plot_height=1500)
|
| 50 |
+
agg = cvs.points(dff, x='Lon', y='Lat')
|
| 51 |
+
|
| 52 |
+
# Get image and coordinates
|
| 53 |
+
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
|
| 54 |
+
coordinates = [
|
| 55 |
+
[coords_lon[0], coords_lat[0]],
|
| 56 |
+
[coords_lon[-1], coords_lat[0]],
|
| 57 |
+
[coords_lon[-1], coords_lat[-1]],
|
| 58 |
+
[coords_lon[0], coords_lat[-1]]
|
| 59 |
+
]
|
| 60 |
+
img = tf.shade(agg, cmap=fire)[::-1].to_pil()
|
| 61 |
+
|
| 62 |
+
# Plotly map
|
| 63 |
+
fig = px.scatter_mapbox(dff[:1], lat='Lat', lon='Lon', zoom=10)
|
| 64 |
+
fig.update_layout(
|
| 65 |
+
mapbox_style="carto-darkmatter",
|
| 66 |
+
mapbox_center={"lat": 40.78, "lon": -73.95},
|
| 67 |
+
mapbox_layers=[
|
| 68 |
+
{
|
| 69 |
+
"sourcetype": "image",
|
| 70 |
+
"source": img,
|
| 71 |
+
"coordinates": coordinates,
|
| 72 |
+
}
|
| 73 |
+
],
|
| 74 |
+
width=400,
|
| 75 |
+
height=550
|
| 76 |
+
)
|
| 77 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 78 |
+
|
| 79 |
+
# Yellow Taxi Pickup Visualization
|
| 80 |
+
with pickup_col2:
|
| 81 |
+
st.write("**Yellow Taxi Pickup Locations**")
|
| 82 |
+
# Prepare data
|
| 83 |
+
df = ytaxi.rename(columns={'pickup_latitude': 'Lat', 'pickup_longitude': 'Lon'})
|
| 84 |
+
df['Lat'] = pd.to_numeric(df['Lat'], errors='coerce')
|
| 85 |
+
df['Lon'] = pd.to_numeric(df['Lon'], errors='coerce')
|
| 86 |
+
dff = df.query('Lat < 40.92').query('Lat > 40.60').query('Lon > -74.15').query('Lon < -73.75')
|
| 87 |
+
|
| 88 |
+
# Datashader grid
|
| 89 |
+
cvs = ds.Canvas(plot_width=1500, plot_height=1500)
|
| 90 |
+
agg = cvs.points(dff, x='Lon', y='Lat')
|
| 91 |
+
|
| 92 |
+
# Get image and coordinates
|
| 93 |
+
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
|
| 94 |
+
coordinates = [
|
| 95 |
+
[coords_lon[0], coords_lat[0]],
|
| 96 |
+
[coords_lon[-1], coords_lat[0]],
|
| 97 |
+
[coords_lon[-1], coords_lat[-1]],
|
| 98 |
+
[coords_lon[0], coords_lat[-1]]
|
| 99 |
+
]
|
| 100 |
+
img = tf.shade(agg, cmap=fire)[::-1].to_pil()
|
| 101 |
+
|
| 102 |
+
# Plotly map
|
| 103 |
+
fig = px.scatter_mapbox(dff[:1], lat='Lat', lon='Lon', zoom=10)
|
| 104 |
+
fig.update_layout(
|
| 105 |
+
mapbox_style="carto-darkmatter",
|
| 106 |
+
mapbox_center={"lat": 40.78, "lon": -73.95},
|
| 107 |
+
mapbox_layers=[
|
| 108 |
+
{
|
| 109 |
+
"sourcetype": "image",
|
| 110 |
+
"source": img,
|
| 111 |
+
"coordinates": coordinates,
|
| 112 |
+
}
|
| 113 |
+
],
|
| 114 |
+
width=400,
|
| 115 |
+
height=550
|
| 116 |
+
)
|
| 117 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 118 |
+
|
| 119 |
+
# Second Row: Dropoff Locations
|
| 120 |
+
st.markdown("#### Dropoff Locations")
|
| 121 |
+
dropoff_col1, dropoff_col2 = st.columns(2) # Create two columns for dropoffs
|
| 122 |
+
|
| 123 |
+
# Green Taxi Dropoff Visualization
|
| 124 |
+
with dropoff_col1:
|
| 125 |
+
st.write("**Green Taxi Dropoff Locations**")
|
| 126 |
+
# Prepare data
|
| 127 |
+
df = gtaxi.rename(columns={'Dropoff_latitude': 'Lat', 'Dropoff_longitude': 'Lon'})
|
| 128 |
+
df['Lat'] = pd.to_numeric(df['Lat'], errors='coerce')
|
| 129 |
+
df['Lon'] = pd.to_numeric(df['Lon'], errors='coerce')
|
| 130 |
+
dff = df.query('Lat < 40.92').query('Lat > 40.60').query('Lon > -74.15').query('Lon < -73.75')
|
| 131 |
+
|
| 132 |
+
# Datashader grid
|
| 133 |
+
cvs = ds.Canvas(plot_width=1500, plot_height=1500)
|
| 134 |
+
agg = cvs.points(dff, x='Lon', y='Lat')
|
| 135 |
+
|
| 136 |
+
# Get image and coordinates
|
| 137 |
+
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
|
| 138 |
+
coordinates = [
|
| 139 |
+
[coords_lon[0], coords_lat[0]],
|
| 140 |
+
[coords_lon[-1], coords_lat[0]],
|
| 141 |
+
[coords_lon[-1], coords_lat[-1]],
|
| 142 |
+
[coords_lon[0], coords_lat[-1]]
|
| 143 |
+
]
|
| 144 |
+
img = tf.shade(agg, cmap=fire)[::-1].to_pil()
|
| 145 |
+
|
| 146 |
+
# Plotly map
|
| 147 |
+
fig = px.scatter_mapbox(dff[:1], lat='Lat', lon='Lon', zoom=10)
|
| 148 |
+
fig.update_layout(
|
| 149 |
+
mapbox_style="carto-darkmatter",
|
| 150 |
+
mapbox_center={"lat": 40.78, "lon": -73.95},
|
| 151 |
+
mapbox_layers=[
|
| 152 |
+
{
|
| 153 |
+
"sourcetype": "image",
|
| 154 |
+
"source": img,
|
| 155 |
+
"coordinates": coordinates,
|
| 156 |
+
}
|
| 157 |
+
],
|
| 158 |
+
width=400,
|
| 159 |
+
height=550
|
| 160 |
+
)
|
| 161 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 162 |
+
|
| 163 |
+
# Yellow Taxi Dropoff Visualization
|
| 164 |
+
with dropoff_col2:
|
| 165 |
+
st.write("**Yellow Taxi Dropoff Locations**")
|
| 166 |
+
# Prepare data
|
| 167 |
+
df = ytaxi.rename(columns={'dropoff_latitude': 'Lat', 'dropoff_longitude': 'Lon'})
|
| 168 |
+
df['Lat'] = pd.to_numeric(df['Lat'], errors='coerce')
|
| 169 |
+
df['Lon'] = pd.to_numeric(df['Lon'], errors='coerce')
|
| 170 |
+
dff = df.query('Lat < 40.92').query('Lat > 40.60').query('Lon > -74.15').query('Lon < -73.75')
|
| 171 |
+
|
| 172 |
+
# Datashader grid
|
| 173 |
+
cvs = ds.Canvas(plot_width=1500, plot_height=1500)
|
| 174 |
+
agg = cvs.points(dff, x='Lon', y='Lat')
|
| 175 |
+
|
| 176 |
+
# Get image and coordinates
|
| 177 |
+
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
|
| 178 |
+
coordinates = [
|
| 179 |
+
[coords_lon[0], coords_lat[0]],
|
| 180 |
+
[coords_lon[-1], coords_lat[0]],
|
| 181 |
+
[coords_lon[-1], coords_lat[-1]],
|
| 182 |
+
[coords_lon[0], coords_lat[-1]]
|
| 183 |
+
]
|
| 184 |
+
img = tf.shade(agg, cmap=fire)[::-1].to_pil()
|
| 185 |
+
|
| 186 |
+
# Plotly map
|
| 187 |
+
fig = px.scatter_mapbox(dff[:1], lat='Lat', lon='Lon', zoom=10)
|
| 188 |
+
fig.update_layout(
|
| 189 |
+
mapbox_style="carto-darkmatter",
|
| 190 |
+
mapbox_center={"lat": 40.78, "lon": -73.95},
|
| 191 |
+
mapbox_layers=[
|
| 192 |
+
{
|
| 193 |
+
"sourcetype": "image",
|
| 194 |
+
"source": img,
|
| 195 |
+
"coordinates": coordinates,
|
| 196 |
+
}
|
| 197 |
+
],
|
| 198 |
+
width=400,
|
| 199 |
+
height=550
|
| 200 |
+
)
|
| 201 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
# ======== DIV 2: Scatter Mapbox of Pickups and Dropoffs ========
|
| 206 |
+
st.subheader("Taxi Pickups and Dropoffs Overview")
|
| 207 |
+
|
| 208 |
+
# Sampling data for visualization
|
| 209 |
+
ytaxi_Viz_1 = ytaxi.sample(frac=0.01, random_state=42)
|
| 210 |
+
gtaxi_Viz_1 = gtaxi.sample(frac=0.01, random_state=42)
|
| 211 |
+
|
| 212 |
+
# Create the plot
|
| 213 |
+
fig = go.Figure()
|
| 214 |
+
|
| 215 |
+
fig.add_trace(go.Scattermapbox(
|
| 216 |
+
lat=ytaxi_Viz_1['pickup_latitude'],
|
| 217 |
+
lon=ytaxi_Viz_1['pickup_longitude'],
|
| 218 |
+
mode='markers',
|
| 219 |
+
marker=dict(size=5, color='yellow', opacity=0.4),
|
| 220 |
+
name='Yellow Taxi Pickups'
|
| 221 |
+
))
|
| 222 |
+
|
| 223 |
+
fig.add_trace(go.Scattermapbox(
|
| 224 |
+
lat=ytaxi_Viz_1['dropoff_latitude'],
|
| 225 |
+
lon=ytaxi_Viz_1['dropoff_longitude'],
|
| 226 |
+
mode='markers',
|
| 227 |
+
marker=dict(size=5, color='orange', opacity=0.4),
|
| 228 |
+
name='Yellow Taxi Dropoffs'
|
| 229 |
+
))
|
| 230 |
+
|
| 231 |
+
fig.add_trace(go.Scattermapbox(
|
| 232 |
+
lat=gtaxi_Viz_1['Pickup_latitude'],
|
| 233 |
+
lon=gtaxi_Viz_1['Pickup_longitude'],
|
| 234 |
+
mode='markers',
|
| 235 |
+
marker=dict(size=5, color='lightgreen', opacity=0.4),
|
| 236 |
+
name='Green Taxi Pickups'
|
| 237 |
+
))
|
| 238 |
+
|
| 239 |
+
fig.add_trace(go.Scattermapbox(
|
| 240 |
+
lat=gtaxi_Viz_1['Dropoff_latitude'],
|
| 241 |
+
lon=gtaxi_Viz_1['Dropoff_longitude'],
|
| 242 |
+
mode='markers',
|
| 243 |
+
marker=dict(size=5, color='green', opacity=0.4),
|
| 244 |
+
name='Green Taxi Dropoffs'
|
| 245 |
+
))
|
| 246 |
+
|
| 247 |
+
fig.update_layout(
|
| 248 |
+
mapbox=dict(
|
| 249 |
+
style="carto-darkmatter",
|
| 250 |
+
zoom=10,
|
| 251 |
+
center=dict(lat=40.730610, lon=-73.935242)
|
| 252 |
+
),
|
| 253 |
+
width=1300,
|
| 254 |
+
height=600,
|
| 255 |
+
margin={"r": 0, "t": 0, "l": 0, "b": 0},
|
| 256 |
+
legend=dict(title="Taxi Type")
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 260 |
+
|
| 261 |
+
# ======== DIV 3: Choropleth Visualization ========
|
| 262 |
+
st.subheader("VTC Taxi Zone Frequency by Type")
|
| 263 |
+
|
| 264 |
+
with open('data/vtc_zone_freq.geojson') as f:
|
| 265 |
+
geojson = json.load(f)
|
| 266 |
+
|
| 267 |
+
# Diviser les données par type de taxi
|
| 268 |
+
yellow_taxi = pd.read_csv('data/YellowVTC_Zone_Freq.csv')
|
| 269 |
+
green_taxi = pd.read_csv('data/GreenVTC_Zone_Freq.csv')
|
| 270 |
+
|
| 271 |
+
# Create the plot
|
| 272 |
+
fig = go.Figure()
|
| 273 |
+
|
| 274 |
+
fig.add_trace(go.Choroplethmapbox(
|
| 275 |
+
geojson=geojson,
|
| 276 |
+
featureidkey="properties.zone",
|
| 277 |
+
locations=yellow_taxi['zone'],
|
| 278 |
+
z=yellow_taxi['frequency'],
|
| 279 |
+
colorscale="YlOrRd",
|
| 280 |
+
colorbar_title="Frequency (Yellow Taxis)",
|
| 281 |
+
marker_opacity=0.7,
|
| 282 |
+
name="Yellow Taxis"
|
| 283 |
+
))
|
| 284 |
+
|
| 285 |
+
fig.add_trace(go.Choroplethmapbox(
|
| 286 |
+
geojson=geojson,
|
| 287 |
+
featureidkey="properties.zone",
|
| 288 |
+
locations=green_taxi['zone'],
|
| 289 |
+
z=green_taxi['frequency'],
|
| 290 |
+
colorscale="Greens",
|
| 291 |
+
colorbar_title="Frequency (Green Taxis)",
|
| 292 |
+
marker_opacity=0.7,
|
| 293 |
+
name="Green Taxis"
|
| 294 |
+
))
|
| 295 |
+
|
| 296 |
+
fig.update_layout(
|
| 297 |
+
mapbox=dict(
|
| 298 |
+
style="carto-positron",
|
| 299 |
+
center={"lat": 40.730610, "lon": -73.935242},
|
| 300 |
+
zoom=9
|
| 301 |
+
),
|
| 302 |
+
margin={"r": 0, "t": 0, "l": 0, "b": 0}
|
| 303 |
+
)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
# ======== DIV 4: Analyse temporelle ========
|
| 311 |
+
st.subheader("Average Temporal Evolution of the Number of Taxi Rides per Hour for Each Day of the Week")
|
| 312 |
+
|
| 313 |
+
# Charger les données
|
| 314 |
+
grouped_by_minute = pd.read_csv('data/grouped_by_minute.csv')
|
| 315 |
+
|
| 316 |
+
fig = px.line(
|
| 317 |
+
grouped_by_minute,
|
| 318 |
+
x="minute", # Utiliser la colonne sans date
|
| 319 |
+
y="frequency",
|
| 320 |
+
color="Journalier", # Couleur par jour de la semaine
|
| 321 |
+
title="Number of Rides per Minute and per Day of the Week",
|
| 322 |
+
labels={
|
| 323 |
+
"Minute": "Heure de la journée",
|
| 324 |
+
"Frequency": "Fréquence",
|
| 325 |
+
"Jour": "Jour de la semaine"
|
| 326 |
+
},
|
| 327 |
+
height=800,
|
| 328 |
+
width=1300
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
fig.update_layout(
|
| 333 |
+
xaxis=dict(
|
| 334 |
+
tickmode='linear', # Mode de ticks linéaire
|
| 335 |
+
dtick=120, # Un tick toutes les 15 minutes (900 secondes)
|
| 336 |
+
title_text="Heure de la journée", # Titre clair pour l'axe X
|
| 337 |
+
tickangle=45 # Incliner les labels pour éviter le chevauchement
|
| 338 |
+
),
|
| 339 |
+
yaxis=dict(
|
| 340 |
+
title_text="Nombre de Courses" # Titre clair pour l'axe Y
|
| 341 |
+
),
|
| 342 |
+
legend_title="Jour de la semaine"
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
###############################################
|
| 352 |
+
# Step 4 : Colonne Slider --> Images Analysis
|
| 353 |
+
###############################################
|
| 354 |
+
with st.sidebar:
|
| 355 |
+
st.title("Analysis of the 3 Base Images")
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
# Charger les images (vérifiez les chemins)
|
| 359 |
+
dropoff_yellow_img = Image.open("images/final_image_dropoff_yellow.png").convert("RGBA")
|
| 360 |
+
pickup_yellow_img = Image.open("images/final_image_pickup_yellow.png").convert("RGBA")
|
| 361 |
+
pickup_green_img = Image.open("images/final_image_pickup_green.png").convert("RGBA")
|
| 362 |
+
|
| 363 |
+
# Sliders pour ajuster les opacités
|
| 364 |
+
st.subheader("Adjust Image Layers")
|
| 365 |
+
dropoff_yellow_opacity = st.slider("Dropoff Yellow", 0, 100, 100) / 100
|
| 366 |
+
pickup_yellow_opacity = st.slider("Pickup Yellow", 0, 100, 0) / 100
|
| 367 |
+
pickup_green_opacity = st.slider("Pickup Green", 0, 100, 0) / 100
|
| 368 |
+
|
| 369 |
+
# Fonction pour superposer les images avec des opacités
|
| 370 |
+
def blend_images(base_image, overlay_image, opacity):
|
| 371 |
+
"""Superpose une image sur une image de base avec une opacité ajustée."""
|
| 372 |
+
overlay = overlay_image.copy()
|
| 373 |
+
overlay.putalpha(int(opacity * 255))
|
| 374 |
+
return Image.alpha_composite(base_image, overlay)
|
| 375 |
+
|
| 376 |
+
# Image de base transparente
|
| 377 |
+
base_image = Image.new("RGBA", dropoff_yellow_img.size, (255, 255, 255, 0))
|
| 378 |
+
|
| 379 |
+
# Ajouter les images en fonction des opacités
|
| 380 |
+
base_image = blend_images(base_image, dropoff_yellow_img, dropoff_yellow_opacity)
|
| 381 |
+
base_image = blend_images(base_image, pickup_yellow_img, pickup_yellow_opacity)
|
| 382 |
+
base_image = blend_images(base_image, pickup_green_img, pickup_green_opacity)
|
| 383 |
+
|
| 384 |
+
# Afficher l'image finale combinée
|
| 385 |
+
st.image(base_image, caption="Superposed Images", use_container_width=True)
|
data/GreenDataResize.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:70884c26e478bbaee48ace46aa97c95382d902dd4c37e41d1ef6229275d9be96
|
| 3 |
+
size 374949651
|
data/GreenVTC_Zone_Freq.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:87437003dac1ecb748b7237d4ac107bb2e2ea7c038ab50ba89d448ac48fa4600
|
| 3 |
+
size 7065721
|
data/YellowDataResize.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a808cae228e47b495ba0b149e34fae19c3707cbf55c4b067d5c17b71cb8741bf
|
| 3 |
+
size 331865310
|
data/YellowVTC_Zone_Freq.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:97b03aba22d1b856b23c8e8a1209aa56b213a4cce2d1bc6f7973d86b68fe216f
|
| 3 |
+
size 409479
|
data/grouped_by_minute.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9fce005ca11616878253b2baf421b8935a9a9b04eccc516e024fb194c7820478
|
| 3 |
+
size 221055
|
data/vtc_zone_freq.geojson
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:580ac8a5d2704a48117da2c179ef760937bf5a4e560eea19f14b7745d500df7e
|
| 3 |
+
size 8183178
|
images/final_image_dropoff_yellow.png
ADDED
|
images/final_image_pickup_green.png
ADDED
|
images/final_image_pickup_yellow.png
ADDED
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
dask-expr
|
| 2 |
+
streamlit
|
| 3 |
+
pandas
|
| 4 |
+
datashader
|
| 5 |
+
plotly
|
| 6 |
+
colorcet
|
| 7 |
+
pillow
|
src/first.png
ADDED
|
src/images.png
ADDED
|
src/last.png
ADDED
|
src/second.png
ADDED
|
src/third.png
ADDED
|