import os import plotly.express as px import plotly.graph_objects as go import pandas as pd from dash import Dash, html, dcc, Input, Output, callback import plotly.express as px import numpy as np import example_data import core from plotly.subplots import make_subplots outside_temp = example_data.ExampleDailyOutsideTemperature energy_price = example_data.ExampleDailyEnergyCost boiler_temperature = example_data.ExampleBoilerTemperature data = pd.DataFrame(columns=['hour', 'energy_consumption', 'comfort', 'policy_readable']) data = pd.concat([data, pd.DataFrame({'hour': np.arange(0, 24), 'energy_consumption': energy_price.value, 'comfort': np.random.rand(24), 'policy_readable': np.random.choice(['A', 'B', 'C', 'D', 'E'], 24) })]) debug = False external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = Dash(__name__, external_stylesheets=external_stylesheets) app.layout = html.Div([ dcc.Location(id='url', refresh=False), html.Div(id='page-content') ]) server = app.server # Solution options solution_options = [ "Discrete Optimization", "Continuous Optimization", "Reinforcement Learning" ] solution_options_default_value = solution_options[0] # Datasets dataset_options = [ "16NSJNnjLK4MndjZYaKYGKEV", "7uLwefnSt8CgVlmIGY8emqJK", "8yS04Ddkk3pPL8e9Rku4LJtc", "Cwp33jA19hp9VdoNJUlj6USf", "iBFIAuvh7bCNyOQDo0jkjhRV", "iNVKpGfGW6rU17eOtxpZSFWR", "kaTMmHVh8gXUbHMppzdmdzpv", "KN9Z3gANLftDuUGvgs8O38dI", "LzbMafI31IosheUI7YGhj5at", "PHqaZDuMTRvCZCvA259Z1vJu", "RZngVU6axOdshmfma0yNAajE", "SQUOjMB6zAgYpSJEMy46tKXJ", ] dataset_options_default_value = dataset_options[0] dataset_original_dfs = { "16NSJNnjLK4MndjZYaKYGKEV": pd.read_csv('data/original/16NSJNnjLK4MndjZYaKYGKEV.csv'), "7uLwefnSt8CgVlmIGY8emqJK": pd.read_csv('data/original/7uLwefnSt8CgVlmIGY8emqJK.csv'), "8yS04Ddkk3pPL8e9Rku4LJtc": pd.read_csv('data/original/8yS04Ddkk3pPL8e9Rku4LJtc.csv'), "Cwp33jA19hp9VdoNJUlj6USf": pd.read_csv('data/original/Cwp33jA19hp9VdoNJUlj6USf.csv'), "iBFIAuvh7bCNyOQDo0jkjhRV": pd.read_csv('data/original/iBFIAuvh7bCNyOQDo0jkjhRV.csv'), "iNVKpGfGW6rU17eOtxpZSFWR": pd.read_csv('data/original/iNVKpGfGW6rU17eOtxpZSFWR.csv'), "kaTMmHVh8gXUbHMppzdmdzpv": pd.read_csv('data/original/kaTMmHVh8gXUbHMppzdmdzpv.csv'), "KN9Z3gANLftDuUGvgs8O38dI": pd.read_csv('data/original/KN9Z3gANLftDuUGvgs8O38dI.csv'), "LzbMafI31IosheUI7YGhj5at": pd.read_csv('data/original/LzbMafI31IosheUI7YGhj5at.csv'), "PHqaZDuMTRvCZCvA259Z1vJu": pd.read_csv('data/original/PHqaZDuMTRvCZCvA259Z1vJu.csv'), "RZngVU6axOdshmfma0yNAajE": pd.read_csv('data/original/RZngVU6axOdshmfma0yNAajE.csv'), "SQUOjMB6zAgYpSJEMy46tKXJ": pd.read_csv('data/original/SQUOjMB6zAgYpSJEMy46tKXJ.csv'), } dataset_water_consumption_dfs = { "16NSJNnjLK4MndjZYaKYGKEV": pd.read_csv('data/water_consumption/16NSJNnjLK4MndjZYaKYGKEV_water_consumption.csv'), "7uLwefnSt8CgVlmIGY8emqJK": pd.read_csv('data/water_consumption/7uLwefnSt8CgVlmIGY8emqJK_water_consumption.csv'), "8yS04Ddkk3pPL8e9Rku4LJtc": pd.read_csv('data/water_consumption/8yS04Ddkk3pPL8e9Rku4LJtc_water_consumption.csv'), "Cwp33jA19hp9VdoNJUlj6USf": pd.read_csv('data/water_consumption/Cwp33jA19hp9VdoNJUlj6USf_water_consumption.csv'), "iBFIAuvh7bCNyOQDo0jkjhRV": pd.read_csv('data/water_consumption/iBFIAuvh7bCNyOQDo0jkjhRV_water_consumption.csv'), "iNVKpGfGW6rU17eOtxpZSFWR": pd.read_csv('data/water_consumption/iNVKpGfGW6rU17eOtxpZSFWR_water_consumption.csv'), "kaTMmHVh8gXUbHMppzdmdzpv": pd.read_csv('data/water_consumption/kaTMmHVh8gXUbHMppzdmdzpv_water_consumption.csv'), "KN9Z3gANLftDuUGvgs8O38dI": pd.read_csv('data/water_consumption/KN9Z3gANLftDuUGvgs8O38dI_water_consumption.csv'), "LzbMafI31IosheUI7YGhj5at": pd.read_csv('data/water_consumption/LzbMafI31IosheUI7YGhj5at_water_consumption.csv'), "PHqaZDuMTRvCZCvA259Z1vJu": pd.read_csv('data/water_consumption/PHqaZDuMTRvCZCvA259Z1vJu_water_consumption.csv'), "RZngVU6axOdshmfma0yNAajE": pd.read_csv('data/water_consumption/RZngVU6axOdshmfma0yNAajE_water_consumption.csv'), "SQUOjMB6zAgYpSJEMy46tKXJ": pd.read_csv('data/water_consumption/SQUOjMB6zAgYpSJEMy46tKXJ_water_consumption.csv'), } dataset_water_consumption_monthly_dfs = { "16NSJNnjLK4MndjZYaKYGKEV": pd.read_csv('data/water_consumption/monthly/16NSJNnjLK4MndjZYaKYGKEV_month.csv'), "7uLwefnSt8CgVlmIGY8emqJK": pd.read_csv('data/water_consumption/monthly/7uLwefnSt8CgVlmIGY8emqJK_month.csv'), "8yS04Ddkk3pPL8e9Rku4LJtc": pd.read_csv('data/water_consumption/monthly/8yS04Ddkk3pPL8e9Rku4LJtc_month.csv'), "Cwp33jA19hp9VdoNJUlj6USf": pd.read_csv('data/water_consumption/monthly/Cwp33jA19hp9VdoNJUlj6USf_month.csv'), "iBFIAuvh7bCNyOQDo0jkjhRV": pd.read_csv('data/water_consumption/monthly/iBFIAuvh7bCNyOQDo0jkjhRV_month.csv'), "iNVKpGfGW6rU17eOtxpZSFWR": pd.read_csv('data/water_consumption/monthly/iNVKpGfGW6rU17eOtxpZSFWR_month.csv'), "kaTMmHVh8gXUbHMppzdmdzpv": pd.read_csv('data/water_consumption/monthly/kaTMmHVh8gXUbHMppzdmdzpv_month.csv'), "KN9Z3gANLftDuUGvgs8O38dI": pd.read_csv('data/water_consumption/monthly/KN9Z3gANLftDuUGvgs8O38dI_month.csv'), "LzbMafI31IosheUI7YGhj5at": pd.read_csv('data/water_consumption/monthly/LzbMafI31IosheUI7YGhj5at_month.csv'), "PHqaZDuMTRvCZCvA259Z1vJu": pd.read_csv('data/water_consumption/monthly/PHqaZDuMTRvCZCvA259Z1vJu_month.csv'), "RZngVU6axOdshmfma0yNAajE": pd.read_csv('data/water_consumption/monthly/RZngVU6axOdshmfma0yNAajE_month.csv'), "SQUOjMB6zAgYpSJEMy46tKXJ": pd.read_csv('data/water_consumption/monthly/SQUOjMB6zAgYpSJEMy46tKXJ_month.csv'), } # provide a scalar value to enable the slider to select ideal temperature ideal_temperature = 50 dashboard_layout = html.Div([ dcc.Link('About this project', href='/wiki'), html.H1('System Evaluation'), #small subtitle that says of solution is possible or not html.Div(id='solution-status', children='', style={'color': 'lighrgrey'}), html.Div([ html.Div([ html.H3('Dataset'), dcc.Dropdown( id='dataset-dropdown', options=dataset_options, value=dataset_options_default_value, ) ], className='three columns'), html.Div([ html.H3('Solution'), dcc.Dropdown( id='solution-dropdown', options=solution_options, value=solution_options_default_value, ) ], className='three columns'), html.Div([ html.H3('Ideal Shower Temperature'), dcc.Slider( id='ideal-temperature-slider', min=0, max=100, step=1, value=ideal_temperature, marks={ 0: '0°C', 25: '25°C', 50: '50°C', 75: '75°C', 100: '100°C' }, ) ], className='three columns'), ], className='row'), html.Div( [ html.Div( [ html.H3('Dataset'), dcc.Graph(id='dataset-graph') ], className='twelve columns', ) ], className='row'), html.Div( [ html.Div( [ html.H3('Water Comsumption Patterns'), dcc.Graph(id='water-consumption-graph') ], className='twelve columns', ) ], className='row'), html.Div( [ html.Div( [ html.H4('Hourly'), dcc.Graph(id='water_consumption_hourly_graph') ], className='six columns', ), html.Div( [ html.H4('Day of the Week'), dcc.Graph(id='water_consumption_week_day_graph') ], className='six columns', ) ], className='row'), html.Div( [ html.Div( [ html.H4('Monthly'), dcc.Graph(id='water_consumption_monthly_graph') ], className='six columns', ) ], className='row'), html.Div( [ html.Div( [ html.H3('Policy'), dcc.Graph(id='policy_readable-graph') ], className='six columns', ), html.Div( [ html.H3('Energy Consumption'), dcc.Graph(id='energy-consumption-graph') ], className='six columns' ), ] ), html.Div( [ html.Div( [ html.H3('Comfort'), dcc.Graph(id='comfort-graph') ], className='six columns' ) ], className='row'), ], #add background image from local file and make it transparent #, style={'background-image':'url(/assets/background_1.png)'} style={'background-color': '#333', 'font-family': 'Fantasy', 'color': '#999', 'padding': '10px'} ) wiki_layout = html.Div([ dcc.Link('Dashboard', href='/'), html.H1('About this project'), html.Div([ html.Div([ html.H3('What is this project about?'), html.P('This project is a simulation of a shower system. The goal is to find the best policy for the boiler to heat the water for the shower. The policy is a function that takes the current hour of the day and the current temperature of the water in the boiler and returns the temperature that the boiler should heat the water to.'), html.P('The best policy is the one that maximizes the comfort of the shower and minimizes the energy consumption of the boiler.'), html.H3('How does it work?'), #Insert image of the system html.H3('\'Bout us'), html.Img(src='/assets/hackatos.png', style={'width': '40%', 'height': 'auto', 'display': 'block', 'margin-left': 'auto', 'margin-right': 'auto'}), html.P('This project was developed by a team of 3, in the context of the Aveiro Tech City 2023 hackathon.'), html.P('The team members are:'), html.H4('Rui Melo'), html.H4('André Catarino'), html.H4('Francisco Petronilho'), html.H4('André Tomás'), html.H4('Zé Miguel'), html.H3('References'), html.P('The boiler model was based on the following paper:'), ], className='six columns'),], className='row'), ], style={'background-color': '#333', 'font-family': 'Fantasy', 'color': '#999', 'padding': '10px'} ) # Update the index @callback(Output('page-content', 'children'), Input('url', 'pathname')) def display_page(pathname): if pathname == '/': return dashboard_layout elif pathname == '/wiki': return wiki_layout else: return '404' # You could also return a 404 "URL not found" page here @app.callback( Output('policy_readable-graph', 'figure'), Output('energy-consumption-graph', 'figure'), Output('comfort-graph', 'figure'), Output('dataset-graph', 'figure'), Output('water-consumption-graph', 'figure'), Output('water_consumption_hourly_graph', 'figure'), Output('water_consumption_week_day_graph', 'figure'), Output('water_consumption_monthly_graph', 'figure'), Output('solution-status', 'children'), Input('dataset-dropdown', 'value'), Input('solution-dropdown', 'value'), Input('ideal-temperature-slider', 'value') ) def update_graph(dataset, solution, ideal_temperature): energy_consumption = data['energy_consumption'].values comfort_obtained = data['comfort'].values # Original Dataset Graph original_df = dataset_original_dfs[dataset] dataset_graph = px.line() dataset_graph.add_scatter(x=original_df['ts'], y=original_df['ActPow'], mode='lines', name='ActPow') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['HwActive'], mode='lines', name='HwActive') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['ChActive'], mode='lines', name='ChActive') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['HwTSet'], mode='lines', name='HwTSet') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['DHW_E21_T3_START_TEMP'], mode='lines', name='START_TEMP') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['HwTStor'], mode='lines', name='HwTStor') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['HwTAct'], mode='lines', name='HwTAct') dataset_graph.add_scatter(x=original_df['ts'], y=original_df['OutTemp'], mode='lines', name='OutTemp') start_time = pd.Timestamp(original_df['ts'][0]) dataset_graph.update_xaxes(range=[start_time, start_time+pd.Timedelta(days=2)]) # Water Consumption Graph water_consumption_df = dataset_water_consumption_dfs[dataset] if len(water_consumption_df) / 24 > 365: water_consumption_df = water_consumption_df.head(365* 24) water_consumption_df.index = pd.to_datetime(water_consumption_df["ts"], errors='coerce') water_consumption_graph = go.Figure() water_consumption_graph = make_subplots(specs=[[{"secondary_y": True}]]) water_consumption_graph.add_trace(go.Scatter(x=water_consumption_df[:]["ts"], y=water_consumption_df[:]['water_consumption_bool'], mode='lines', name='Water consumption'), secondary_y=False,) water_consumption_graph.add_trace(go.Scatter(x=water_consumption_df[:]["ts"], y=water_consumption_df[:]['HwTStor'], mode='lines', name='Water temperature') ,secondary_y=True,) water_consumption_graph.update_layout( title_text="Water consumption" ) water_consumption_graph.update_xaxes(title_text="time") water_consumption_graph.update_yaxes(title_text="water consumption", secondary_y=False) water_consumption_graph.update_yaxes(title_text="water temperature", secondary_y=True) # Water Consumption Hourly Graph water_consumption_df["ts_hour"] = water_consumption_df["ts"].apply(lambda x: x.split(" ")[1].split(":")[0]) hour_series = water_consumption_df.groupby("ts_hour")["water_consumption_bool"].sum() water_consumption_hourly_graph = go.Figure() water_consumption_hourly_graph.add_trace(go.Bar(x=hour_series.index, y=hour_series.values, name='Water consumption per hour')) water_consumption_hourly_graph.update_layout( title_text="Water consumption per hour" ) water_consumption_hourly_graph.update_xaxes(title_text="Hour of day") water_consumption_hourly_graph.update_yaxes(title_text="Number of water usages") # Water Consumption Week Day Graph order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] water_consumption_df["datetime"] = pd.to_datetime(water_consumption_df["ts"], errors='coerce') #create columns with day of week water_consumption_df['day_of_week'] = water_consumption_df["datetime"].apply(lambda x: x.day_name()) #turn day of week number into day of week name #df['day_of_week'] = df['day_of_week'].apply(lambda x: calendar.day_name[x]) week_series = water_consumption_df.groupby("day_of_week")["water_consumption_bool"].sum().loc[order] # Water Consumption Week Day Graph water_consumption_week_day_graph = go.Figure() water_consumption_week_day_graph.add_trace(go.Bar(x=week_series.index, y=week_series.values, name='Water consumption per day of week')) water_consumption_week_day_graph.update_layout( title_text="Water consumption per day of week" ) water_consumption_week_day_graph.update_xaxes(title_text="Day of week") water_consumption_week_day_graph.update_yaxes(title_text="Number of water usages") #dataset_water_consumption_monthly_dfs #Water Consumption Monthly Graph water_consumption_monthly_df = dataset_water_consumption_monthly_dfs[dataset] water_consumption_monthly_graph = go.Figure() water_consumption_monthly_graph.add_trace(go.Bar(x=water_consumption_monthly_df["month"], y=water_consumption_monthly_df["water_consumption_bool"], name='Water consumption per month')) water_consumption_monthly_graph.update_layout( title_text="Water consumption per month" ) water_consumption_monthly_graph.update_xaxes(title_text="Month") water_consumption_monthly_graph.update_yaxes(title_text="Number of water usages") # Policy Graph policy_readable_graph = px.line(data, x='hour', y='policy_readable', labels={'hour': 'Hour', 'policy_readable': 'Policy'}, color_discrete_sequence=['lightgreen']) policy_readable_graph.update_layout( xaxis_title="Hour", yaxis_title="Temperature (°C)", legend_title="Policy" ) # Energy Consumption Graph energy_consumption_graph = px.line(data, x='hour', y='energy_consumption', labels={'hour': 'Hour', 'energy_consumption': 'Energy Consumption (kWh)'}, color_discrete_sequence=['lightgreen']) energy_consumption_graph.update_layout( xaxis_title="Hour", yaxis_title="Energy Consumption (kWh)", legend_title="Energy Consumption", ) #add accumulated energy consumption energy_consumption = np.cumsum(energy_consumption) energy_consumption_graph.add_trace(px.line(data, x='hour', y=energy_consumption, labels={'y': 'Acc. Energy Consumption (kWh)'}, color_discrete_sequence=['green']).data[0]) # Comfort Graph comfort_graph = px.line(data, x='hour', y='comfort', labels={'hour': 'Hour', 'comfort': 'comfort Score'}, color_discrete_sequence=['lightgreen']) comfort_graph.update_layout( xaxis_title="Hour", yaxis_title="comfort Score", legend_title="comfort" ) #add accumulated comfort comfort_obtained = np.cumsum(comfort_obtained) comfort_graph.add_trace(px.line(data, x='hour', y=comfort_obtained, labels={'y': 'Acc. comfort Score'}, color_discrete_sequence=['green'] ).data[0]) result = "No solution found" return policy_readable_graph, energy_consumption_graph, comfort_graph, dataset_graph, water_consumption_graph, water_consumption_hourly_graph, water_consumption_week_day_graph,water_consumption_monthly_graph, result if __name__ == "__main__": app.run_server(host="0.0.0.0", port="8050", debug=debug)