I built a pipeline that processes traffic points to identify congestion zones in NYC. This project is an end-to-end Data Engineering pipeline designed to analyze real-time traffic congestion in New York City. It demonstrates Geospatial Data Engineering skills by ingesting live traffic speed data, performing spatial joins (PostGIS) to map coordinates to city boroughs, and automating the workflow.
Key Features:
- ELT Architecture: Extract, Load, and Transform pattern.
- Geospatial Analysis: Uses PostGIS to handle coordinate systems(
ST_GeomFromGeoJSON,ST_SetSRID,ST_MakePoint,ST_Multi) and spatial joins (ST_Contains). - Infrastructure as Code: Fully containerized using Docker.
- Orchestration: Automated scheduling using Dagster.
- Extract: Python script hits the NYC Open Data API (Socrata).
- Load: Raw JSON is saved to a Data Lake (MinIO/S3) for durability.
- Staging: Data is loaded into PostgreSQL (PostGIS enabled).
- Transform: dbt (data build tool) performs data cleaning and spatial aggregation.
- Visualize: Final analytics are ready for tools like Kepler.gl or Superset.
- Language: Python 3.9+
- Containerization: Docker & Docker Compose
- Orchestration: Dagster
- Database: PostgreSQL + PostGIS Extension
- Transformation: dbt Core
- Storage: MinIO (S3 Compatible)
- Docker Desktop installed and running.
- Create and Add .env file with Postgres Database credentials and MinIO Configurations used in docker-compose.yml
-
Clone the repository:
git clone https://github.com/pranavkapale/Smart-City-Traffic-Optimizer cd Smart-City-Traffic-Optimizer -
Start the infrastructure:
docker-compose up --build
This downloads the images for Postgres, MinIO, and Dagster and starts them.
-
Access the Dashboard:
- Open your browser to
http://localhost:3000. - Click "Materialize All" to trigger the pipeline manually.
- Open your browser to
-
Verify Data:
- MinIO (Data Lake): Go to
http://localhost:9001(User:minio_admin, Pass:minio_password). You should see theraw-databucket. - Database: Connect via DBeaver/pgAdmin using:
- Host:
localhost - Port:
5432 - User:
POSTGRES_USERmentioned in .env file - Password:
POSTGRES_PASSWORDmentioned in .env file - Database:
POSTGRES_DBmentioned in .env file
- Host:
- MinIO (Data Lake): Go to
Once the pipeline finishes, you can run this SQL in your database tool to see the results:
SELECT * FROM traffic_by_borough ORDER BY active_sensors DESC;- Although technically we can delete init.py in modern Python Projects(Python 3.3+) and the project will still work as a "Namespace Package."
- However, in our case Dagster and Python look for init.py to confirm that the folder is a legitimate module they can import from.
- Also, Sometimes Docker mounts volumes can cause Python to fail to find sub-modules if the init.py is missing. Keeping it acts as a "marker" that says "This folder is a Python package."
-
⏻ Shut Down the Running Services: This stops and removes containers, networks, and volumes created by up
docker-compose down
-
✔️ List down Volumes: Docker "remembers" the older volumes even if you stop the container. So if you change Configurations from .env file in between builds this will help you to identify and delete older volumes.
docker volume ls
-
🧹 Remove Single Volume: To Remove Single Volume
docker volume rm <Enter-Volume-which-needs-to-be-deleted>
-
🧹 Remove Images: To delete the images that were built
docker-compose down --rmi all
-
🗑️ Remove Volumes: Removes volumes declared in your docker-compose.yml
docker-compose down -v
-
🔄 Full Cleanup: Remove containers, networks, images, and volumes all at once
docker-compose down --rmi all -v
-
🧾 Extra Cleanup (if needed): Remove everything Docker has created (be careful — this wipes all containers, images, volumes, and networks on your system)
docker system prune -a --volumes
💡 Tip: Use docker-compose down for normal cleanup, and only add --rmi all -v or docker system prune when you want a completely fresh slate.