-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHomepage.py
More file actions
212 lines (176 loc) · 5.98 KB
/
Homepage.py
File metadata and controls
212 lines (176 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import matplotlib.pyplot as plt
import pandas as pd
import requests
import streamlit as st
from tests.eia_part3 import (
build_df_from_eia_data,
filter_since,
latest_value,
sum_by_week,
)
from validation import eia_schema
st.set_page_config(page_title="Weekly U.S. Petroleum Supply", layout="wide")
st.title("The Correlation between Weekly U.S. Petroleum Product Supplied and WTI Crude Oil Price")
st.subheader("Team Members: Irina, Indra")
st.caption("Source: U.S. Energy Information Administration (EIA)")
# =========================
# Project Proposal
# =========================
with st.expander("Project Proposal", expanded=False):
st.subheader("Project Overview")
st.write(
"""
This project analyzes weekly U.S. petroleum product supplied data and
WTI crude oil spot price data using the EIA API. Our goal is to explore
how petroleum supply and crude oil prices evolve over time and whether
they exhibit similar patterns during major economic or energy market events.
"""
)
st.subheader("Datasets")
st.markdown(
"""
- **Weekly U.S. Petroleum Product Supplied**
https://www.eia.gov/opendata/browser/petroleum/cons/wpsup
- **Weekly WTI Crude Oil Spot Price (RWTC)**
https://www.eia.gov/opendata/browser/petroleum/pri/spt
"""
)
st.subheader("Research Questions")
st.markdown(
"""
1. How has U.S. petroleum product supplied changed since 2012?
2. How has WTI crude oil price changed over the same period?
3. Do petroleum supply and crude oil prices show similar patterns over time?
4. Are there noticeable disruptions during major events such as the COVID-19 period?
"""
)
st.subheader("Link to the notebook")
st.markdown(
"[Project Notebook](https://github.com/advanced-computing/giggling-wombat/blob/main/project.ipynb)"
)
st.subheader("Target Visualization")
st.markdown(
"""
- Weekly time-series line chart of U.S. petroleum product supplied
- Weekly time-series line chart of WTI crude oil price
- Visual comparison of trends between the two series
"""
)
st.subheader("Known Unknowns and Challenges")
st.markdown(
"""
- Petroleum product supplied is a proxy for demand rather than a direct measure
- Weekly data can be noisy and may obscure long-term trends
- Oil prices and supply may react to different economic forces
- The project depends on API data retrieval instead of downloadable CSV files
"""
)
st.divider()
API_KEY = st.secrets.get("EIA_API_KEY", None)
if not API_KEY:
st.error("Missing EIA API key. Set it in Streamlit Secrets as EIA_API_KEY.")
st.stop()
# --- API endpoint (supply) ---
SUPPLY_URL = (
"https://api.eia.gov/v2/petroleum/cons/wpsup/data/"
f"?api_key={API_KEY}"
"&frequency=weekly"
"&data[0]=value"
"&sort[0][column]=period"
"&sort[0][direction]=desc"
"&offset=0&length=5000"
)
@st.cache_data(ttl=60 * 60) # cache 1 hour
def fetch_supply_json(url: str) -> dict:
r = requests.get(url, timeout=30)
r.raise_for_status()
return r.json()
try:
payload = fetch_supply_json(SUPPLY_URL)
except Exception as e:
st.error(f"Failed to fetch supply data: {e}")
st.stop()
# IMPORTANT: build_df_from_eia_data expects list[dict], not the whole payload
data = payload.get("response", {}).get("data", [])
df = build_df_from_eia_data(
data=data,
period_col="period",
value_col="value",
new_date_col="week",
)
if df.empty:
st.error("EIA returned no usable data for supply (empty after parsing).")
st.stop()
# Filter to 2012–present first
df = filter_since(df, date_col="week", start_date="2012-01-01")
df = eia_schema.validate(df)
if df.empty:
st.error("No data after filtering to 2012–present. Check parsing or EIA response.")
st.stop()
# Aggregate weekly (safe even if already weekly)
weekly_total = sum_by_week(df, date_col="week", value_col="value")
# Rename for readability
weekly_total = weekly_total.rename(columns={"value": "total_product_supplied"})
# =========================
# Interactive Week Filter
# =========================
st.subheader("Filter by Week")
min_week = weekly_total["week"].min().date()
max_week = weekly_total["week"].max().date()
col1, col2 = st.columns(2)
with col1:
start_week = st.date_input(
"Start week",
value=min_week,
min_value=min_week,
max_value=max_week,
)
with col2:
end_week = st.date_input(
"End week",
value=max_week,
min_value=min_week,
max_value=max_week,
)
if start_week > end_week:
st.error("Start week must be earlier than or equal to end week.")
st.stop()
filtered_total = weekly_total[
(weekly_total["week"] >= pd.to_datetime(start_week))
& (weekly_total["week"] <= pd.to_datetime(end_week))
].copy()
if filtered_total.empty:
st.warning("No data available for the selected date range.")
st.stop()
# Latest value
try:
latest_total = latest_value(
filtered_total,
date_col="week",
value_col="total_product_supplied",
)
except Exception:
latest_total = None
# Metrics
c1, c2 = st.columns(2)
c1.metric("Weeks in selected range", f"{filtered_total.shape[0]:,}")
c2.metric(
"Latest total (sum of products)",
f"{latest_total:,.0f}" if latest_total is not None else "—",
)
st.divider()
st.subheader("Total Product Supplied (Weekly, All Products Summed)")
fig, ax = plt.subplots()
ax.plot(filtered_total["week"], filtered_total["total_product_supplied"])
ax.set_xlabel("Week")
ax.set_ylabel("Total Product Supplied (sum of EIA 'value')")
st.pyplot(fig)
with st.expander("Show data table"):
st.dataframe(
filtered_total.sort_values("week", ascending=False),
use_container_width=True,
)
st.caption(
"Note: 'Product supplied' is often used as a proxy for consumption. "
"This visualization is descriptive (not causal)."
)