diff --git a/app/VEKA_2050+.py b/app/VEKA_2050+.py index 288d32c80..7e50fda59 100644 --- a/app/VEKA_2050+.py +++ b/app/VEKA_2050+.py @@ -16,8 +16,9 @@ - **Loads**: The total yearly load per energy carrier, year, country and subsector. - **Capacities**: The power production capacities installed per country, technologies and year. - **RES potentials**: The total potential for RES power production capacity considered by the model for the various technologies and countries. - - **Consumption Profiles**: The load 3-hourly profiles for every carrier, year and subsector. This data is currently shown at system level (ENTSO-E area) and Belgium (BE) due to the very large quantity of data that needs to be handled for every country in the system. - - **Production Profiles**: The same visualization as consumption for the supply side: 3-hourly production profiles by carrier and year. + - **Consumption**: The yearly load and 3-hourly profiles for every carrier, year and subsector. This data is currently shown at system level (ENTSO-E area), Belgium (BE), Flanders (FL) due to the very large quantity of data that needs to be handled for every country in the system. + - **Production**: The same visualization as consumption for the supply side: yearly production and 3-hourly production profiles by carrier, year and subsector. + - **Profiles**: The same visualization of 3-hourly profiles is presented. This view enables the comparison of profiles and leads to a better understanding of the dynamics. - **RES Profiles**: The same visualization as consumption for the supply side: 3-hourly production RES profiles by carrier and year. All countries are available. - **Imports & Exports**: Energy imports and exports between countries in the system, for all carriers, countries and years. - **Balancing**: (Under construction) diff --git a/app/pages/0Loads.py b/app/pages/0Loads.py index f92e8a938..6b5cf0ae9 100644 --- a/app/pages/0Loads.py +++ b/app/pages/0Loads.py @@ -46,10 +46,11 @@ def get_data(scenario): carrier = st.selectbox('Choose your carrier:', df_ca["carrier"].unique(), index=1) df_ca = df_ca.query("carrier==@carrier").drop("carrier", axis=1) -df_ca = df_ca.groupby(by="sector").sum() +df_ca = df_ca.groupby(by="sector").sum().sort_values(by="2050", ascending=False) df_ca_tot = pd.DataFrame(df_ca.sum().rename("Total")).T df_ca = pd.concat([df_ca, df_ca_tot]) +df_ca.index.name = "Annual load [TWh]" fig = px.bar( df_ca, @@ -69,9 +70,7 @@ def get_data(scenario): , use_container_width=True ) -st.subheader(f"Annual load per sector for {carrier}") st.dataframe(df_ca - .rename(mapper=lambda x: x + " [TWh]", axis=1) .style .format(precision=2, thousands=",", decimal='.'), use_container_width=True @@ -106,10 +105,11 @@ def get_data(scenario): sector = st.selectbox('Choose your sector:', df_se["sector"].unique(), index=8) df_se = df_se.query("sector==@sector").drop("sector", axis=1) -df_se = df_se.groupby(by="carrier").sum() +df_se = df_se.groupby(by="carrier").sum().sort_values(by="2050", ascending=False) df_se_tot = pd.DataFrame(df_se.sum().rename("Total")).T df_se = pd.concat([df_se, df_se_tot]) +df_se.index.name = "Annual load [TWh]" fig = px.bar( df_se, @@ -129,9 +129,7 @@ def get_data(scenario): , use_container_width=True ) -st.subheader(f"Annual load per carrier for {sector}") st.dataframe(df_se - .rename(mapper=lambda x: x + " [TWh]", axis=1) .style .format(precision=2, thousands=",", decimal='.'), use_container_width=True diff --git a/app/pages/1Capacities.py b/app/pages/1Capacities.py index d04ced89f..60ca2ccfe 100644 --- a/app/pages/1Capacities.py +++ b/app/pages/1Capacities.py @@ -44,8 +44,8 @@ def get_df(scenario): .groupby(['sector']) .sum(numeric_only=True) .rename(index={"sector": "Technologies"}) - ) +df.index.name = "Capacity [GW]" fig = px.bar( df, @@ -66,7 +66,6 @@ def get_df(scenario): ) st.dataframe(df - .rename(mapper=lambda x: x + " [GW]", axis=1) .style .format(precision=2, thousands=",", decimal='.'), use_container_width=True @@ -85,6 +84,8 @@ def get_df(scenario): .set_index('country') .rename_axis("Investment year") ) +df_bar.index.name = "Capacity [GW]" + fig_bar = px.bar( df_bar, title=f"{technology.capitalize()} installed capacities [GW]", @@ -99,9 +100,7 @@ def get_df(scenario): fig_bar.update_layout(hovermode="x unified", legend_title_text='Technologies') -col1, col2 = st.columns([0.35, 0.6]) -with col1: - st.dataframe(df_bar.style.format(precision=2, thousands=",", decimal='.'), width=500) -with col2: - st.plotly_chart(fig_bar +st.plotly_chart(fig_bar , use_container_width=True) + +st.dataframe(df_bar.style.format(precision=2, thousands=",", decimal='.'), use_container_width=True) diff --git a/app/pages/1RES_Potentials.py b/app/pages/1RES_Potentials.py index dca9382f4..2ad881147 100644 --- a/app/pages/1RES_Potentials.py +++ b/app/pages/1RES_Potentials.py @@ -36,6 +36,7 @@ def get_df(scenario): carrier = st.multiselect('Choose your carrier:', list(df.columns.unique()), default=list(df.columns.unique())[2:4]) df = df.loc[:, carrier] carrier_list = ' & '.join(list(map(str.capitalize, carrier))) +df.index.name = "Potential [GW]" fig = px.bar( df, @@ -54,6 +55,13 @@ def get_df(scenario): , use_container_width=True ) +st.dataframe(df + .rename(mapper=lambda x: x.capitalize() + " [GW]", axis=1) + .style + .format(precision=2, thousands=",", decimal='.'), + use_container_width=True + ) + st.divider() st.header("Potentials per country") diff --git a/app/pages/2Consumption.py b/app/pages/2Consumption.py new file mode 100644 index 000000000..741782299 --- /dev/null +++ b/app/pages/2Consumption.py @@ -0,0 +1,112 @@ +from pathlib import Path + +import pandas as pd +import plotly.express as px +import streamlit as st +from st_common import PROFILES_AREA +from st_common import YEARS +from st_common import network_path +from st_common import scenario_dict +from st_common import st_page_config +from st_common import st_side_bar + +st_page_config(layout="wide") +scenario = st_side_bar() + +st.title("Consumption per carrier") + +st.markdown("The total energy consumption per year, country and subsector. This data is currently shown at system level (ENTSO-E area), Belgium (BE) and Flanders (FL) due to the very large quantity of data that needs to be handled for every country in the system.") + + +@st.cache_data(show_spinner="Retrieving data ...") +def get_data(scenario, year, selected_area): + area = selected_area if selected_area != "ENTSO-E area" else '' + return ( + pd.read_csv( + Path(network_path, scenario_dict[scenario]["path"], + f"load_temporal_{area.lower()}_{year}.csv".replace('__', '_')), + header=[1, 2] + ) + .set_index(("carrier", "sector")) + ) + + +col1, col2 = st.columns(2) +with col1: + selected_area = st.selectbox('Choose area :', PROFILES_AREA) + +dfx = [] +for y in YEARS: + dfi = get_data(scenario, y, selected_area) + dfi = ((dfi.sum() / 1e3 + * 8760 / len(dfi.axes[0])) + .to_frame(name=y)) + dfx.append(dfi) +dfx = pd.concat(dfx, axis=1).fillna(0).sort_values(by=y, ascending=False) +dfx.index.name = 'Annual consumption [TWh]' + +with col2: + carrier = st.selectbox('Choose your carrier:', dfx.index.unique(0).sort_values(), index=6) +dfx = dfx.loc[carrier] + + +st.subheader(f"Annual {carrier} consumption per sector") + +total = (dfx.sum()) +dfx.loc['Total'] = total +dfx.index.name = "Annual consumption [TWh]" + +fig = px.bar( + dfx, + title=f"Consumption in {selected_area} for {carrier} [TWh]", + barmode="group", + text_auto=".2s" +) + +fig.update_traces(hovertemplate="%{y:,.0f}") +fig.update_layout(hovermode="x unified") +fig.update_yaxes(title_text='Consumption [TWh]') +fig.update_xaxes(title_text='Sectors') +fig.update_layout(legend_title_text='Years') + +st.plotly_chart( + fig + , use_container_width=True +) + +st.dataframe( + dfx + .style + .format(precision=2, thousands=",", decimal='.'), + use_container_width=True +) + +st.divider() + + +st.subheader(f"Consumption profiles per carrier") + +st.markdown( + "The load 3-hourly profiles for every carrier, year and subsector. You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want.") + +year = st.selectbox('Choose the year:', YEARS) +data = get_data(scenario, year, selected_area) + +df = data[carrier] + +fig = px.area( + df, + title=f"System consumption profile for {carrier} [GW]", +) +fig.update_traces(hovertemplate="%{y:,.0f}", + line=dict(width=0.1)) +fig.update_layout(legend_traceorder="reversed", + hovermode="x unified", + legend_title_text='Technologies') +fig.update_yaxes(title_text='Consumption [GW]') +fig.update_xaxes(title_text='Timesteps') + +st.plotly_chart( + fig + , use_container_width=True +) diff --git a/app/pages/2Consumption_Profiles.py b/app/pages/2Consumption_Profiles.py deleted file mode 100644 index 23099bc0c..000000000 --- a/app/pages/2Consumption_Profiles.py +++ /dev/null @@ -1,85 +0,0 @@ -from pathlib import Path - -import pandas as pd -import plotly.express as px -import streamlit as st -from st_common import PROFILES_AREA -from st_common import YEARS -from st_common import network_path -from st_common import scenario_dict -from st_common import st_page_config -from st_common import st_side_bar - -st_page_config(layout="wide") -scenario = st_side_bar() - -st.title("Consumption profiles per carrier") -st.markdown( - "The load 3-hourly profiles for every carrier, year and subsector. This data is currently shown at system level (ENTSO-E area) and Belgium (BE) due to the very large quantity of data that needs to be handled for every country in the system. You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want.") - -selected_area = st.selectbox('Choose area :', PROFILES_AREA) - - -@st.cache_data(show_spinner="Retrieving data ...") -def get_data(scenario, year, selected_area): - area = selected_area if selected_area != "ENTSO-E area" else '' - return ( - pd.read_csv( - Path(network_path, scenario_dict[scenario]["path"], - f"load_temporal_{area.lower()}_{year}.csv".replace('__', '_')), - header=[1, 2] - ) - .set_index(("carrier", "sector")) - ) - - -# %%Cell Name -# should be able to -# - Display per carrier -# - 3h load profile -# - eventually per country -# - eventuelly per subtype of supply - -col1, col2 = st.columns(2) -with col1: - year = st.selectbox('Choose the year:', YEARS) -data = get_data(scenario, year, selected_area) - -with col2: - carrier = st.selectbox('Choose your carrier:', data.columns.get_level_values(0).unique(), index=1) -df = data[carrier] - -fig = px.area( - df, - title=f"System consumption profile for {carrier} [GW]", -) -fig.update_traces(hovertemplate="%{y:,.0f}", - line=dict(width=0.1)) -fig.update_layout(legend_traceorder="reversed", - hovermode="x unified", - legend_title_text='Technologies') -fig.update_yaxes(title_text='Consumption [GW]') -fig.update_xaxes(title_text='Timesteps') - -st.plotly_chart( - fig - , use_container_width=True -) - -st.subheader(f"Annual {carrier} consumption per sector for {year} ") - -df_table = ((df.sum() / 1e3 - * 8760 / len(df.axes[0])) - .rename('Annual consumption [TWh]') - .sort_values(ascending=False) - .to_frame()) - -total = (df_table.sum()) - -df_table.loc['Total'] = total -st.dataframe( - df_table - .style - .format(precision=2, thousands=",", decimal='.'), - use_container_width=True -) diff --git a/app/pages/2Production.py b/app/pages/2Production.py new file mode 100644 index 000000000..7242b7dd9 --- /dev/null +++ b/app/pages/2Production.py @@ -0,0 +1,111 @@ +from pathlib import Path + +import pandas as pd +import plotly.express as px +import streamlit as st +from st_common import PROFILES_AREA +from st_common import YEARS +from st_common import network_path +from st_common import scenario_dict +from st_common import st_page_config +from st_common import st_side_bar + +st_page_config(layout="wide") +scenario = st_side_bar() + +st.title("Production per carrier") +st.markdown("The total energy production per year, country and subsector. This data is currently shown at system level (ENTSO-E area), Belgium (BE) and Flanders (FL) due to the very large quantity of data that needs to be handled for every country in the system.") + + +@st.cache_data(show_spinner="Retrieving data ...") +def get_data(scenario, year, selected_area): + area = selected_area if selected_area != "ENTSO-E area" else '' + return ( + pd.read_csv( + Path(network_path, scenario_dict[scenario]["path"], + f"supply_temporal_{area.lower()}_{year}.csv".replace('__', '_')), + header=[1, 2] + ) + .set_index(("carrier", "sector")) + ) + + +col1, col2 = st.columns(2) +with col1: + selected_area = st.selectbox('Choose area :', PROFILES_AREA) + +dfx = [] +for y in YEARS: + dfi = get_data(scenario, y, selected_area) + dfi = ((dfi.sum() / 1e3 + * 8760 / len(dfi.axes[0])) + .to_frame(name=y)) + dfx.append(dfi) +dfx = pd.concat(dfx, axis=1).fillna(0).sort_values(by=y, ascending=False) +dfx.index.name = 'Annual production [TWh]' + +with col2: + carrier = st.selectbox('Choose your carrier:', dfx.index.unique(0).sort_values(), index=6) +dfx = dfx.loc[carrier] + + +st.subheader(f"Annual {carrier} production per sector") + +total = (dfx.sum()) +dfx.loc['Total'] = total +dfx.index.name = "Annual production [TWh]" + +fig = px.bar( + dfx, + title=f"Production in {selected_area} for {carrier} [TWh]", + barmode="group", + text_auto=".2s" +) + +fig.update_traces(hovertemplate="%{y:,.0f}") +fig.update_layout(hovermode="x unified") +fig.update_yaxes(title_text='Production [TWh]') +fig.update_xaxes(title_text='Sectors') +fig.update_layout(legend_title_text='Years') + +st.plotly_chart( + fig + , use_container_width=True +) + +st.dataframe( + dfx + .style + .format(precision=2, thousands=",", decimal='.'), + use_container_width=True +) + +st.divider() + + +st.subheader(f"Production profiles per carrier") + +st.markdown( + "The load 3-hourly profiles for every carrier, year and subsector. You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want.") + +year = st.selectbox('Choose the year:', YEARS) +data = get_data(scenario, year, selected_area) + +df = data[carrier] + +fig = px.area( + df, + title=f"System production profile for {carrier} [GW]", +) +fig.update_traces(hovertemplate="%{y:,.0f}", + line=dict(width=0.1)) +fig.update_layout(legend_traceorder="reversed", + hovermode="x unified", + legend_title_text='Technologies') +fig.update_yaxes(title_text='Production [GW]') +fig.update_xaxes(title_text='Timesteps') + +st.plotly_chart( + fig + , use_container_width=True +) diff --git a/app/pages/2Production_Profiles.py b/app/pages/2Production_Profiles.py deleted file mode 100644 index 25f79dd39..000000000 --- a/app/pages/2Production_Profiles.py +++ /dev/null @@ -1,85 +0,0 @@ -from pathlib import Path - -import pandas as pd -import plotly.express as px -import streamlit as st -from st_common import PROFILES_AREA -from st_common import YEARS -from st_common import network_path -from st_common import scenario_dict -from st_common import st_page_config -from st_common import st_side_bar - -st_page_config(layout="wide") -scenario = st_side_bar() - -st.title("Production profiles per carrier") -st.markdown( - "The production 3-hourly profiles for every carrier, year and subsector. This data is currently shown at system level (ENTSO-E area) and Belgium (BE) due to the very large quantity of data that needs to be handled for every country in the system. You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want.") - -selected_area = st.selectbox('Choose area :', PROFILES_AREA) - - -@st.cache_data(show_spinner="Retrieving data ...") -def get_data(scenario, year, selected_area): - area = selected_area if selected_area != "ENTSO-E area" else '' - return ( - pd.read_csv( - Path(network_path, scenario_dict[scenario]["path"], - f"supply_temporal_{area.lower()}_{year}.csv".replace('__', '_')), - header=[1, 2] - ) - .set_index(("carrier", "sector")) - ) - - -# %%Cell Name -# should be able to -# - Display per carrier -# - 3h load profile -# - eventually per country -# - eventuelly per subtype of supply - -col1, col2 = st.columns(2) -with col1: - year = st.selectbox('Choose the year:', YEARS) -data = get_data(scenario, year, selected_area) - -with col2: - carrier = st.selectbox('Choose your carrier:', data.columns.get_level_values(0).unique(), index=6) -df = data[carrier] - -fig = px.area( - df, - title=f"System production profile for {carrier} [GW]", -) -fig.update_traces(hovertemplate="%{y:,.0f}", - line=dict(width=0.1)) -fig.update_layout(legend_traceorder="reversed", - hovermode="x unified", - legend_title_text='Technologies') -fig.update_yaxes(title_text='Production [GW]') -fig.update_xaxes(title_text='Timesteps') - -st.plotly_chart( - fig - , use_container_width=True -) - -st.subheader(f"Annual {carrier} production per technology for {year} ") - -df_table = ((df.sum() / 1e3 - * 8760 / len(df.axes[0])) - .rename('Annual production [TWh]') - .sort_values(ascending=False) - .to_frame()) - -total = (df_table.sum()) - -df_table.loc['Total'] = total -st.dataframe( - df_table - .style - .format(precision=2, thousands=",", decimal='.'), - use_container_width=True -) diff --git a/app/pages/2Profiles.py b/app/pages/2Profiles.py new file mode 100644 index 000000000..a6e610710 --- /dev/null +++ b/app/pages/2Profiles.py @@ -0,0 +1,126 @@ +from pathlib import Path + +import pandas as pd +import plotly.express as px +import plotly.subplots as sp +import streamlit as st +from st_common import PROFILES_AREA +from st_common import YEARS +from st_common import network_path +from st_common import scenario_dict +from st_common import st_page_config +from st_common import st_side_bar + +st_page_config(layout="wide") +scenario = st_side_bar() + +st.title("Production and consumption profiles") +st.markdown( + "The 3-hourly consumption and production profiles for every carrier, year and subsector. This data is currently shown at system level (ENTSO-E area), Belgium (BE) and Flanders (FL) due to the very large quantity of data that needs to be handled for every country in the system. \n\n" + "You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want. We suggest to maximize the graph to improve the experience.") + + +@st.cache_data(show_spinner="Retrieving data ...") +def get_data_supply(scenario, year, selected_area): + area = selected_area if selected_area != "ENTSO-E area" else '' + return ( + pd.read_csv( + Path(network_path, scenario_dict[scenario]["path"], + f"supply_temporal_{area.lower()}_{year}.csv".replace('__', '_')), + header=[1, 2] + ) + .set_index(("carrier", "sector")) + ) + + +@st.cache_data(show_spinner="Retrieving data ...") +def get_data_load(scenario, year, selected_area): + area = selected_area if selected_area != "ENTSO-E area" else '' + return ( + pd.read_csv( + Path(network_path, scenario_dict[scenario]["path"], + f"load_temporal_{area.lower()}_{year}.csv".replace('__', '_')), + header=[1, 2] + ) + .set_index(("carrier", "sector")) + ) + + +col1, col2 = st.columns(2) +with col1: + selected_area = st.selectbox('Choose area :', PROFILES_AREA) +with col2: + year = st.selectbox('Choose the year:', YEARS) + +prod = "Production" +cons = "Consumption" +types = [prod, cons] +col1, col2, col3, col4 = st.columns(4) +with col1: + carrier1 = st.selectbox('Choose your top carrier:', get_data_supply(scenario, year, selected_area).columns.unique(0).sort_values(), index=5) +with col2: + type1 = st.selectbox('Choose your top type:', types, index=0) +with col3: + carrier2 = st.selectbox('Choose your bottom carrier:', get_data_load(scenario, year, selected_area).columns.unique(0).sort_values(), index=5) +with col4: + type2 = st.selectbox('Choose your bottom type:', types, index=1) + +if type1 == prod: + data1 = get_data_supply(scenario, year, selected_area) +elif type1 == cons: + data1 = get_data_load(scenario, year, selected_area) +if type2 == prod: + data2 = get_data_supply(scenario, year, selected_area) +elif type2 == cons: + data2 = get_data_load(scenario, year, selected_area) + +df = data1[carrier1] +fig1 = px.area(df) + +df = data2[carrier2] +fig2 = px.area(df) + +# For as many traces that exist per Express figure, get the traces from each plot and store them in an array. +# This is essentially breaking down the Express fig into it's traces +figure1_traces = [] +figure2_traces = [] +for trace in range(len(fig1["data"])): + figure1_traces.append(fig1["data"][trace]) +for trace in range(len(fig2["data"])): + figure2_traces.append(fig2["data"][trace]) + +# Create a 1x2 subplot +this_figure = sp.make_subplots(rows=2, cols=1, shared_xaxes=True, shared_yaxes=True, + subplot_titles=[ + f"System {type1.lower()} profile for {carrier1} [GW]", + f"System {type2.lower()} profile for {carrier2} [GW]", + ]) + +# Get the Express fig broken down as traces and add the traces to the proper plot within in the subplot +for traces in figure1_traces: + this_figure.add_trace(traces.update(legendgrouptitle=dict(text=type1), legendgroup="1"), row=1, col=1) +for traces in figure2_traces: + this_figure.add_trace(traces.update(legendgrouptitle=dict(text=type2), legendgroup="2"), row=2, col=1) + +this_figure.update_layout(hovermode="x unified", + legend_title_text='Technologies', + legend_tracegroupgap=10,) + +this_figure.update_traces(hovertemplate="%{y:,.0f}", + line=dict(width=0.1), + row=1, col=1) +this_figure.update_yaxes(title_text=f'{type1} [GW]', + row=1, col=1) + +this_figure.update_traces(hovertemplate="%{y:,.0f}", + line=dict(width=0.1), + row=2, col=1) +this_figure.update_yaxes(title_text=f'{type2} [GW]', + row=2, col=1) +this_figure.update_xaxes(title_text='Timesteps', + row=2, col=1) + +st.plotly_chart( + this_figure + , use_container_width=True +) diff --git a/app/pages/2RES_Profiles.py b/app/pages/2RES_Profiles.py index 769981fe2..bc4d0c5a1 100644 --- a/app/pages/2RES_Profiles.py +++ b/app/pages/2RES_Profiles.py @@ -12,7 +12,7 @@ st_page_config(layout="wide") scenario = st_side_bar() -st.title("Renewable production per carrier") +st.title("Renewable production profiles per carrier") st.markdown( "The RES production 3-hourly profiles for every carrier, year and subsector. You can zoom on these interactive graphs for specific time windows and you can also select/deselect various categories if you want.") @@ -49,16 +49,11 @@ def get_df(scenario, year): df_table = ( (df.sum(axis=1) / 1e3 # TWh * 3) - .rename(f"Annual production [TWh]") - .to_frame() + .to_frame(name=year) .style .format(precision=2, thousands=",", decimal='.') ) -st.subheader(f"Renewable annual production for {country}") -st.dataframe(df_table, use_container_width=True) -st.subheader(f"Renewable production profiles for {country}") - carrier = st.selectbox('Choose your carrier:', list(df.index.unique())) if carrier != 'all': df = df.query("carrier in @carrier") @@ -80,3 +75,6 @@ def get_df(scenario, year): fig , use_container_width=True ) + +df_table.index.name = "Production [TWh]" +st.dataframe(df_table, use_container_width=True) \ No newline at end of file diff --git a/app/pages/3Imports_&_Exports.py b/app/pages/3Imports_&_Exports.py index 0b083bc0f..6826a6dcc 100644 --- a/app/pages/3Imports_&_Exports.py +++ b/app/pages/3Imports_&_Exports.py @@ -12,7 +12,7 @@ scenario = st_side_bar() st.title("Imports and exports per carrier") -st.markdown("The energy imports and exports between countries in the system, for all carriers, countries and years.") +st.markdown("The energy imports and exports between countries in the system, for all carriers and countries. A negative value means that the area is exporting.") @st.cache_data(show_spinner="Retrieving data ...") @@ -29,44 +29,47 @@ def get_data(scenario): df = get_data(scenario) -def query_imp_exp(df, carriers, country, year, imports_exports): +def query_imp_exp(df, carriers, country, imports_exports, year=None): df_imp_exp = ( df.query("" "carriers == @carriers & " - "year == @year & " "imports_exports == @imports_exports" ) - .drop(["carriers", "year", "imports_exports"], axis=1) - .set_index('countries') + .drop(["carriers", "imports_exports"], axis=1) + .set_index(["year", "countries"]) [country] ) + if year: + df_imp_exp = df_imp_exp.loc[year] return df_imp_exp -col1, col2, col3 = st.columns(3) +col1, col2 = st.columns(2) with col1: country = st.selectbox('Choose your country:', df["countries"].unique(), index=12) with col2: carrier = st.selectbox('Choose your carrier:', df['carriers'].unique()) -with col3: - year = st.selectbox('Choose your year:', df["year"].unique()) -df_imp_exp = ( - pd.concat([query_imp_exp(df, carrier, country, year, 'imports'), - -1 * query_imp_exp(df, carrier, country, year, 'exports')], - axis=1, keys=['imports', 'exports']) -) -df_imp_exp.rename(mapper=lambda x: x.capitalize(), axis=1, inplace=True) + +df_imp_x = query_imp_exp(df, carrier, country, 'imports').reset_index() +df_imp_x = df_imp_x[df_imp_x[country] != 0] +df_imp_x = df_imp_x.pivot_table(index="countries", values=country, columns="year") +df_imp_x.index.name = 'Annual import volume [TWh]' + +df_exp_x = (-1 * query_imp_exp(df, carrier, country, 'exports')).reset_index() +df_exp_x = df_exp_x[df_exp_x[country] != 0] +df_exp_x = df_exp_x.pivot_table(index="countries", values=country, columns="year") +df_exp_x.index.name = 'Annual export volume [TWh]' fig = px.bar( - df_imp_exp, + pd.concat([df_imp_x.T, df_exp_x.T]), title=f"Imports / Exports for {country} for {carrier} [TWh]", text_auto=".2s" ) fig.update_traces(hovertemplate="%{y:,.0f}") -fig.update_yaxes(title_text='Annual exchange volume [TWh]') -fig.update_xaxes(title_text='Countries') -fig.update_layout(hovermode="x unified", +fig.update_yaxes(title_text='Annual exchange volume [TWh]', zeroline=True, zerolinewidth=3, zerolinecolor='black') +fig.update_xaxes(title_text='') +fig.update_layout(hovermode="closest", legend_title_text='Exchange') st.plotly_chart( @@ -74,12 +77,22 @@ def query_imp_exp(df, carriers, country, year, imports_exports): , use_container_width=True ) -df_imp_exp_ = df_imp_exp.drop(df_imp_exp.query('Imports == 0 and Exports ==0').index) -df_imp_exp_.rename(mapper=lambda x: x + " [TWh]", axis=1, inplace=True) - -st.subheader(f"Annual {carrier} exchange volumes of {country} for {year} ") +total_imp = (df_imp_x.sum()) +try: + df_imp_x.loc['Total'] = total_imp +except ValueError: + pass +st.dataframe(df_imp_x + .style + .format(precision=2, thousands=",", decimal='.'), + use_container_width=True) -st.dataframe(df_imp_exp_ +total_exp = (df_exp_x.sum()) +try: + df_exp_x.loc['Total'] = total_exp +except ValueError: + pass +st.dataframe(df_exp_x .style .format(precision=2, thousands=",", decimal='.'), use_container_width=True) diff --git a/app/pages/4Balancing.py b/app/pages/4Balancing.py index 607ce081b..f41a287e2 100644 --- a/app/pages/4Balancing.py +++ b/app/pages/4Balancing.py @@ -78,13 +78,10 @@ def get_df(scenario, mode): fig.update_layout(hovermode="x unified", legend_title_text='Technologies') -st.plotly_chart( - fig - # , use_container_width=True -) +st.plotly_chart(fig, use_container_width=True) # %% -st.header("Actual annual energy output per technology") +st.header("Annual energy output per technology") data2 = get_df(scenario, "supply") df2 = data2.copy() @@ -95,10 +92,8 @@ def get_df(scenario, mode): .query("carrier == @technology") .drop(columns=['carrier']) .set_index('country') - .rename(columns=lambda x: x + ' [GWh]') ) - -st.write("Energy output by country") +df2.index.name = "Energy output [GWh]" fig_bar = px.bar( df2, @@ -113,12 +108,9 @@ def get_df(scenario, mode): fig_bar.update_layout(hovermode="x unified", legend_title_text='Technologies') -col1, col2 = st.columns([0.35, 0.6]) -with col1: - st.dataframe(df2.style.format(precision=2, thousands=",", decimal='.'), width=500) -with col2: - st.plotly_chart(fig_bar - , use_container_width=True) +st.plotly_chart(fig_bar, use_container_width=True) + +st.dataframe(df2.style.format(precision=2, thousands=",", decimal='.'), use_container_width=True) # # %% # st.header("Focus on EV batteries (BEVs)") diff --git a/app/pages/5Costs.py b/app/pages/5Costs.py index 0ffe69d76..47c8b82b3 100644 --- a/app/pages/5Costs.py +++ b/app/pages/5Costs.py @@ -30,6 +30,9 @@ def get_data(scenario, path): # %% Cost segment st.header("Cost by unit segment") +st.markdown("* ENTSO-E area includes all modeled countries, so imports and exports = 0.\n" + "* A negative value means that the area is exporting and thus making a profit.") + df_cost_segments = get_data(scenario, "costs_segments.csv").set_index("config") col1, col2 = st.columns([4, 4]) @@ -40,11 +43,10 @@ def get_data(scenario, path): df_cost_segments = df_cost_segments.query("cost_segment in @selected_cost_segment") else: df_cost_segments = df_cost_segments.query("cost_segment != 'Net_Imports'") - st.text("A negative value means that the area is exporting and thus making a profit") + with col2: selected_area = st.selectbox("Choose area :", COSTS_AREA) df_cost_segments = df_cost_segments[df_cost_segments.index.str.endswith(COSTS_AREA[selected_area])] - st.text("tot includes all modeled countries, so imports and exports = 0") df_cost_segments = df_cost_segments.groupby(by="cost/carrier").sum().drop(columns=["cost_segment"]) diff --git a/scripts/graph_extraction_load_st.py b/scripts/graph_extraction_load_st.py index af1dc2fc7..a46a0c639 100644 --- a/scripts/graph_extraction_load_st.py +++ b/scripts/graph_extraction_load_st.py @@ -155,10 +155,6 @@ def load_balancing_supply(config): return pd.read_csv(Path(config["path"]["csvs"], "balancing_supply_countries.csv")) -def load_elec_grid(config): - return pd.read_csv(Path(config["path"]["csvs"], "elec_grid.csv")) - - # generic function for calling costs def _load_costs_year_segment(config, year=None, _countries=None, cost_segment=None): """