Skip to content

Commit

Permalink
Merge pull request #138 from agoenergy/unified_costs_calculation_per_…
Browse files Browse the repository at this point in the history
…dimension

Update cost results presentation
  • Loading branch information
joAschauer authored Nov 27, 2023
2 parents 587b0fd + cd6de8c commit 8bed9d8
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 133 deletions.
60 changes: 60 additions & 0 deletions app/layout_elements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
"""Layout elements that get reused in several tabs."""
import pandas as pd
import streamlit as st

from app.plot_functions import create_bar_chart_costs
from app.ptxboa_functions import config_number_columns


def display_costs(
df_costs: pd.DataFrame, key: str, titlestring: str, key_suffix: str = ""
):
"""Display costs as table and bar chart."""
key_suffix = key_suffix.lower().replace(" ", "_")
st.subheader(titlestring)
c1, c2 = st.columns([1, 5])
with c1:
# filter data:
df_res = df_costs.copy()

# select filter:
show_which_data = st.radio(
"Select elements to display:",
["All", "Manual select"],
index=0,
key=f"show_which_data_{key}_{key_suffix}",
)

# apply filter:
if show_which_data == "Manual select":
ind_select = st.multiselect(
"Select regions:",
df_res.index.values,
default=df_res.index.values,
key=f"select_data_{key}_{key_suffix}",
)
df_res = df_res.loc[ind_select]

# sort:
sort_ascending = st.toggle(
"Sort by total costs?",
value=True,
key=f"sort_data_{key}_{key_suffix}",
)
if sort_ascending:
df_res = df_res.sort_values(["Total"], ascending=True)
with c2:
# create graph:
fig = create_bar_chart_costs(
df_res,
current_selection=st.session_state[key],
)
st.plotly_chart(fig, use_container_width=True)

with st.expander("**Data**"):
column_config = config_number_columns(
df_res, format=f"%.1f {st.session_state['output_unit']}"
)
st.dataframe(df_res, use_container_width=True, column_config=column_config)
return None
8 changes: 6 additions & 2 deletions app/plot_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
import plotly.graph_objects as go
import streamlit as st

from app.ptxboa_functions import remove_subregions, subset_and_pivot_input_data
from app.ptxboa_functions import (
remove_subregions,
select_subregions,
subset_and_pivot_input_data,
)
from ptxboa.api import PtxboaAPI


