Skip to content

Commit

Permalink
Merge pull request #34 from JoshuaMarden/dashboard_extentions
Browse files Browse the repository at this point in the history
Dashboard extentions
  • Loading branch information
JoshuaMarden authored Aug 22, 2024
2 parents 2de375d + 6f28ad7 commit 0a2b77f
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 61 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.venv
*.env
*.tfvars
*explore.ipynb

# Logs and Logging-Related
tmp/logs/*
Expand Down
168 changes: 107 additions & 61 deletions dashboard/dashboard_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import streamlit as st
import psycopg2
import altair as alt
import datetime as dt
from datetime import timedelta
from dotenv import load_dotenv

load_dotenv('.env')
Expand All @@ -12,8 +14,12 @@
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB_NAME = os.getenv('DB_NAME')

CURRENT_TIME = dt.datetime.now()
LAST_24_HOURS = CURRENT_TIME - timedelta(hours=24)
NEXT_24_HOURS = CURRENT_TIME + timedelta(hours=24)

class DataLoader:

class DataBase:
@staticmethod
def connect_to_db(db_host: str = DB_HOST, db_port: str = DB_PORT,
db_user: str = DB_USER, db_password: str = DB_PASSWORD,
Expand All @@ -33,21 +39,41 @@ def fetch_data_from_tables(conn):
demand_query = "SELECT * FROM Demand"
gen_query = "SELECT * FROM Generation"
carbon_query = "SELECT * FROM Carbon"
piechart_query = "SELECT * FROM generation_percent"
demand_df = pd.read_sql_query(demand_query, conn)
gen_df = pd.read_sql_query(gen_query, conn)
carbon_df = pd.read_sql_query(carbon_query, conn)
carbon_df = carbon_df[-48:]
pie_df = pd.read_sql_query(piechart_query, conn)

if conn:
conn.close()
return gen_df, demand_df, carbon_df
return gen_df, demand_df, carbon_df, pie_df
raise ConnectionError("Failed to connect to Database")

def submit_form(self, name, email, postcode, hours_to_charge, charging_preference):
conn = self.connect_to_db()
cursor = conn.cursor()
insert_query = """
INSERT INTO user_data (users_name, user_email, user_postcode, hours_to_charge, user_preference)
VALUES (%s, %s, %s, %s, %s)
"""
cursor.execute(insert_query, (name, email, postcode,
hours_to_charge, charging_preference))
conn.commit()

if cursor:
cursor.close()
if conn:
conn.close()


class dashboard:
class Dashboard:
def __init__(self) -> None:
pass

def carbon_plots(self, carbon_df: pd.DataFrame) -> alt.Chart:

return alt.Chart(carbon_df).mark_bar().encode(alt.X('publish_time:T', title='Time'),
y=alt.Y('forecast:Q', title='Carbon Intensity'), color='carbon_level').properties(width=650, height=400)

Expand All @@ -64,11 +90,14 @@ def generation_fuel_type(self, gen_df: pd.DataFrame) -> alt.Chart:
"NUCLEAR", "OCGT", "OIL", "OTHER", "PS", "WIND"]
df_fuel_types = gen_df[gen_df['fuel_type'].isin(
fuel_types)]

return alt.Chart(df_fuel_types[["publish_time", "generated", "fuel_type"]]).mark_line().encode(
x=alt.X('publish_time:T', title='Time'), y=alt.Y('generated:Q', title='Energy Generated MW'),
color="fuel_type").properties(width=1000, height=1000)

def generate_piechart(self, pie_df):
pie_df = pie_df[["fuel_type", "slice_percentage"]]
return alt.Chart(pie_df).mark_arc().encode(theta="slice_percentage", color="fuel_type")

def intensity_factors_df(self) -> alt.Chart:
intensity_factors = {'Energy Source': ['Biomass', 'Coal', 'Dutch Imports', 'French Imports', 'Gas (Combined Cycle)', 'Gas (Open Cycle)',
'Hydro', 'Irish Imports', 'Nuclear', 'Oil', 'Other', 'Pumped Storage', 'Solar', 'Wind'],
Expand Down Expand Up @@ -115,24 +144,29 @@ def generation_interconnection(self, gen_df: pd.DataFrame) -> alt.Chart:

return alt.Chart(df_interconnectors[["publish_time", "generated", "country"]]).mark_line().encode(x=alt.X('publish_time:T', title='Time'), y=alt.Y('generated:Q', title='Energy Generated MW'), color="country").properties(width=1400, height=1000)

def generate_dashboard(self, gen_df: pd.DataFrame, demand_df: pd.DataFrame, carbon_df: pd.DataFrame):
def generate_dashboard(self, gen_df: pd.DataFrame, demand_df: pd.DataFrame, carbon_df: pd.DataFrame, pie_df: pd.DataFrame, energy_db: DataBase):
st.set_page_config(layout="wide")
st.title("Energy Monitor")
with st.container():
st.header("Carbon Intensity Forecast")
col1, col2 = st.columns(2)
with col1:
st.altair_chart(self.carbon_plots(carbon_df))
carbon_container = st.container(border=True)
with carbon_container:
low_col, high_col = carbon_container.columns(2)
with low_col:
st.metric(label="Lowest Carbon Footprint at:", value=f"{self.time_of_lowest_carbon(
carbon_df)}", delta=f"{min(carbon_df["forecast"].values)}")
with high_col:
st.metric(label="Highest Carbon Footprint at:", value=f"{
self.time_of_highest_carbon(carbon_df)}", delta=f"{max(carbon_df["forecast"].values)}", delta_color="inverse")
with st.expander("Join our mail list to be informed on the greenest time to charge your EV"):
carbon_tab, generation_tab = st.tabs(
["Carbon Impact", "Energy Generation"])

with carbon_tab:
with st.container():
st.header("Carbon Intensity Forecast")
col1, col2 = st.columns(2)
with col1:
st.altair_chart(self.carbon_plots(carbon_df))
carbon_container = st.container(border=True)
with carbon_container:
low_col, high_col = carbon_container.columns(2)
with low_col:
st.metric(label="Lowest Carbon Footprint at:", value=f"{self.time_of_lowest_carbon(
carbon_df)}", delta=f"{min(carbon_df["forecast"].values)}")
with high_col:
st.metric(label="Highest Carbon Footprint at:", value=f"{
self.time_of_highest_carbon(carbon_df)}", delta=f"{max(carbon_df["forecast"].values)}", delta_color="inverse")
st.header(
"Join our mail list to be informed on the greenest time to charge your EV")
email_form = st.form("email_form")
name = email_form.text_input("Name")
email = email_form.text_input("Email")
Expand All @@ -142,48 +176,60 @@ def generate_dashboard(self, gen_df: pd.DataFrame, demand_df: pd.DataFrame, carb
charging_preference = email_form.select_slider(
"When do you normally charge?", options=["Morning", "Afternoon", "Evening", "Night"])

email_form.form_submit_button("Submit")

with col2:
st.header("What is Carbon Intensity?")
st.write("The carbon intensity of electricity is a measure of how much CO2 emissions are produced per kilowatt hour of electricity consumed.The carbon intensity of electricity is sensitive to small changes in carbon-intensive generation. Carbon intensity varies due to changes in electricity demand, low carbon generation (wind, solar, hydro, nuclear, biomass) and conventional generation.")
with st.expander("Find out more"):
Method_tab, Factors_tab = st.tabs(
["Methodology", "Intensity Factors"])
with Method_tab:
st.write("The demand and generation by fuel type (gas, coal, wind, nuclear, solar etc.) for each region is forecast several days ahead at 30-min temporal resolution using an ensemble of state-of-the-art supervised Machine Learning (ML) regression models. An advanced model ensembling technique is used to blend the ML models to generate a new optimised meta-model. The forecasts are updated every 30 mins using a nowcasting technique to adjust the forecasts a short period ahead. The carbon intensity factors are applied to each technology type for each import generation mix to calculate the forecast")
with Factors_tab:
st.table(self.intensity_factors_df())

with st.container():
st.header("Energy Generation by Fuel Type")
col1, col2 = st.columns([3, 1])
with col1:
st.altair_chart(self.generation_fuel_type(gen_df))
with col2:
with st.expander("Fuel Type Information"):
st.write("""
- **BIOMASS**: Organic materials used as a renewable energy source. It includes plant materials and animal waste that can be burned or converted to biofuels.
- **CCGT (Combined Cycle Gas Turbine)**: A form of highly efficient energy generation that combines a gas-fired turbine with a steam turbine.
- **COAL**: Traditional fossil fuel used for generating electricity through combustion.
- **NPSHYD (Non-Pumped Storage Hydro)**: Refers to the conventional hydroelectric generation where water flows through turbines to generate power, with no pumped storage components.
- **NUCLEAR**: Power generated using nuclear reactions.Provides a stable base-load energy supply.
- **OCGT (Open Cycle Gas Turbine)**: A type of gas power plant where air is compressed, mixed with fuel, and burned in a simple cycle. It's less efficient than CCGT but is often quicker to start and stop.
- **OIL**: Oil-fired power plants burn petroleum or its derivatives to generate electricity. Similar to coal, it has large environmental impacts.
- **OTHER**: This category usually encompasses any generation sources not specifically listed, which could include experimental or less common technologies like tidal or certain types of bio-gas plants.
- **PS (Pumped Storage)**: A type of hydropower generation where water is pumped to a higher elevation during low demand periods and released through turbines for electricity during high demand.
- **WIND**: The use of wind turbines to convert wind energy into electricity. It's a clean, renewable source increasingly used worldwide, particularly in areas with strong, consistent winds.
""")

with st.container():
st.header("Where is your energy coming from ? ")
st.write("Interconnectors are high-voltage links allowing electricity to flow between regions or countries, providing crucial flexibility and reliability to power supplies. They help balance energy demand and supply, integrate renewable energy sources, and enhance grid resilience and sustainability. This leads to more stable electricity prices and a more reliable power supply for everyone.")
st.altair_chart(self.generation_interconnection(gen_df))
submit = email_form.form_submit_button("Submit")
if submit:
energy_db.submit_form(name, email, postcode,
hours_to_charge, charging_preference)

with col2:
st.header("What is Carbon Intensity?")
st.write("The carbon intensity of electricity is a measure of how much CO2 emissions are produced per kilowatt hour of electricity consumed.The carbon intensity of electricity is sensitive to small changes in carbon-intensive generation. Carbon intensity varies due to changes in electricity demand, low carbon generation (wind, solar, hydro, nuclear, biomass) and conventional generation.")
with st.expander("Find out more"):
Method_tab, Factors_tab = st.tabs(
["Methodology", "Intensity Factors"])
with Method_tab:
st.write("The demand and generation by fuel type (gas, coal, wind, nuclear, solar etc.) for each region is forecast several days ahead at 30-min temporal resolution using an ensemble of state-of-the-art supervised Machine Learning (ML) regression models. An advanced model ensembling technique is used to blend the ML models to generate a new optimised meta-model. The forecasts are updated every 30 mins using a nowcasting technique to adjust the forecasts a short period ahead. The carbon intensity factors are applied to each technology type for each import generation mix to calculate the forecast")
with Factors_tab:
st.table(self.intensity_factors_df())
with generation_tab:
show_all_data = st.checkbox('Show all historical data')
if not show_all_data:
filtered_df = gen_df[gen_df['publish_time'] >= LAST_24_HOURS]
else:
filtered_df = gen_df
with st.container():
st.header("Energy Generation by Fuel Type")
col1, col2 = st.columns([3, 1])
with col1:
st.altair_chart(self.generation_fuel_type(filtered_df))
st.write("Energy generated in the last 30 minutes")
st.altair_chart(self.generate_piechart(pie_df))
with col2:
with st.expander("Fuel Type Information"):
st.write("""
- **BIOMASS**: Organic materials used as a renewable energy source. It includes plant materials and animal waste that can be burned or converted to biofuels.
- **CCGT (Combined Cycle Gas Turbine)**: A form of highly efficient energy generation that combines a gas-fired turbine with a steam turbine.
- **COAL**: Traditional fossil fuel used for generating electricity through combustion.
- **NPSHYD (Non-Pumped Storage Hydro)**: Refers to the conventional hydroelectric generation where water flows through turbines to generate power, with no pumped storage components.
- **NUCLEAR**: Power generated using nuclear reactions.Provides a stable base-load energy supply.
- **OCGT (Open Cycle Gas Turbine)**: A type of gas power plant where air is compressed, mixed with fuel, and burned in a simple cycle. It's less efficient than CCGT but is often quicker to start and stop.
- **OIL**: Oil-fired power plants burn petroleum or its derivatives to generate electricity. Similar to coal, it has large environmental impacts.
- **OTHER**: This category usually encompasses any generation sources not specifically listed, which could include experimental or less common technologies like tidal or certain types of bio-gas plants.
- **PS (Pumped Storage)**: A type of hydropower generation where water is pumped to a higher elevation during low demand periods and released through turbines for electricity during high demand.
- **WIND**: The use of wind turbines to convert wind energy into electricity. It's a clean, renewable source increasingly used worldwide, particularly in areas with strong, consistent winds.
""")

with st.container():
st.header("Where is your energy coming from ? ")
st.write("Interconnectors are high-voltage links allowing electricity to flow between regions or countries, providing crucial flexibility and reliability to power supplies. They help balance energy demand and supply, integrate renewable energy sources, and enhance grid resilience and sustainability. This leads to more stable electricity prices and a more reliable power supply for everyone.")
st.altair_chart(self.generation_interconnection(filtered_df))


if __name__ == "__main__":
connection = DataLoader.connect_to_db()
gen_df, demand_df, carbon_df = DataLoader.fetch_data_from_tables(
energy_db = DataBase()
connection = energy_db.connect_to_db()
gen_df, demand_df, carbon_df, pie_df = energy_db.fetch_data_from_tables(
connection)
energy_dashboard = dashboard()
energy_dashboard.generate_dashboard(gen_df, demand_df, carbon_df)
energy_dashboard = Dashboard()
energy_dashboard.generate_dashboard(
gen_df, demand_df, carbon_df, pie_df, energy_db)

0 comments on commit 0a2b77f

Please sign in to comment.