Getting your interactive taxi data dashboard up and running quickly
- Docker installed on your local machine
- An Altinity.Cloud® account (free trial available at altinity.cloud)
If you don't have one already, you can sign up for a free trial account. See the Altinity docs site for the details.
- Log into Altinity Cloud Manager (ACM).
- Go to the Clusters view and click the LAUNCH CLUSTER button at the top of the page. (Complete instructions are on the Creating a New Cluster page.)
- Give your new cluster a name and click the LAUNCH button.
- Wait for your cluster to provision (~5 minutes).
- In the ACM, go to your cluster, click the EXPLORE button, then go to the Query tab.
- Copy and paste these commands to create the new database, a table in that database, then load that table with data:
-- Create database
CREATE DATABASE IF NOT EXISTS maddie ON CLUSTER '{cluster}'; -- Create table
CREATE TABLE maddie.taxi_local ON CLUSTER '{cluster}'
(
`VendorID` Nullable(Int32),
`tpep_pickup_datetime` Nullable(DateTime64(6)),
`tpep_dropoff_datetime` Nullable(DateTime64(6)),
`passenger_count` Nullable(Int64),
`trip_distance` Nullable(Float64),
`RatecodeID` Nullable(Int64),
`store_and_fwd_flag` Nullable(String),
`PULocationID` Nullable(Int32),
`DOLocationID` Nullable(Int32),
`payment_type` Nullable(Int64),
`fare_amount` Nullable(Float64),
`extra` Nullable(Float64),
`mta_tax` Nullable(Float64),
`tip_amount` Nullable(Float64),
`tolls_amount` Nullable(Float64),
`improvement_surcharge` Nullable(Float64),
`total_amount` Nullable(Float64),
`congestion_surcharge` Nullable(Float64),
`Airport_fee` Nullable(Float64),
`cbd_congestion_fee` Nullable(Float64)
)
ENGINE = ReplicatedMergeTree('/clickhouse/{cluster}/tables/{database}/{table}', '{replica}')
ORDER BY tuple()
SETTINGS index_granularity = 8192;
-- Create the table for the boroughs and zone names
CREATE TABLE maddie.taxi_zones ON CLUSTER '{cluster}'
(
`LocationID` Int32,
`Borough` String,
`Zone` String,
`service_zone` String
)
ENGINE = ReplicatedMergeTree('/clickhouse/{cluster}/tables/{database}/{table}', '{replica}')
ORDER BY LocationID
SETTINGS index_granularity = 8192;- Import the data
Run these statements to load the tables:
-- Load August-October 2025 data from Parquet files
INSERT INTO maddie.taxi_local
SELECT * FROM url('https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2025-{08,09,10}.parquet',
'Parquet'
);
-- Load mapping from location IDs to borough names into the new table
INSERT INTO maddie.taxi_zones
SELECT * FROM url(
'https://d37ci6vzurychx.cloudfront.net/misc/taxi_zone_lookup.csv',
'CSVWithNames'
);- Verify that the data loaded:
SELECT count() FROM maddie.taxi_local;The table should have roughly 12.25 million rows.
SELECT count() FROM maddie.taxi_zones;As of this writing, the table has 265 rows.
- In the ACM, go to your cluster and go to the API Endpoints tab.
- Click the IMPORT button at the top.
- Click the UPLOAD JSON FILE button at the top and upload the
api-endpoints.jsonfile from this package. - Wait ~30 seconds for the cluster configuration to update.
- Verify that the endpoints are defined (you should see three:
/rush-hour,/tips,/routes).
-
Get your cluster connection details:
- In the ACM, go to your cluster and click the Connection Details link.
- Copy the HTTPS endpoint URL (it'll be something like
https://username:password@your-cluster.altinity.cloud:8443). - Note your username and password (if your username is
admin, you really should create a new user with limited privileges for security purposes).
-
Edit
vite.config.jsin the project root:- Find the line
target: 'https://mycluster.myenv.altinity.cloud:8443'
and replace the value with your cluster URL withoutuserid:password. We'll define those values in an.envfile next.
- Find the line
-
Create an
.envfile from the example file:
# Copy the example file
cp .env.example .env - Edit
.envand add your credentials:
VITE_CLICKHOUSE_USERNAME=your_username_here
VITE_CLICKHOUSE_PASSWORD=your_password_here NOTE: The included .gitignore file includes .env, so you don't have to worry about commiting it accidentally.
To run the project in Docker:
# Start the dashboard
docker compose up -dOr if you prefer local Node.js:
npm install
npm run devOpen your browser to: http://localhost:5173
You should see:
- Rush Hour Analysis with cyan theme and pie chart
- Tip Distribution with gold theme and bar chart
- Hottest Routes with green theme and ranked list
Work with the controls on the page and watch the data update in real-time! Every change to the UI causes the app to call an API Endpoint in your ClickHouse cluster.
- Check browser console for errors
- Verify API endpoints are created (takes ~30 seconds after creation)
- Test endpoints with curl:
curl 'https://USERNAME:PASSWORD@your-cluster:8443/rush-hour?start_time=16&end_time=20'
You can try the brute force approach and just kill the process:
lsof -i :5173
kill -9 <PID>Or use a different port. For example, if you want to use port 3000, you can change docker-compose.yml:
ports:
- "3000:5173"If you're running this with local Node.js, you can specify the port on the command line:
npm run dev -- --port 3000- Check Network tab in DevTools - you should see new requests
- Verify parameter names match between SQL and JavaScript
- Edit the API endpoint SQL in ACM
- Modify
src/taxi-dashboard.jsxto change visualizations - Add more endpoints for additional insights!
- Load additional months of taxi data
- Try other NYC TLC datasets (green taxis, FHV, etc.)
- Add time series charts
- Create geographic visualizations
- Build drill-down views
Your package should include:
├── .env.example - Sample credentials file
├── .gitignore - Don't commit .env, ./node_modules and other files
├── AGENTS.md - Outlines the AI-guided development process
├── api-endpoints.json - API endpoint definitions
├── docker-compose.yml - Docker setup
├── images - Various graphics:
│ ├── clock.png
│ ├── dollar_sign.png
│ ├── hottest_routes.png
│ ├── map_pin.png
│ ├── rush_hour_analysis.png
│ └── tip_destination_by_distance.png
├── index.html - HTML template
├── package.json - Dependencies
├── README.md - Detailed documentation
├── SETUP.md - This file
├── src
│ ├── App.jsx - App wrapper
│ ├── main.jsx - Entry point
│ └── taxi-dashboard.jsx - Main React component
└── vite.config.js - Dev server config with proxy