diff --git a/app/tab_market_scanning.py b/app/tab_market_scanning.py index 14b95828..2cc919a4 100644 --- a/app/tab_market_scanning.py +++ b/app/tab_market_scanning.py @@ -4,11 +4,15 @@ import plotly.express as px import streamlit as st -from app.ptxboa_functions import config_number_columns, remove_subregions +from app.ptxboa_functions import ( + config_number_columns, + prepare_and_download_df_as_excel, + remove_subregions, +) from ptxboa.api import PtxboaAPI -def content_market_scanning(api: PtxboaAPI, res_costs: pd.DataFrame) -> None: +def content_market_scanning(api: PtxboaAPI, res_costs: pd.DataFrame, cd: dict) -> None: """Create content for the "market scanning" sheet. Parameters @@ -17,6 +21,8 @@ def content_market_scanning(api: PtxboaAPI, res_costs: pd.DataFrame) -> None: an instance of the api class res_costs : pd.DataFrame Results. + cd: dict + context data. """ with st.expander("What is this?"): st.markdown( @@ -47,39 +53,195 @@ def content_market_scanning(api: PtxboaAPI, res_costs: pd.DataFrame) -> None: ) # merge costs and distances: - df_plot = pd.DataFrame() - df_plot["total costs"] = res_costs["Total"] - df_plot = df_plot.merge(distances, left_index=True, right_index=True) + df = pd.DataFrame() + df["total costs"] = res_costs["Total"] + df = df.merge(distances, left_index=True, right_index=True) + + # merge RE supply potential from context data: + df = df.merge( + cd["supply"].set_index("country_name")[ + ["re_tech_pot_EWI", "re_tech_pot_PTXAtlas"] + ], + left_index=True, + right_index=True, + how="left", + ) + + # prettify column names: + df.rename( + { + "total costs": f"Total costs ({st.session_state['output_unit']})", + "shipping distance": "Shipping distance (km)", + "pipeline distance": "Pipeline distance (km)", + "re_tech_pot_EWI": "RE technical potential (EWI) (TWh/a)", + "re_tech_pot_PTXAtlas": "RE technical potential (PTX Atlas) (TWh/a)", + }, + inplace=True, + axis=1, + ) + + # replace nan entries: + df = df.replace({"no potential": None, "no analysis ": None}) + df = df.astype(float) # do not show subregions: - df_plot = remove_subregions(api, df_plot, st.session_state["country"]) + df = remove_subregions(api, df, st.session_state["country"]) + + with st.container(border=True): + st.markdown( + "### Costs and transportation distances from different supply regions" + f" to {st.session_state['country']}" + ) + c1, c2 = st.columns(2) + with c1: + # select which distance to show: + selected_distance = st.radio( + "Select parameter to show on horizontal axis:", + ["Shipping distance (km)", "Pipeline distance (km)"], + key="selected_distance_supply_regions", + ) - # create plot:st.session_state - [c1, c2] = st.columns([1, 5]) - with c1: - # select which distance to show: + with c2: + # select parameter for marker size: + parameter_for_marker_size = st.radio( + "Select parameter to scale marker size:", + [ + "RE technical potential (EWI) (TWh/a)", + "RE technical potential (PTX Atlas) (TWh/a)", + "None", + ], + ) + + # create plot: + df_plot = df.copy().round(0) + + # distinguish between selected region and others: + df_plot["category"] = "other regions" + df_plot.at[st.session_state["region"], "category"] = "selected supply region" + + if parameter_for_marker_size == "None": + fig = px.scatter( + df_plot, + x=selected_distance, + y=f"Total costs ({st.session_state['output_unit']})", + color="category", + color_discrete_sequence=["#1A667B", "#D05094"], + text=df_plot.index, + ) + fig.update_traces(textposition="top center") + else: + df_plot = df_plot.loc[df_plot[parameter_for_marker_size] > 0] + fig = px.scatter( + df_plot, + x=selected_distance, + y=f"Total costs ({st.session_state['output_unit']})", + size=parameter_for_marker_size, + size_max=50, + color="category", + color_discrete_sequence=["#1A667B", "#D05094"], + text=df_plot.index, + ) + fig.update_traces(textposition="top center") + + st.plotly_chart(fig, use_container_width=True) + + # show data in tabular form: + with st.expander("**Data**"): + column_config = config_number_columns(df, format="%.0f") + st.dataframe( + df, + use_container_width=True, + column_config=column_config, + ) + + fn = "market_scanning_supply_regions" + prepare_and_download_df_as_excel(df, filename=fn) + + with st.container(border=True): + st.markdown( + f"### Transportation distances from {st.session_state['region']}" + " to different target countries" + ) + + # filter shipping and pipeline distances: + df = input_data.loc[ + ( + input_data["parameter_code"].isin( + ["shipping distance", "pipeline distance"] + ) + ) + & (input_data["source_region_code"] == st.session_state["region"]), + ["target_country_code", "parameter_code", "value"], + ] + df = df.pivot_table( + index="target_country_code", + columns="parameter_code", + values="value", + aggfunc="sum", + ) + + # merge H2 demand from context data: + + # H2 demand data hard coded from excel tool. + # TODO: improve data representation in context_data.xlsx + # and take data from there. + df["h2_demand_2030"] = None + + df.at["China", "h2_demand_2030"] = 35 + df.at["France", "h2_demand_2030"] = None + df.at["Germany", "h2_demand_2030"] = 3 + df.at["India", "h2_demand_2030"] = 10 + df.at["Japan", "h2_demand_2030"] = 3 + df.at["Netherlands", "h2_demand_2030"] = None + df.at["South Korea", "h2_demand_2030"] = 2 + df.at["Spain", "h2_demand_2030"] = None + df.at["USA", "h2_demand_2030"] = 10 + + # EU data is missing completely in context_data.xlsx: + df.at["EU", "shipping distance"] = 1104 + df.at["EU", "pipeline distance"] = 2000 + df.at["EU", "h2_demand_2030"] = 20 + + df["h2_demand_2030"] = df["h2_demand_2030"].astype(float) + + # prettify column names: + df.rename( + { + "shipping distance": "Shipping distance (km)", + "pipeline distance": "Pipeline distance (km)", + "h2_demand_2030": "Projected H2 demand in 2030 (Mt/a)", + }, + inplace=True, + axis=1, + ) + + # select parameter to display on x axis: selected_distance = st.radio( - "Select parameter:", - ["shipping distance", "pipeline distance"], + "Select parameter to show on horizontal axis:", + ["Shipping distance (km)", "Pipeline distance (km)"], + key="selected_distance_target_countries", ) - with c2: + + # create plot: + df_plot = df.copy().round(0) + + # distinguish between selected region and others: + df_plot["category"] = "other countries" + df_plot.at[st.session_state["country"], "category"] = "selected target country" + fig = px.scatter( df_plot, x=selected_distance, - y="total costs", - title="Costs and transportation distances", - height=600, - ) - # Add text above markers - fig.update_traces( + y="Projected H2 demand in 2030 (Mt/a)", + color="category", + color_discrete_sequence=["#1A667B", "#D05094"], text=df_plot.index, - textposition="top center", - mode="markers+text", ) + fig.update_traces(textposition="top center") - st.plotly_chart(fig) + st.plotly_chart(fig, use_container_width=True) - # show data in tabular form: - st.markdown("**Data:**") - column_config = config_number_columns(df_plot, format="%.1f") - st.dataframe(df_plot, use_container_width=True, column_config=column_config) + with st.expander("**Data**"): + st.dataframe(df, use_container_width=True) + fn = "market_scanning_target_countries" + prepare_and_download_df_as_excel(df, filename=fn) diff --git a/ptxboa_streamlit.py b/ptxboa_streamlit.py index f40b7842..2ee62b17 100644 --- a/ptxboa_streamlit.py +++ b/ptxboa_streamlit.py @@ -1,5 +1,10 @@ # -*- coding: utf-8 -*- -"""Mockup streamlit app.""" +""" +PtX BOA streamlit app, main file. + +Execution: +>>> streamlit run ptxboa_streamlit.py +""" # TODO how do I use the treamlit logger? import logging @@ -39,7 +44,7 @@ logger.addHandler(log_handler) -logger.info("Updating app...") +logger.debug("Updating app...") # app layout: @@ -191,7 +196,7 @@ ) if st.session_state[st.session_state["tab_key"]] == "Market scanning": - content_market_scanning(api, costs_per_region) + content_market_scanning(api, costs_per_region, cd) if st.session_state[st.session_state["tab_key"]] == "Input data": content_input_data(api)