Expand Down Expand Up @@ -226,7 +230,7 @@ def _choropleth_map_deep_dive_country(
if custom_data_func_kwargs is None:
custom_data_func_kwargs = {}
# subsetting 'df' for the selected deep dive country
df = df.copy().loc[df.index.str.startswith(f"{deep_dive_country} ("), :]
df = select_subregions(df, deep_dive_country)
# need to calculate custom data befor is03166 column is appended.
hover_data = custom_data_func(df, **custom_data_func_kwargs)
# get dataframe with info about iso 3166-2 codes and map them to res_costs
Expand Down
39 changes: 35 additions & 4 deletions app/ptxboa_functions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
"""Utility functions for streamlit app."""
from typing import Literal

import pandas as pd
import streamlit as st
Expand Down Expand Up @@ -83,19 +84,28 @@ def calculate_results_list(
for parameter in parameter_list:
settings2 = settings.copy()
settings2[parameter_to_change] = parameter
res_single = calculate_results_single(api, settings2, user_data=user_data)
res_single = calculate_results_single(
api,
settings2,
user_data=st.session_state["user_changes_df"],
)
res_list.append(res_single)
res_details = pd.concat(res_list)

return aggregate_costs(res_details)
return aggregate_costs(res_details, parameter_to_change)


def aggregate_costs(res_details: pd.DataFrame) -> pd.DataFrame:
def aggregate_costs(
res_details: pd.DataFrame, parameter_to_change: str
) -> pd.DataFrame:
"""Aggregate detailed costs."""
# Exclude levelized costs:
res = res_details.loc[res_details["cost_type"] != "LC"]
res = res.pivot_table(
index="region", columns="process_type", values="values", aggfunc="sum"
index=parameter_to_change,
columns="process_type",
values="values",
aggfunc="sum",
)
# calculate total costs:
res["Total"] = res.sum(axis=1)
Expand Down Expand Up @@ -185,6 +195,27 @@ def remove_subregions(api: PtxboaAPI, df: pd.DataFrame, country_name: str):
return df


def select_subregions(
df: pd.DataFrame, deep_dive_country: Literal["Argentina", "Morocco", "South Africa"]
) -> pd.DataFrame:
"""
Only select rows corresponding to subregions of a deep dive country.
Parameters
----------
df : pd.DataFrame
pandas DataFrame with list of regions as index.
deep_dive_country : str in {"Argentina", "Morocco", "South Africa"}
Returns
-------
pd.DataFrame
"""
df = df.copy().loc[df.index.str.startswith(f"{deep_dive_country} ("), :]
return df


def reset_user_changes():
"""Reset all user changes."""
if (
Expand Down
107 changes: 0 additions & 107 deletions app/tab_compare_costs.py

This file was deleted.

37 changes: 33 additions & 4 deletions app/tab_dashboard.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# -*- coding: utf-8 -*-
"""Content of dashboard tab."""
import pandas as pd
import streamlit as st
from plotly.subplots import make_subplots

from app.layout_elements import display_costs
from app.plot_functions import (
create_bar_chart_costs,
create_box_plot,
plot_costs_on_map,
)
from app.ptxboa_functions import remove_subregions
from ptxboa.api import PtxboaAPI


def _create_infobox(context_data: dict):
Expand All @@ -30,7 +34,14 @@ def write_info(info):
write_info(info4)


def content_dashboard(api, res_costs: dict, context_data: dict):
def content_dashboard(
api: PtxboaAPI,
costs_per_region: pd.DataFrame,
costs_per_scenario: pd.DataFrame,
costs_per_res_gen: pd.DataFrame,
costs_per_chain: pd.DataFrame,
context_data: dict,
):
with st.expander("What is this?"):
st.markdown(
"""
Expand All @@ -39,6 +50,8 @@ def content_dashboard(api, res_costs: dict, context_data: dict):
regional distribution of total costs across supply regions
- a split-up of costs by category for your chosen supply region
- key information on your chosen demand country.
- total cost and cost components for different supply countries, scenarios,
renewable electricity sources and process chains.
Switch to other tabs to explore data and results in more detail!
"""
Expand All @@ -48,14 +61,16 @@ def content_dashboard(api, res_costs: dict, context_data: dict):

with c_1:
fig_map = plot_costs_on_map(
api, res_costs, scope="world", cost_component="Total"
api, costs_per_region, scope="world", cost_component="Total"
)
st.plotly_chart(fig_map, use_container_width=True)

with c_2:
# create box plot and bar plot:
fig1 = create_box_plot(res_costs)
filtered_data = res_costs[res_costs.index == st.session_state["region"]]
fig1 = create_box_plot(costs_per_region)
filtered_data = costs_per_region[
costs_per_region.index == st.session_state["region"]
]
fig2 = create_bar_chart_costs(filtered_data)
doublefig = make_subplots(rows=1, cols=2, shared_yaxes=True)

Expand All @@ -70,3 +85,17 @@ def content_dashboard(api, res_costs: dict, context_data: dict):
st.plotly_chart(doublefig, use_container_width=True)

_create_infobox(context_data)

display_costs(
remove_subregions(api, costs_per_region, st.session_state["country"]),
"region",
"Costs by region:",
)

display_costs(costs_per_scenario, "scenario", "Costs by data scenario:")

display_costs(
costs_per_res_gen, "res_gen", "Costs by renewable electricity source:"
)

display_costs(costs_per_chain, "chain", "Costs by supply chain:")
18 changes: 14 additions & 4 deletions app/tab_deep_dive_countries.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@
import plotly.express as px
import streamlit as st

from app.layout_elements import display_costs
from app.plot_functions import plot_costs_on_map, plot_input_data_on_map
from app.ptxboa_functions import display_and_edit_data_table
from app.ptxboa_functions import display_and_edit_data_table, select_subregions
from ptxboa.api import PtxboaAPI


def content_deep_dive_countries(api: PtxboaAPI, res_costs: pd.DataFrame) -> None:
def content_deep_dive_countries(api: PtxboaAPI, costs_per_region: pd.DataFrame) -> None:
"""Create content for the "costs by region" sheet.
Parameters
----------
api : :class:`~ptxboa.api.PtxboaAPI`
an instance of the api class
res_costs : pd.DataFrame
costs_per_region : pd.DataFrame
Results.
Output
Expand All @@ -41,9 +42,18 @@ def content_deep_dive_countries(api: PtxboaAPI, res_costs: pd.DataFrame) -> None
"Select country:", ["Argentina", "Morocco", "South Africa"], horizontal=True
)

fig_map = plot_costs_on_map(api, res_costs, scope=ddc, cost_component="Total")
fig_map = plot_costs_on_map(
api, costs_per_region, scope=ddc, cost_component="Total"
)
st.plotly_chart(fig_map, use_container_width=True)

display_costs(
select_subregions(costs_per_region, ddc),
key="region",
titlestring="Costs per subregion",
key_suffix=ddc,
)

st.subheader("Full load hours of renewable generation")
input_data = api.get_input_data(st.session_state["scenario"])
# filter data:
Expand Down
Loading

0 comments on commit 8bed9d8

Please sign in to comment.