Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions AI_ASSIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,43 @@ Document one place you used an LLM during this assignment.
Example: "My Streamlit KPI panel kept re-querying Postgres on every
sidebar interaction even though I wrapped run_query in @st.cache_data." -->

TODO
While building the Streamlit dashboard, my "Trips by Hour of Day" chart was not displaying correctly. I wanted to check whether my SQL query and the data format passed to st.line_chart() were correct.

## The prompt

<!-- TODO: paste the exact prompt you sent to the LLM. -->

TODO
I have this Streamlit code for a line chart. The query runs successfully, but I want to make sure the data is in the correct format for st.line_chart(). Is there anything I should change?

st.subheader("Trips by Hour of Day")

hour_query = f"""
SELECT
EXTRACT(HOUR FROM pickup_datetime) AS pickup_hour,
COUNT(*) AS trip_count
FROM {DB_SCHEMA}.fct_trips
{payment_filter}
GROUP BY pickup_hour
ORDER BY pickup_hour;
"""

hour_df = run_query(hour_query)

st.line_chart(hour_df)

## The response

<!-- TODO: summarise or paste what the LLM returned. -->

TODO
The LLM explained that st.line_chart() works best when the x-axis is used as the DataFrame index. It suggested converting pickup_hour to an integer and setting it as the index before creating the chart.

## Reflection

<!-- TODO: what did you change, keep, or discard after reviewing the LLM's answer?
Be specific: "I kept the cache_data suggestion but changed ttl from 60 to 300
to match the mart's once-a-day refresh cadence." -->

TODO
I kept the suggestion to convert pickup_hour to an integer and used it as the DataFrame index before calling st.line_chart(). After making these changes, the chart displayed correctly and the hours appeared in the correct order.

---

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ Fill in `week11-streamlit/metric_definitions.md`: a five-field definition (name,
3) Paste your 5-minute presentation recording link (keep it PRIVATE). -->

- Metabase dashboard (in the **Week 11 Submissions** collection): TODO
- Screenshots / PDF export: TODO
https://metabase-hyf.politepebble-abd3ebc2.westeurope.azurecontainerapps.io/dashboard/42-nyc-taxi-analytics-baraah
- Screenshots / PDF export: TODO Metabase_dashboard_baraah.png
- Presentation recording (private, hosted in the Azure `student-submissions` container): TODO

https://hyfstoragedev.blob.core.windows.net/student-submissions/week-11/Baraah.mp4?sp=r&st=2026-07-16T15:33:03Z&se=2026-07-22T23:48:03Z&skoid=8bfd6dc9-8735-4bc5-8362-05ebddd6526b&sktid=07a14c4e-d88c-42f7-83b3-13af7e57ff3d&skt=2026-07-16T15:33:03Z&ske=2026-07-22T23:48:03Z&sks=b&skv=2026-02-06&spr=https&sv=2026-02-06&sr=b&sig=GRcWIO6iheJqLzk0s8zeJNoQLaZaSRw%2FGOD9scBdsYQ%3D

> ⚠️ **Keep the recording private.** It shows your screen and voice. Never make it public and never commit the `.mp4` (git history is forever). Check the frame for passwords, `.env` contents, or connection strings before uploading.

Host the recording in Azure: upload the `.mp4` to the shared `student-submissions` blob container (teachers get read access, nothing is public) and put the read-only link in your PR. The container is shared, so name your file after yourself: `week-11/<your-name>.mp4` (e.g. `week-11/jane-doe.mp4`). See "Host the recording on Azure Blob Storage" in the Week 11 Assignment chapter for the `az` CLI and Portal steps.
Expand Down
Binary file added week11-streamlit/Metabase_dashboard_baraah.png

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something went wrong with your last graph, both axis have the same label and there is a linear line (probably plotting pickup hour vs pickup hour)

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added week11-streamlit/Streamlit_dashboard_baraah.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 106 additions & 4 deletions week11-streamlit/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
load_dotenv() # reads .env file if present

POSTGRES_URL = os.environ["POSTGRES_URL"]
DB_SCHEMA = os.environ.get("DB_SCHEMA", "dev_yourname")
DB_SCHEMA = os.environ.get("DB_SCHEMA", "dev_baraah")

st.set_page_config(page_title="NYC Taxi Metrics", layout="wide")
st.title("NYC Taxi Metrics")
Expand All @@ -30,6 +30,27 @@ def run_query(sql: str) -> pd.DataFrame:
with engine.connect() as conn:
return pd.read_sql(sql, conn)

st.sidebar.header("Filters")

payment_query = f"""
SELECT DISTINCT payment_type_label
FROM {DB_SCHEMA}.fct_trips
ORDER BY payment_type_label;
"""

payment_df = run_query(payment_query)

payment_options = ["All"] + payment_df["payment_type_label"].tolist()

selected_payment = st.sidebar.selectbox(
"Payment Type",
payment_options
)

if selected_payment == "All":
payment_filter = ""
else:
payment_filter = f"WHERE payment_type_label = '{selected_payment}'"

st.subheader("Headline KPIs")

