From 3c912ea0126e288893b94fb5c6b4dcf94bb6cc5b Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 14:51:57 +0100 Subject: [PATCH 1/8] add excel download button below cost results dataframes --- app/excel_download.py | 56 ++++++++++++++++++++++++++++++++++++++++++ app/layout_elements.py | 4 +++ requirements.txt | 1 + 3 files changed, 61 insertions(+) create mode 100644 app/excel_download.py diff --git a/app/excel_download.py b/app/excel_download.py new file mode 100644 index 00000000..81510fa7 --- /dev/null +++ b/app/excel_download.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +"""Utility functions to download a pd.DataFrame as Excel file with streamlit.""" +from io import BytesIO + +import pandas as pd +import streamlit as st + +st.cache_data() + + +def prepare_df_as_excel_stream(df: pd.DataFrame) -> bytes: + """ + Convert a Dataframe to excel bytes stream. + + Parameters + ---------- + df : pd.DataFrame + _description_ + + Returns + ------- + pd.DataFrame + _description_ + """ + output = BytesIO() + writer = pd.ExcelWriter(output, engine="xlsxwriter") + df.to_excel(writer, index=True, sheet_name="Data") + writer.close() + return output.getvalue() + + +def prepare_and_download_df_as_excel(df: pd.DataFrame, filename: str): + """ + Prepare a bytes stream and add streamlit download button. + + https://stackoverflow.com/a/70120061 + + Parameters + ---------- + df : pd:dataFrame + filename : str + filename will be appended with ".xlsx" + + Returns + ------- + None + """ + excel_stream = prepare_df_as_excel_stream(df) + + st.download_button( + label="Download Table as Excel", + data=excel_stream, + file_name=f"{filename}.xlsx", + help="Click to download this Table as Excel File.", + ) + return None diff --git a/app/layout_elements.py b/app/layout_elements.py index 7965da4b..72d5430d 100644 --- a/app/layout_elements.py +++ b/app/layout_elements.py @@ -3,6 +3,7 @@ import pandas as pd import streamlit as st +from app.excel_download import prepare_and_download_df_as_excel from app.plot_functions import create_bar_chart_costs from app.ptxboa_functions import config_number_columns @@ -82,6 +83,9 @@ def display_costs( with st.expander("**Data**"): column_config = config_number_columns(df_res, format=f"%.1f {output_unit}") st.dataframe(df_res, use_container_width=True, column_config=column_config) + fn = f"costs_per_{key}_{key_suffix}".strip("_") + prepare_and_download_df_as_excel(df_res, filename=fn) + return None diff --git a/requirements.txt b/requirements.txt index 3f3aaf08..1f814610 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ streamlit>=1.29 openpyxl~=3.1 plotly~=5.16 streamlit-antd-components +XlsxWriter From 1c5ec857b885e1a3336c854cb693dddc84ab8450 Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 14:54:34 +0100 Subject: [PATCH 2/8] move apply changes button above table --- app/ptxboa_functions.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/ptxboa_functions.py b/app/ptxboa_functions.py index eeea0227..eb1d57ff 100644 --- a/app/ptxboa_functions.py +++ b/app/ptxboa_functions.py @@ -655,14 +655,6 @@ def display_and_edit_input_data( ) ) - df = st.data_editor( - df, - use_container_width=True, - key=editor_key, - num_rows="fixed", - disabled=[index], - column_config=column_config, - ) st.form_submit_button( "Apply Changes", type="primary", @@ -679,6 +671,16 @@ def display_and_edit_input_data( "editor_key": editor_key, }, ) + + df = st.data_editor( + df, + use_container_width=True, + key=editor_key, + num_rows="fixed", + disabled=[index], + column_config=column_config, + ) + else: st.dataframe( df, From b12e15e4621c6f4c6b1bbea5594f8af95bc4966d Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 14:59:57 +0100 Subject: [PATCH 3/8] remove border around data editor form --- app/ptxboa_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ptxboa_functions.py b/app/ptxboa_functions.py index eb1d57ff..6e3408c4 100644 --- a/app/ptxboa_functions.py +++ b/app/ptxboa_functions.py @@ -647,7 +647,7 @@ def display_and_edit_input_data( st.session_state[f"{key}_number"] = 0 editor_key = f"{key}_{st.session_state[f'{key}_number']}" - with st.form(key=f"{key}_form"): + with st.form(key=f"{key}_form", border=False): st.info( ( "You can edit data directly in the table. When done, click the " From 070fe8c51171f4f190adc3a866658f9e79ce2a59 Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 15:28:50 +0100 Subject: [PATCH 4/8] add excel download button to input data tables --- app/ptxboa_functions.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/ptxboa_functions.py b/app/ptxboa_functions.py index 6e3408c4..c00cd80b 100644 --- a/app/ptxboa_functions.py +++ b/app/ptxboa_functions.py @@ -7,6 +7,7 @@ import pandas as pd import streamlit as st +from app.excel_download import prepare_and_download_df_as_excel from ptxboa.api import PtxboaAPI @@ -687,6 +688,12 @@ def display_and_edit_input_data( use_container_width=True, column_config=column_config, ) + + scenario = st.session_state["scenario"].lower() + scenario = scenario.replace(")", "").replace("(", "") + fn = f"{key}_{scenario}".replace(" ", "_") + prepare_and_download_df_as_excel(df, filename=fn) + return df From 9737d6545a6e32906dc2ff6ca08e99c9c2f4d8e9 Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 15:29:52 +0100 Subject: [PATCH 5/8] rename input data editors session state keys --- app/tab_deep_dive_countries.py | 2 +- app/tab_input_data.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/tab_deep_dive_countries.py b/app/tab_deep_dive_countries.py index 92bccbe8..556d002e 100644 --- a/app/tab_deep_dive_countries.py +++ b/app/tab_deep_dive_countries.py @@ -87,7 +87,7 @@ def content_deep_dive_countries( api, data_type="full load hours", scope=ddc, - key="input_data_editor_full_load_hours_ddc", + key=f"input_data_full_load_hours_{ddc.replace(' ', '_').lower()}", ) with c_0_1: diff --git a/app/tab_input_data.py b/app/tab_input_data.py index c9c66729..40de3a88 100644 --- a/app/tab_input_data.py +++ b/app/tab_input_data.py @@ -65,7 +65,7 @@ def content_input_data(api: PtxboaAPI) -> None: api, data_type=data_selection, scope="world", - key=f"input_data_editor_{data_selection}", + key=f"input_data_{data_selection}", ) with c_0_1: st.markdown("**Regional Distribution**") @@ -81,21 +81,21 @@ def content_input_data(api: PtxboaAPI) -> None: api, data_type="electricity_generation", scope=None, - key="input_data_editor_electricity_generation", + key="input_data_electricity_generation", ) with st.expander("**Electrolysis and derivate production**"): display_and_edit_input_data( api, data_type="conversion_processes", scope=None, - key="input_data_editor_conversion_processes", + key="input_data_conversion_processes", ) with st.expander("**Transportation (ships and pipelines)**"): display_and_edit_input_data( api, data_type="transportation_processes", scope=None, - key="input_data_editor_transportation_processes", + key="input_data_transportation_processes", ) with st.expander( "**Transportation (compression, liquefication and reconversion)**" @@ -104,12 +104,12 @@ def content_input_data(api: PtxboaAPI) -> None: api, data_type="reconversion_processes", scope=None, - key="input_data_editor_reconversion_processes", + key="input_data_reconversion_processes", ) with st.expander("**Specific costs for materials and energy carriers**"): display_and_edit_input_data( api, data_type="specific_costs", scope=None, - key="input_data_editor_specific_costs", + key="input_data_specific_costs", ) From 93c5b2a6e52110863cbd15fd400ad9abaf678967 Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Wed, 13 Dec 2023 15:34:03 +0100 Subject: [PATCH 6/8] strip docstring --- app/excel_download.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/app/excel_download.py b/app/excel_download.py index 81510fa7..457c1080 100644 --- a/app/excel_download.py +++ b/app/excel_download.py @@ -9,19 +9,7 @@ def prepare_df_as_excel_stream(df: pd.DataFrame) -> bytes: - """ - Convert a Dataframe to excel bytes stream. - - Parameters - ---------- - df : pd.DataFrame - _description_ - - Returns - ------- - pd.DataFrame - _description_ - """ + """Convert a Dataframe to excel bytes stream.""" output = BytesIO() writer = pd.ExcelWriter(output, engine="xlsxwriter") df.to_excel(writer, index=True, sheet_name="Data") From 9697c03043143107ea52445559d5a4fc7b6f2452 Mon Sep 17 00:00:00 2001 From: Johannes Aschauer <38501948+joAschauer@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:29:18 +0100 Subject: [PATCH 7/8] add to filename which data is downloaded Co-authored-by: Markus Haller --- app/layout_elements.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/layout_elements.py b/app/layout_elements.py index 72d5430d..918c00ad 100644 --- a/app/layout_elements.py +++ b/app/layout_elements.py @@ -84,6 +84,8 @@ def display_costs( column_config = config_number_columns(df_res, format=f"%.1f {output_unit}") st.dataframe(df_res, use_container_width=True, column_config=column_config) fn = f"costs_per_{key}_{key_suffix}".strip("_") + if st.session_state["user_changes_df"] is not None: + fn = f"{fn}_{select_data}".replace(" ", "_") prepare_and_download_df_as_excel(df_res, filename=fn) return None From 67e99b54e83c8a8447855196b1b3dbcfc6c88110 Mon Sep 17 00:00:00 2001 From: "j.aschauer" Date: Thu, 14 Dec 2023 09:34:19 +0100 Subject: [PATCH 8/8] make filename lowercase --- app/layout_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/layout_elements.py b/app/layout_elements.py index 918c00ad..8b2e68c2 100644 --- a/app/layout_elements.py +++ b/app/layout_elements.py @@ -85,7 +85,7 @@ def display_costs( st.dataframe(df_res, use_container_width=True, column_config=column_config) fn = f"costs_per_{key}_{key_suffix}".strip("_") if st.session_state["user_changes_df"] is not None: - fn = f"{fn}_{select_data}".replace(" ", "_") + fn = f"{fn}_{select_data}".lower().replace(" ", "_") prepare_and_download_df_as_excel(df_res, filename=fn) return None