|
1 | | -import streamlit as st |
2 | | -import pandas as pd |
3 | | -import plotly.express as px |
4 | | - |
5 | | -from data_utils import convert_units, parse_period_and_value, top_n_by_total |
6 | | -from eia_api import fetch_all_pages |
7 | | - |
8 | | -st.set_page_config(page_title="EIA Fuel Type Demand", layout="wide") |
9 | | -st.title("U.S. Electricity Demand by Fuel Type (Eastern Time)") |
10 | | - |
11 | | -# API Key Retrieval |
12 | | -api_key = st.secrets.get("EIA_API_KEY", None) |
13 | | - |
14 | | -# Predefine time and unit values |
15 | | -start = st.sidebar.text_input("Start date (YYYY-MM-DD)", value="2026-02-09") |
16 | | -end = st.sidebar.text_input("End date (YYYY-MM-DD)", value="2026-02-16") |
17 | | -units = st.sidebar.radio("Units", ["MWh", "GWh"], horizontal=True) |
18 | | - |
19 | | -# Adding in filters for user to choose for display |
20 | | -top_n = st.sidebar.slider("Show top N fuel types (by total)", 1, 15, 10) |
21 | | -filter_eastern = st.sidebar.checkbox("Filter to Eastern timezone only", value=True) |
22 | | - |
23 | | -BASE_URL = "https://api.eia.gov/v2/electricity/rto/daily-fuel-type-data/data/" |
24 | | - |
25 | | -@st.cache_data(show_spinner=False) |
26 | | -def load_fuel_data(api_key: str, start: str, end: str) -> pd.DataFrame: |
27 | | - params = { |
28 | | - "api_key": api_key, |
29 | | - "frequency": "daily", |
30 | | - "data[0]": "value", |
31 | | - "start": start, |
32 | | - "end": end, |
33 | | - "sort[0][column]": "period", |
34 | | - "sort[0][direction]": "asc", |
35 | | - "offset": 0, |
36 | | - "length": 5000, |
37 | | - } |
38 | | - rows = fetch_all_pages(BASE_URL, params) |
39 | | - return pd.json_normalize(rows) |
40 | | - |
41 | | -with st.spinner("Loading data..."): |
42 | | - df = load_fuel_data(api_key, start, end) |
43 | | - |
44 | | -if df.empty: |
45 | | - st.warning("No data returned. Check dates/API key.") |
46 | | - st.stop() |
47 | | - |
48 | | -df = parse_period_and_value(df) |
49 | | -df, ycol, ylabel = convert_units(df, units) |
50 | | - |
51 | | -# Aggregation by date and fuel type |
52 | | -agg = ( |
53 | | - df.groupby(["period", "type-name"], as_index=False)[ycol] |
54 | | - .sum() |
55 | | - .rename(columns={ycol: "Demand"}) |
56 | | -) # type: ignore |
57 | | - |
58 | | -# Keep top N fuel types by total |
59 | | -agg = top_n_by_total(agg, "type-name", "Demand", top_n=top_n) |
60 | | - |
61 | | -# Plot Graph |
62 | | -fig = px.line( |
63 | | - agg.sort_values("period"), |
64 | | - x="period", |
65 | | - y="Demand", |
66 | | - color="type-name", |
67 | | - title=f"Electricity demand by fuel type ({start} to {end})", |
68 | | - labels={"period": "Date", "Demand": ylabel, "type-name": "Fuel type"}, |
69 | | -) |
70 | | -st.plotly_chart(fig, use_container_width=True) |
| 1 | +import streamlit as st |
| 2 | +import pandas as pd |
| 3 | +import requests |
| 4 | +import plotly.express as px |
| 5 | + |
| 6 | +st.set_page_config(page_title="EIA Fuel Type Demand", layout="wide") |
| 7 | +st.title("U.S. Electricity Demand by Fuel Type (Eastern Time)") |
| 8 | + |
| 9 | +# API Key Retrieval |
| 10 | +api_key = st.secrets.get("EIA_API_KEY", None) |
| 11 | + |
| 12 | +# Predefine time and unit values |
| 13 | +start = st.sidebar.text_input("Start date (YYYY-MM-DD)", value="2026-02-09") |
| 14 | +end = st.sidebar.text_input("End date (YYYY-MM-DD)", value="2026-02-16") |
| 15 | +units = st.sidebar.radio("Units", ["MWh", "GWh"], horizontal=True) |
| 16 | + |
| 17 | +# Adding in filters for user to choose for display |
| 18 | +top_n = st.sidebar.slider("Show top N fuel types (by total)", 1, 15, 10) |
| 19 | +filter_eastern = st.sidebar.checkbox("Filter to Eastern timezone only", value=True) |
| 20 | + |
| 21 | +BASE_URL = "https://api.eia.gov/v2/electricity/rto/daily-fuel-type-data/data/" |
| 22 | + |
| 23 | + |
| 24 | +def fetch_all_pages(base_url: str, params: dict) -> list: |
| 25 | + all_rows = [] |
| 26 | + offset = 0 |
| 27 | + length = params.get("length", 5000) |
| 28 | + |
| 29 | + while True: |
| 30 | + params["offset"] = offset |
| 31 | + r = requests.get(base_url, params=params, timeout=60) |
| 32 | + r.raise_for_status() |
| 33 | + payload = r.json() |
| 34 | + rows = payload.get("response", {}).get("data", []) |
| 35 | + all_rows.extend(rows) |
| 36 | + if len(rows) < length: |
| 37 | + break |
| 38 | + offset += length |
| 39 | + |
| 40 | + return all_rows |
| 41 | + |
| 42 | + |
| 43 | +@st.cache_data(show_spinner=False) |
| 44 | +def load_fuel_data(api_key: str, start: str, end: str) -> pd.DataFrame: |
| 45 | + params = { |
| 46 | + "api_key": api_key, |
| 47 | + "frequency": "daily", |
| 48 | + "data[0]": "value", |
| 49 | + "start": start, |
| 50 | + "end": end, |
| 51 | + "sort[0][column]": "period", |
| 52 | + "sort[0][direction]": "asc", |
| 53 | + "offset": 0, |
| 54 | + "length": 5000, |
| 55 | + } |
| 56 | + rows = fetch_all_pages(BASE_URL, params) |
| 57 | + return pd.json_normalize(rows) |
| 58 | + |
| 59 | + |
| 60 | +with st.spinner("Loading data..."): |
| 61 | + df = load_fuel_data(api_key, start, end) |
| 62 | + |
| 63 | +if df.empty: |
| 64 | + st.warning("No data returned. Check dates/API key.") |
| 65 | + st.stop() |
| 66 | + |
| 67 | +# Ignoring Na values |
| 68 | +df["period"] = pd.to_datetime(df["period"], errors="coerce") |
| 69 | +df["value"] = pd.to_numeric(df["value"], errors="coerce") |
| 70 | + |
| 71 | +# Convert units |
| 72 | +ycol = "value" |
| 73 | +ylabel = "Demand (MWh)" |
| 74 | +if units == "GWh": |
| 75 | + df["value_gwh"] = df["value"] / 1000.0 |
| 76 | + ycol = "value_gwh" |
| 77 | + ylabel = "Demand (GWh)" |
| 78 | + |
| 79 | +# Aggregation by date and fuel type |
| 80 | +agg = ( |
| 81 | + df.groupby(["period", "type-name"], as_index=False)[ycol] |
| 82 | + .sum() |
| 83 | + .rename(columns={ycol: "Demand"}) |
| 84 | +) |
| 85 | + |
| 86 | +# Keep top N fuel types by total |
| 87 | +top_fuels = agg.groupby("type-name")["Demand"].sum().nlargest(top_n).index |
| 88 | +agg = agg[agg["type-name"].isin(top_fuels)].copy() |
| 89 | + |
| 90 | +# Plot Graph |
| 91 | +fig = px.line( |
| 92 | + agg.sort_values("period"), |
| 93 | + x="period", |
| 94 | + y="Demand", |
| 95 | + color="type-name", |
| 96 | + title=f"Electricity demand by fuel type ({start} to {end})", |
| 97 | + labels={"period": "Date", "Demand": ylabel, "type-name": "Fuel type"}, |
| 98 | +) |
| 99 | +st.plotly_chart(fig, use_container_width=True) |
0 commit comments