Expand All @@ -39,7 +60,88 @@ def run_query(sql: str) -> pd.DataFrame:
# This is deliberately not the total-trips/avg-fare/total-revenue trio
# from the chapter: trip_distance and fare_per_mile are different columns,
# so copying the chapter's SQL verbatim will not answer this.
raise NotImplementedError(
"TODO: implement the headline KPIs panel (total trips, avg trip "
"distance, avg fare per mile) from fct_trips."
# Query headline KPIs from fct_trips
kpi_query = f"""
SELECT
COUNT(*) AS total_trips,
AVG(trip_distance) AS avg_trip_distance,
AVG(fare_per_mile) AS avg_fare_per_mile
FROM {DB_SCHEMA}.fct_trips
{payment_filter};
"""

kpi_df = run_query(kpi_query)

total_trips = int(kpi_df["total_trips"].iloc[0])
avg_trip_distance = kpi_df["avg_trip_distance"].iloc[0]
avg_fare_per_mile = kpi_df["avg_fare_per_mile"].iloc[0]


col1, col2, col3 = st.columns(3)

with col1:
st.metric(
"Total Trips",
f"{total_trips:,}"
)

with col2:
st.metric(
"Average Trip Distance",
f"{avg_trip_distance:.2f} miles"
)

with col3:
st.metric(
"Average Fare per Mile",
f"${avg_fare_per_mile:.2f}"
)

st.subheader("Trips by Hour of Day")

hour_query = f"""
SELECT
EXTRACT(HOUR FROM pickup_datetime) AS pickup_hour,
COUNT(*) AS trip_count
FROM {DB_SCHEMA}.fct_trips
{payment_filter}
GROUP BY pickup_hour
ORDER BY pickup_hour;
"""

hour_df = run_query(hour_query)

hour_df["pickup_hour"] = hour_df["pickup_hour"].astype(int)

st.line_chart(
hour_df.set_index("pickup_hour")["trip_count"]
)

st.subheader("Data Freshness")

freshness_query = f"""
SELECT
COUNT(*) AS row_count,
MAX(pickup_datetime) AS latest_pickup_datetime
FROM {DB_SCHEMA}.fct_trips
{payment_filter};
"""

freshness_df = run_query(freshness_query)

row_count = int(freshness_df["row_count"].iloc[0])
latest_pickup = freshness_df["latest_pickup_datetime"].iloc[0]

col1, col2 = st.columns(2)

with col1:
st.metric(
"Rows in fct_trips",
f"{row_count:,}"
)

with col2:
st.metric(
"Latest Pickup Datetime",
str(latest_pickup)
)
68 changes: 68 additions & 0 deletions week11-streamlit/metric_definitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Metric definitions

Five fields per metric: Name, Description, Calculation, Data source, Refresh frequency. One block per panel. Copy this file to `metric_definitions.md` inside your `week11-streamlit/` folder and fill it in.

## Metabase panels

<!-- One block per Question: trip count by payment type, average fare per
mile by dropoff borough, average trip duration by hour of day. -->

### Panel 1: Trip Count by Payment Type

- **Name**: trip_count_by_payment_type
- **Description**: Total number of taxi trips grouped by payment type. This metric shows which payment methods are most commonly used by passengers.
- **Calculation**: COUNT(*) grouped by payment_type_label.
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.

### Panel 2: Average Fare per Mile by Dropoff Borough

- **Name**: avg_fare_per_mile_by_dropoff_borough
- **Description**: Average fare earned per mile for taxi trips grouped by dropoff borough. This metric compares fare efficiency across boroughs.
- **Calculation**: AVG(fare_per_mile) grouped by dropoff_borough.
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.

### Panel 3: Average Trip Duration by Hour of Day

- **Name**: avg_trip_duration_by_hour
- **Description**: Average trip duration in minutes grouped by pickup hour. This metric helps identify how trip duration changes throughout the day.
- **Calculation**: AVG(EXTRACT(EPOCH FROM (dropoff_datetime - pickup_datetime)) / 60) grouped by EXTRACT(HOUR FROM pickup_datetime).
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.

## Streamlit panels

<!-- Headline KPIs panel: total trips, average trip distance, average
fare per mile. -->

### Panel 1: Headline KPIs

- **Name**: taxi_headline_kpis
- **Description**: Displays the total trips, average trip distance, and average fare per mile.
- **Calculation**: COUNT(*), AVG(trip_distance), and AVG(fare_per_mile).
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.


### Panel 2: Trips by Hour of Day

- **Name**: trips_by_hour
- **Description**: Shows the number of taxi trips for each pickup hour.
- **Calculation**: COUNT(*) grouped by EXTRACT(HOUR FROM pickup_datetime).
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.

### Panel 3: Data Freshness

- **Name**: taxi_data_freshness
- **Description**: Shows the total number of rows and the latest pickup datetime to verify that the data is current.
- **Calculation**: COUNT(*) and MAX(pickup_datetime).
- **Data source**: dev_baraah.fct_trips (dbt mart)
- **Refresh frequency**: Rebuilt once per day.



<!-- Add more ### Panel blocks under either section if you build more (the Required tier adds
an hour-of-day trend and a freshness panel to Streamlit; a Metabase date filter is Extra,
bonus credit, not required). -->
Loading