Skip to content

Commit

Permalink
Merge branch 'develop' into api-optimize-user-data-optional
Browse files Browse the repository at this point in the history
  • Loading branch information
wingechr committed May 15, 2024
2 parents 24fedc3 + 56895ff commit d645e75
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 63 deletions.
4 changes: 3 additions & 1 deletion app/layout_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,9 @@ def display_and_edit_input_data(
missing_index_name = "parameter_code"
missing_index_value = "interest rate"
column_config = {
c: st.column_config.NumberColumn(format="%.3f", min_value=0, max_value=1)
c: st.column_config.NumberColumn(
format="%.2f %%", min_value=0, max_value=100
)
for c in df.columns
}

Expand Down
17 changes: 12 additions & 5 deletions app/plot_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ def plot_input_data_on_map(
"""
input_data = get_data_type_from_input_data(api, data_type=data_type, scope=None)

units = {"CAPEX": "USD/kW", "full load hours": "h/a", "interest rate": ""}
units = {"CAPEX": "USD/kW", "full load hours": "h/a", "interest rate": "%"}

if data_type == "interest rate":
assert color_col == "interest rate"
custom_data_func_kwargs = {"float_precision": 3}
custom_data_func_kwargs = {"float_precision": 2}
if data_type == "full load hours":
assert color_col in [
"PV tilted",
Expand All @@ -155,6 +155,10 @@ def plot_input_data_on_map(
custom_data_func_kwargs["data_type"] = data_type
custom_data_func_kwargs["map_variable"] = color_col

# transform data to % for interest rate
if data_type == "interest rate":
input_data = input_data * 100

if scope == "world":
# Create a choropleth world map:
fig = _choropleth_map_world(
Expand Down Expand Up @@ -310,15 +314,18 @@ def _make_inputs_hoverdata(df, data_type, map_variable, unit, float_precision):
custom_hover_data = []
if data_type == "interest rate":
for idx, row in df.iterrows():
hover = f"<b>{idx} | {data_type} </b><br><br>{row['interest rate']}"
hover = (
f"<b>{idx} | {data_type} </b><br><br>"
f"{row['interest rate']:.{float_precision}f} {unit}"
)
custom_hover_data.append(hover)
else:
for idx, row in df.iterrows():
hover = f"<b>{idx} | {data_type} </b><br>"
for i, v in zip(row.index, row):
hover += f"<br><b>{i}</b>: {v:.{float_precision}f}{unit}"
hover += f"<br><b>{i}</b>: {v:.{float_precision}f} {unit}"
if i == map_variable:
hover += " (displayed on map)"
hover += " ← <i>displayed on map</i>"
custom_hover_data.append(hover)
return [custom_hover_data]

Expand Down
9 changes: 8 additions & 1 deletion app/ptxboa_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ def get_data_type_from_input_data(
if scope in ["Argentina", "Morocco", "South Africa"]:
df = select_subregions(df, scope)

# transform data to match unit [%] for 'interest_rate' and 'efficieny'
if data_type == "interest rate":
df = df * 100

if "efficiency" in df.columns:
df["efficiency"] = df["efficiency"] * 100

return df


Expand Down Expand Up @@ -526,7 +533,7 @@ def get_column_config() -> dict:
"CAPEX": st.column_config.NumberColumn(format="%.0f USD/kW", min_value=0),
"OPEX (fix)": st.column_config.NumberColumn(format="%.0f USD/kW", min_value=0),
"efficiency": st.column_config.NumberColumn(
format="%.2f", min_value=0, max_value=1
format="%.2f %%", min_value=0, max_value=100
),
"lifetime / amortization period": st.column_config.NumberColumn(
format="%.0f a",
Expand Down
10 changes: 8 additions & 2 deletions app/tab_costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ def content_costs(
with st.container(border=True):
display_costs(
remove_subregions(api, costs_per_region, st.session_state["country"]),
remove_subregions(
api, costs_per_region_without_user_changes, st.session_state["country"]
(
remove_subregions(
api,
costs_per_region_without_user_changes,
st.session_state["country"],
)
if st.session_state["user_changes_df"] is not None
else None
),
"region",
"Costs by region",
Expand Down
6 changes: 5 additions & 1 deletion app/tab_deep_dive_countries.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ def content_deep_dive_countries(

display_costs(
select_subregions(costs_per_region, ddc),
select_subregions(costs_per_region_without_user_changes, ddc),
(
select_subregions(costs_per_region_without_user_changes, ddc)
if st.session_state["user_changes_df"] is not None
else None
),
key="region",
titlestring="Costs per subregion",
key_suffix=ddc,
Expand Down
2 changes: 1 addition & 1 deletion app/tab_input_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def content_input_data(api: PtxboaAPI) -> None:
if data_selection == "full load hours":
ylabel = "full load hours (h/a)"
if data_selection == "interest rate":
ylabel = "interest rate (per unit)"
ylabel = "interest rate (%)"
fig = px.box(df)
fig.update_layout(xaxis_title=None, yaxis_title=ylabel)
st.plotly_chart(fig, use_container_width=True)
Expand Down
16 changes: 15 additions & 1 deletion app/user_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ def register_user_changes(
# Replace the 'id' values with the corresponding index elements from df_tab
res[index] = res[index].map(lambda x: df_tab.index[x])

# convert the interest rate from [%] to [decimals]
res["value"] = res["value"].astype(float)
for param_code in ["interest rate", "efficiency"]:
res.loc[res["parameter_code"] == param_code, "value"] = (
res.loc[res["parameter_code"] == param_code, "value"] / 100
)

if st.session_state["user_changes_df"] is None:
st.session_state["user_changes_df"] = pd.DataFrame(
columns=[
Expand All @@ -70,7 +77,7 @@ def register_user_changes(

# only track the last changes if a duplicate entry is found.
st.session_state["user_changes_df"] = pd.concat(
[st.session_state["user_changes_df"], res]
[st.session_state["user_changes_df"].astype(res.dtypes), res]
).drop_duplicates(
subset=[
"source_region_code",
Expand All @@ -95,6 +102,13 @@ def display_user_changes(api):
"""Display input data changes made by user."""
if st.session_state["user_changes_df"] is not None:
df = st.session_state["user_changes_df"].copy()

# convert the values for 'interest rate' and 'efficiency' from [decimals] to [%]
for param_code in ["interest rate", "efficiency"]:
df.loc[df["parameter_code"] == param_code, "value"] = (
df.loc[df["parameter_code"] == param_code, "value"] * 100
)

parameters = api.get_dimension("parameter")
df["Unit"] = df["parameter_code"].map(
pd.Series(parameters["unit"].tolist(), index=parameters["parameter_name"])
Expand Down
131 changes: 80 additions & 51 deletions ptxboa_streamlit.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,14 @@
if st.session_state["tab_key"] not in st.session_state:
st.session_state[st.session_state["tab_key"]] = "Costs"

sac.tabs(
[sac.TabsItem(label=i, icon=tabs_icons.get(i, None)) for i in tabs],
sac.buttons(
[sac.ButtonsItem(label=i, icon=tabs_icons.get(i, None)) for i in tabs],
index=tabs.index(st.session_state[st.session_state["tab_key"]]),
format_func="title",
align="center",
key=st.session_state["tab_key"],
)

st.divider()
# create sidebar:
make_sidebar(api)

Expand All @@ -169,56 +169,85 @@
colors = pd.read_csv("data/Agora_Industry_Colours.csv")
st.session_state["colors"] = colors["Hex Code"].to_list()

# calculate results over different data dimensions:
costs_per_region = calculate_results_list(
api, parameter_to_change="region", parameter_list=None
)
costs_per_scenario = calculate_results_list(
api,
parameter_to_change="scenario",
parameter_list=None,
)
costs_per_res_gen = calculate_results_list(
api,
parameter_to_change="res_gen",
# TODO: here we remove PV tracking manually, this needs to be fixed in data
parameter_list=[
x for x in api.get_dimension("res_gen").index.to_list() if x != "PV tracking"
],
)
costs_per_chain = calculate_results_list(
api,
parameter_to_change="chain",
parameter_list=None,
override_session_state={"output_unit": "USD/MWh"},
)
if st.session_state[st.session_state["tab_key"]] in [
"Costs",
"Market scanning",
"Input data",
"Deep-dive countries",
]:
# calculate results over different data dimensions:
costs_per_region = calculate_results_list(
api, parameter_to_change="region", parameter_list=None
)
costs_per_scenario = calculate_results_list(
api,
parameter_to_change="scenario",
parameter_list=None,
)
costs_per_res_gen = calculate_results_list(
api,
parameter_to_change="res_gen",
# TODO: here we remove PV tracking manually, this needs to be fixed in data
parameter_list=[
x
for x in api.get_dimension("res_gen").index.to_list()
if x != "PV tracking"
],
)
costs_per_chain = calculate_results_list(
api,
parameter_to_change="chain",
parameter_list=None,
override_session_state={"output_unit": "USD/MWh"},
)

# calculate results over different data dimensions (without user changes):
costs_per_region_without_user_changes = calculate_results_list(
api, parameter_to_change="region", parameter_list=None, apply_user_data=False
)
costs_per_scenario_without_user_changes = calculate_results_list(
api, parameter_to_change="scenario", parameter_list=None, apply_user_data=False
)
costs_per_res_gen_without_user_changes = calculate_results_list(
api,
parameter_to_change="res_gen",
# TODO: here we remove PV tracking manually, this needs to be fixed in data
parameter_list=[
x for x in api.get_dimension("res_gen").index.to_list() if x != "PV tracking"
],
apply_user_data=False,
)
costs_per_chain_without_user_changes = calculate_results_list(
api,
parameter_to_change="chain",
parameter_list=None,
override_session_state={"output_unit": "USD/MWh"},
apply_user_data=False,
)
if st.session_state["user_changes_df"] is not None:
# calculate results over different data dimensions (without user changes):
costs_per_region_without_user_changes = calculate_results_list(
api,
parameter_to_change="region",
parameter_list=None,
apply_user_data=False,
)
costs_per_scenario_without_user_changes = calculate_results_list(
api,
parameter_to_change="scenario",
parameter_list=None,
apply_user_data=False,
)
costs_per_res_gen_without_user_changes = calculate_results_list(
api,
parameter_to_change="res_gen",
# TODO: here we remove PV tracking manually, this needs to be fixed in data
parameter_list=[
x
for x in api.get_dimension("res_gen").index.to_list()
if x != "PV tracking"
],
apply_user_data=False,
)
costs_per_chain_without_user_changes = calculate_results_list(
api,
parameter_to_change="chain",
parameter_list=None,
override_session_state={"output_unit": "USD/MWh"},
apply_user_data=False,
)
else:
costs_per_region_without_user_changes = None
costs_per_scenario_without_user_changes = None
costs_per_res_gen_without_user_changes = None
costs_per_chain_without_user_changes = None

# import context data:
cd = load_context_data()
if st.session_state[st.session_state["tab_key"]] in [
"Country fact sheets",
"Certification schemes",
"Sustainability",
"Literature",
"Market scanning",
]:
# import context data:
cd = load_context_data()

# costs:
if st.session_state[st.session_state["tab_key"]] == "Costs":
Expand Down
27 changes: 27 additions & 0 deletions tests/test_ptxboa_streamlit.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,30 @@ def running_app():
def test_app_smoke(running_app):
"""Test if the app starts up without errors."""
assert not running_app.exception


@pytest.fixture(
params=(
"Info",
"Costs",
"Market scanning",
"Input data",
"Deep-dive countries",
"Country fact sheets",
"Certification schemes",
"Sustainability",
"Literature",
"Optimization",
)
)
def running_app_on_tab(request):
tab = request.param
at = AppTest.from_file("ptxboa_streamlit.py")
at.session_state["tab_key"] = "tab_key_0"
at.session_state[at.session_state["tab_key"]] = tab
at.run(timeout=60)
return at


def test_tabs_smoke(running_app_on_tab):
assert not running_app_on_tab.exception

0 comments on commit d645e75

Please sign in to comment.