Skip to content

Commit d34c2d6

Browse files
authored
Merge pull request #53 from advanced-computing/ux-layout-improvements
feat: vertical layout, navy sidebar, soft blue theme, clearer gridlines
2 parents 8a51f9c + 5b0f09f commit d34c2d6

4 files changed

Lines changed: 297 additions & 165 deletions

File tree

.streamlit/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[theme]
2+
primaryColor = "#1B4F8A"
3+
backgroundColor = "#F0F4F9"
4+
secondaryBackgroundColor = "#E4EBF4"
5+
textColor = "#1A1A1A"
6+
font = "serif"

Homepage.py

Lines changed: 100 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,57 @@
1313
st.set_page_config(page_title="Weekly U.S. Petroleum Supply", layout="wide")
1414

1515
# =========================
16-
# Sidebar title
16+
# Sidebar title (above nav via CSS)
1717
# =========================
18-
st.sidebar.markdown(
18+
st.markdown(
1919
"""
20-
<h1 style="font-size: 1.5rem; line-height: 1.2; margin-bottom: 0.2rem;">
21-
U.S. Petroleum & WTI Weekly Monitor
22-
</h1>
20+
<style>
21+
[data-testid="stSidebar"] {
22+
background-color: #0D2B5E !important;
23+
}
24+
[data-testid="stSidebar"] * {
25+
color: white !important;
26+
}
27+
[data-testid="stSidebar"] input {
28+
color: #1A1A1A !important;
29+
}
30+
[data-testid="stSidebar"] .stDateInput input {
31+
color: #1A1A1A !important;
32+
background-color: #E4EBF4 !important;
33+
}
34+
[data-testid="stSidebarNav"] a {
35+
color: rgba(255,255,255,0.8) !important;
36+
}
37+
[data-testid="stSidebarNav"] a:hover {
38+
color: white !important;
39+
background-color: rgba(255,255,255,0.1) !important;
40+
}
41+
[data-testid="stSidebarNav"] {
42+
padding-top: 3.5rem;
43+
}
44+
[data-testid="stSidebarNav"]::before {
45+
content: "U.S. Petroleum & WTI Weekly Monitor";
46+
display: block;
47+
position: absolute;
48+
top: 0;
49+
left: 0;
50+
right: 0;
51+
padding: 1rem 1.2rem 0.2rem 1.2rem;
52+
font-size: 1.05rem;
53+
font-weight: 600;
54+
line-height: 1.3;
55+
color: white !important;
56+
}
57+
</style>
2358
""",
2459
unsafe_allow_html=True,
2560
)
26-
st.sidebar.caption("Source: EIA")
27-
st.sidebar.divider()
2861

2962
# =========================
3063
# Main page header
3164
# =========================
3265
st.title("Weekly U.S. Petroleum Supply")
33-
st.subheader("Team Members: Irina, Indra")
34-
st.caption("Source: U.S. Energy Information Administration (EIA)")
66+
st.caption("Team Members: Irina, Indra · Source: U.S. Energy Information Administration (EIA)")
3567

3668
# =========================
3769
# Project Proposal
@@ -332,63 +364,71 @@ def compute_product_price_sensitivity(
332364
st.divider()
333365

334366
# =========================
335-
# Two side-by-side charts
367+
# Stacked charts
336368
# =========================
337-
left_col, right_col = st.columns(TWO_COLUMN_LAYOUT)
369+
st.subheader("Total Product Supplied")
338370

339-
with left_col:
340-
st.subheader("Total Product Supplied")
371+
fig = px.line(
372+
filtered_total,
373+
x="week",
374+
y="total_supply",
375+
labels={"week": "Week", "total_supply": "Total Product Supplied"},
376+
)
377+
fig.update_layout(
378+
hovermode="x unified",
379+
xaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
380+
yaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
381+
plot_bgcolor="rgba(0,0,0,0)",
382+
paper_bgcolor="rgba(0,0,0,0)",
383+
)
384+
fig.update_traces(hovertemplate="<b>%{x|%b %d, %Y}</b><br>Total Supply: %{y:,.0f}<extra></extra>")
385+
st.plotly_chart(fig, use_container_width=True)
341386

342-
fig = px.line(
343-
filtered_total,
387+
with st.expander("Show total supply data table"):
388+
total_display = filtered_total.sort_values("week", ascending=False).copy()
389+
total_display["week"] = total_display["week"].dt.strftime("%Y-%m-%d")
390+
st.dataframe(total_display, width="stretch")
391+
392+
st.divider()
393+
394+
st.subheader("Product-Level Weekly Supply")
395+
396+
if not selected_products:
397+
st.warning("Please select at least one product from the sidebar.")
398+
else:
399+
product_plot_df = filtered_product[
400+
filtered_product["product_name"].isin(selected_products)
401+
].copy()
402+
403+
fig2 = px.line(
404+
product_plot_df,
344405
x="week",
345-
y="total_supply",
346-
labels={"week": "Week", "total_supply": "Total Product Supplied"},
406+
y="product_supplied",
407+
color="product_name",
408+
labels={
409+
"week": "Week",
410+
"product_supplied": "Product Supplied",
411+
"product_name": "Product",
412+
},
347413
)
348-
fig.update_layout(hovermode="x unified")
349-
fig.update_traces(
350-
hovertemplate="<b>%{x|%b %d, %Y}</b><br>Total Supply: %{y:,.0f}<extra></extra>"
414+
fig2.update_layout(
415+
hovermode="x unified",
416+
xaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
417+
yaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
418+
plot_bgcolor="rgba(0,0,0,0)",
419+
paper_bgcolor="rgba(0,0,0,0)",
351420
)
352-
st.plotly_chart(fig, use_container_width=True)
353-
354-
with st.expander("Show total supply data table"):
355-
total_display = filtered_total.sort_values("week", ascending=False).copy()
356-
total_display["week"] = total_display["week"].dt.strftime("%Y-%m-%d")
357-
st.dataframe(total_display, width="stretch")
358-
359-
with right_col:
360-
st.subheader("Product-Level Weekly Supply")
361-
362-
if not selected_products:
363-
st.warning("Please select at least one product from the sidebar.")
364-
else:
365-
product_plot_df = filtered_product[
366-
filtered_product["product_name"].isin(selected_products)
367-
].copy()
368-
369-
fig2 = px.line(
370-
product_plot_df,
371-
x="week",
372-
y="product_supplied",
373-
color="product_name",
374-
labels={
375-
"week": "Week",
376-
"product_supplied": "Product Supplied",
377-
"product_name": "Product",
378-
},
379-
)
380-
fig2.update_layout(hovermode="x unified")
381-
fig2.update_traces(
382-
hovertemplate="<b>%{fullData.name}</b><br>%{x|%b %d, %Y}: %{y:,.0f}<extra></extra>"
383-
)
384-
st.plotly_chart(fig2, use_container_width=True)
385-
386-
with st.expander("Show product-level data table"):
387-
product_display = product_plot_df.sort_values(
388-
["product_name", "week"], ascending=[True, False]
389-
).copy()
390-
product_display["week"] = product_display["week"].dt.strftime("%Y-%m-%d")
391-
st.dataframe(product_display, width="stretch")
421+
fig2.update_traces(
422+
hovertemplate="<b>%{fullData.name}</b><br>%{x|%b %d, %Y}: %{y:,.0f}<extra></extra>"
423+
)
424+
st.plotly_chart(fig2, use_container_width=True)
425+
426+
with st.expander("Show product-level data table"):
427+
product_display = product_plot_df.sort_values(
428+
["product_name", "week"], ascending=[True, False]
429+
).copy()
430+
product_display["week"] = product_display["week"].dt.strftime("%Y-%m-%d")
431+
st.dataframe(product_display, width="stretch")
392432

393433
st.divider()
394434

pages/2_WTI_Price.py

Lines changed: 96 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,51 @@
1414
st.set_page_config(page_title="WTI Price", layout="wide")
1515

1616
# =========================
17-
# Sidebar title
17+
# Sidebar title (above nav via CSS)
1818
# =========================
19-
st.sidebar.markdown(
19+
st.markdown(
2020
"""
21-
<h1 style="font-size: 1.5rem; line-height: 1.2; margin-bottom: 0.2rem;">
22-
U.S. Petroleum & WTI Weekly Monitor
23-
</h1>
21+
<style>
22+
[data-testid="stSidebar"] {
23+
background-color: #0D2B5E !important;
24+
}
25+
[data-testid="stSidebar"] * {
26+
color: white !important;
27+
}
28+
[data-testid="stSidebar"] input {
29+
color: #1A1A1A !important;
30+
}
31+
[data-testid="stSidebar"] .stDateInput input {
32+
color: #1A1A1A !important;
33+
background-color: #E4EBF4 !important;
34+
}
35+
[data-testid="stSidebarNav"] a {
36+
color: rgba(255,255,255,0.8) !important;
37+
}
38+
[data-testid="stSidebarNav"] a:hover {
39+
color: white !important;
40+
background-color: rgba(255,255,255,0.1) !important;
41+
}
42+
[data-testid="stSidebarNav"] {
43+
padding-top: 3.5rem;
44+
}
45+
[data-testid="stSidebarNav"]::before {
46+
content: "U.S. Petroleum & WTI Weekly Monitor";
47+
display: block;
48+
position: absolute;
49+
top: 0;
50+
left: 0;
51+
right: 0;
52+
padding: 1rem 1.2rem 0.2rem 1.2rem;
53+
font-size: 1.05rem;
54+
font-weight: 600;
55+
line-height: 1.3;
56+
color: white !important;
57+
}
58+
</style>
2459
""",
2560
unsafe_allow_html=True,
2661
)
27-
st.sidebar.caption("Source: EIA")
28-
st.sidebar.divider()
2962

3063
# =========================
3164
# Main page header
@@ -256,60 +289,66 @@ def find_top_highest_years(yearly_avg: pd.DataFrame, top_n: int) -> set[int]:
256289
st.divider()
257290

258291
# =========================
259-
# Two charts side by side
292+
# Stacked charts
260293
# =========================
261-
left_col, right_col = st.columns(TWO_COLUMN_LAYOUT)
262-
263-
with left_col:
264-
st.subheader("WTI Price Over Time (Weekly)")
265-
266-
fig = go.Figure()
267-
fig.add_trace(
268-
go.Scatter(
269-
x=filtered_wti["week"],
270-
y=filtered_wti["wti_price"],
271-
name="WTI Price",
272-
mode="lines",
273-
hovertemplate="WTI Price: $%{y:.2f}<extra></extra>",
274-
)
275-
)
276-
fig.add_trace(
277-
go.Scatter(
278-
x=filtered_wti["week"],
279-
y=filtered_wti["wti_ma"],
280-
name=f"{ma_window}-Week Moving Average",
281-
mode="lines",
282-
hovertemplate=f"{ma_window}-Week Avg: $%{{y:.2f}}<extra></extra>",
283-
)
284-
)
285-
fig.update_layout(
286-
xaxis_title="Week",
287-
yaxis_title="WTI Price ($/barrel)",
288-
hovermode="x unified",
289-
hoverlabel=dict(namelength=-1),
294+
st.subheader("WTI Price Over Time (Weekly)")
295+
296+
fig = go.Figure()
297+
fig.add_trace(
298+
go.Scatter(
299+
x=filtered_wti["week"],
300+
y=filtered_wti["wti_price"],
301+
name="WTI Price",
302+
mode="lines",
303+
hovertemplate="WTI Price: $%{y:.2f}<extra></extra>",
290304
)
291-
st.plotly_chart(fig, use_container_width=True)
292-
293-
with right_col:
294-
st.subheader("Weekly Change in WTI Price")
295-
296-
fig2 = go.Figure()
297-
fig2.add_trace(
298-
go.Scatter(
299-
x=filtered_wti["week"],
300-
y=filtered_wti["weekly_change"],
301-
mode="lines",
302-
name="Weekly Change",
303-
hovertemplate="<b>%{x|%b %d, %Y}</b><br>Change: $%{y:.2f}<extra></extra>",
304-
)
305+
)
306+
fig.add_trace(
307+
go.Scatter(
308+
x=filtered_wti["week"],
309+
y=filtered_wti["wti_ma"],
310+
name=f"{ma_window}-Week Moving Average",
311+
mode="lines",
312+
hovertemplate=f"{ma_window}-Week Avg: $%{{y:.2f}}<extra></extra>",
305313
)
306-
fig2.add_hline(y=0, line_color="gray", line_width=1)
307-
fig2.update_layout(
308-
xaxis_title="Week",
309-
yaxis_title="Weekly Change ($/barrel)",
310-
hovermode="x unified",
314+
)
315+
fig.update_layout(
316+
xaxis_title="Week",
317+
yaxis_title="WTI Price ($/barrel)",
318+
hovermode="x unified",
319+
hoverlabel=dict(namelength=-1),
320+
xaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
321+
yaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
322+
plot_bgcolor="rgba(0,0,0,0)",
323+
paper_bgcolor="rgba(0,0,0,0)",
324+
)
325+
st.plotly_chart(fig, use_container_width=True)
326+
327+
st.divider()
328+
329+
st.subheader("Weekly Change in WTI Price")
330+
331+
fig2 = go.Figure()
332+
fig2.add_trace(
333+
go.Scatter(
334+
x=filtered_wti["week"],
335+
y=filtered_wti["weekly_change"],
336+
mode="lines",
337+
name="Weekly Change",
338+
hovertemplate="<b>%{x|%b %d, %Y}</b><br>Change: $%{y:.2f}<extra></extra>",
311339
)
312-
st.plotly_chart(fig2, use_container_width=True)
340+
)
341+
fig2.add_hline(y=0, line_color="#0D2B5E", line_width=1.5)
342+
fig2.update_layout(
343+
xaxis_title="Week",
344+
yaxis_title="Weekly Change ($/barrel)",
345+
hovermode="x unified",
346+
xaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
347+
yaxis=dict(gridcolor="rgba(13,43,94,0.2)", linecolor="#0D2B5E"),
348+
plot_bgcolor="rgba(0,0,0,0)",
349+
paper_bgcolor="rgba(0,0,0,0)",
350+
)
351+
st.plotly_chart(fig2, use_container_width=True)
313352

314353
st.divider()
315354
st.subheader("Real-Time Interpretation")

0 commit comments

Comments
 (0)