Spaces:
Sleeping
Sleeping
| """ | |
| Data export module for HVAC Load Calculator. | |
| This module provides functionality for exporting calculation results. | |
| """ | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| from typing import Dict, List, Any, Optional, Tuple | |
| import json | |
| import os | |
| import base64 | |
| import io | |
| from datetime import datetime | |
| import xlsxwriter | |
| class DataExport: | |
| """Class for data export functionality.""" | |
| def export_to_csv(data: Dict[str, Any], file_path: str = None) -> Optional[str]: | |
| """ | |
| Export data to CSV format. | |
| Args: | |
| data: Dictionary with data to export | |
| file_path: Optional path to save the CSV file | |
| Returns: | |
| CSV string if file_path is None, otherwise None | |
| """ | |
| try: | |
| # Create DataFrame from data | |
| df = pd.DataFrame(data) | |
| # Convert to CSV | |
| csv_data = df.to_csv(index=False) | |
| # Save to file if path provided | |
| if file_path: | |
| df.to_csv(file_path, index=False) | |
| return None | |
| # Return CSV string if no path provided | |
| return csv_data | |
| except Exception as e: | |
| st.error(f"Error exporting to CSV: {e}") | |
| return None | |
| def export_to_excel(data_dict: Dict[str, pd.DataFrame], file_path: str = None) -> Optional[bytes]: | |
| """ | |
| Export data to Excel format. | |
| Args: | |
| data_dict: Dictionary with sheet names and DataFrames | |
| file_path: Optional path to save the Excel file | |
| Returns: | |
| Excel bytes if file_path is None, otherwise None | |
| """ | |
| try: | |
| # Create Excel file in memory or on disk | |
| if file_path: | |
| writer = pd.ExcelWriter(file_path, engine='xlsxwriter') | |
| else: | |
| output = io.BytesIO() | |
| writer = pd.ExcelWriter(output, engine='xlsxwriter') | |
| # Write each DataFrame to a different sheet | |
| for sheet_name, df in data_dict.items(): | |
| df.to_excel(writer, sheet_name=sheet_name, index=False) | |
| # Auto-adjust column widths | |
| worksheet = writer.sheets[sheet_name] | |
| for i, col in enumerate(df.columns): | |
| max_width = max( | |
| df[col].astype(str).map(len).max(), | |
| len(col) | |
| ) + 2 | |
| worksheet.set_column(i, i, max_width) | |
| # Save the Excel file | |
| writer.close() | |
| # Return Excel bytes if no path provided | |
| if not file_path: | |
| output.seek(0) | |
| return output.getvalue() | |
| return None | |
| except Exception as e: | |
| st.error(f"Error exporting to Excel: {e}") | |
| return None | |
| def export_scenario_to_json(scenario: Dict[str, Any], file_path: str = None) -> Optional[str]: | |
| """ | |
| Export scenario data to JSON format. | |
| Args: | |
| scenario: Dictionary with scenario data | |
| file_path: Optional path to save the JSON file | |
| Returns: | |
| JSON string if file_path is None, otherwise None | |
| """ | |
| try: | |
| # Convert to JSON | |
| json_data = json.dumps(scenario, indent=4) | |
| # Save to file if path provided | |
| if file_path: | |
| with open(file_path, "w") as f: | |
| f.write(json_data) | |
| return None | |
| # Return JSON string if no path provided | |
| return json_data | |
| except Exception as e: | |
| st.error(f"Error exporting scenario to JSON: {e}") | |
| return None | |
| def get_download_link(data: Any, filename: str, text: str, mime_type: str = "text/csv") -> str: | |
| """ | |
| Generate a download link for data. | |
| Args: | |
| data: Data to download | |
| filename: Name of the file to download | |
| text: Text to display for the download link | |
| mime_type: MIME type of the file | |
| Returns: | |
| HTML string with download link | |
| """ | |
| if isinstance(data, str): | |
| b64 = base64.b64encode(data.encode()).decode() | |
| else: | |
| b64 = base64.b64encode(data).decode() | |
| href = f'<a href="data:{mime_type};base64,{b64}" download="{filename}">{text}</a>' | |
| return href | |
| def create_cooling_load_dataframes(results: Dict[str, Any]) -> Dict[str, pd.DataFrame]: | |
| """ | |
| Create DataFrames for cooling load results. | |
| Args: | |
| results: Dictionary with calculation results | |
| Returns: | |
| Dictionary with DataFrames for Excel export | |
| """ | |
| dataframes = {} | |
| # Create summary DataFrame | |
| summary_data = { | |
| "Metric": [ | |
| "Total Cooling Load", | |
| "Sensible Cooling Load", | |
| "Latent Cooling Load", | |
| "Cooling Load per Area" | |
| ], | |
| "Value": [ | |
| results["cooling"]["total_load"], | |
| results["cooling"]["sensible_load"], | |
| results["cooling"]["latent_load"], | |
| results["cooling"]["load_per_area"] | |
| ], | |
| "Unit": [ | |
| "kW", | |
| "kW", | |
| "kW", | |
| "W/m²" | |
| ] | |
| } | |
| dataframes["Cooling Summary"] = pd.DataFrame(summary_data) | |
| # Create component breakdown DataFrame | |
| component_data = { | |
| "Component": [ | |
| "Walls", | |
| "Roof", | |
| "Windows", | |
| "Doors", | |
| "People", | |
| "Lighting", | |
| "Equipment", | |
| "Infiltration", | |
| "Ventilation" | |
| ], | |
| "Load (kW)": [ | |
| results["cooling"]["component_loads"]["walls"], | |
| results["cooling"]["component_loads"]["roof"], | |
| results["cooling"]["component_loads"]["windows"], | |
| results["cooling"]["component_loads"]["doors"], | |
| results["cooling"]["component_loads"]["people"], | |
| results["cooling"]["component_loads"]["lighting"], | |
| results["cooling"]["component_loads"]["equipment"], | |
| results["cooling"]["component_loads"]["infiltration"], | |
| results["cooling"]["component_loads"]["ventilation"] | |
| ], | |
| "Percentage (%)": [ | |
| results["cooling"]["component_loads"]["walls"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["roof"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["windows"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["doors"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["people"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["lighting"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["equipment"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["infiltration"] / results["cooling"]["total_load"] * 100, | |
| results["cooling"]["component_loads"]["ventilation"] / results["cooling"]["total_load"] * 100 | |
| ] | |
| } | |
| dataframes["Cooling Components"] = pd.DataFrame(component_data) | |
| # Create detailed loads DataFrames | |
| # Walls | |
| wall_data = [] | |
| for wall in results["cooling"]["detailed_loads"]["walls"]: | |
| wall_data.append({ | |
| "Name": wall["name"], | |
| "Orientation": wall["orientation"], | |
| "Area (m²)": wall["area"], | |
| "U-Value (W/m²·K)": wall["u_value"], | |
| "CLTD (°C)": wall["cltd"], | |
| "Load (kW)": wall["load"] | |
| }) | |
| if wall_data: | |
| dataframes["Cooling Walls"] = pd.DataFrame(wall_data) | |
| # Roofs | |
| roof_data = [] | |
| for roof in results["cooling"]["detailed_loads"]["roofs"]: | |
| roof_data.append({ | |
| "Name": roof["name"], | |
| "Orientation": roof["orientation"], | |
| "Area (m²)": roof["area"], | |
| "U-Value (W/m²·K)": roof["u_value"], | |
| "CLTD (°C)": roof["cltd"], | |
| "Load (kW)": roof["load"] | |
| }) | |
| if roof_data: | |
| dataframes["Cooling Roofs"] = pd.DataFrame(roof_data) | |
| # Windows | |
| window_data = [] | |
| for window in results["cooling"]["detailed_loads"]["windows"]: | |
| window_data.append({ | |
| "Name": window["name"], | |
| "Orientation": window["orientation"], | |
| "Area (m²)": window["area"], | |
| "U-Value (W/m²·K)": window["u_value"], | |
| "SHGC": window["shgc"], | |
| "SCL (W/m²)": window["scl"], | |
| "Load (kW)": window["load"] | |
| }) | |
| if window_data: | |
| dataframes["Cooling Windows"] = pd.DataFrame(window_data) | |
| # Doors | |
| door_data = [] | |
| for door in results["cooling"]["detailed_loads"]["doors"]: | |
| door_data.append({ | |
| "Name": door["name"], | |
| "Orientation": door["orientation"], | |
| "Area (m²)": door["area"], | |
| "U-Value (W/m²·K)": door["u_value"], | |
| "CLTD (°C)": door["cltd"], | |
| "Load (kW)": door["load"] | |
| }) | |
| if door_data: | |
| dataframes["Cooling Doors"] = pd.DataFrame(door_data) | |
| # Internal loads | |
| internal_data = [] | |
| for internal_load in results["cooling"]["detailed_loads"]["internal"]: | |
| internal_data.append({ | |
| "Type": internal_load["type"], | |
| "Name": internal_load["name"], | |
| "Quantity": internal_load["quantity"], | |
| "Heat Gain (W)": internal_load["heat_gain"], | |
| "CLF": internal_load["clf"], | |
| "Load (kW)": internal_load["load"] | |
| }) | |
| if internal_data: | |
| dataframes["Cooling Internal Loads"] = pd.DataFrame(internal_data) | |
| # Infiltration and ventilation | |
| air_data = [ | |
| { | |
| "Type": "Infiltration", | |
| "Air Flow (m³/s)": results["cooling"]["detailed_loads"]["infiltration"]["air_flow"], | |
| "Sensible Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["sensible_load"], | |
| "Latent Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["latent_load"], | |
| "Total Load (kW)": results["cooling"]["detailed_loads"]["infiltration"]["total_load"] | |
| }, | |
| { | |
| "Type": "Ventilation", | |
| "Air Flow (m³/s)": results["cooling"]["detailed_loads"]["ventilation"]["air_flow"], | |
| "Sensible Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["sensible_load"], | |
| "Latent Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["latent_load"], | |
| "Total Load (kW)": results["cooling"]["detailed_loads"]["ventilation"]["total_load"] | |
| } | |
| ] | |
| dataframes["Cooling Air Exchange"] = pd.DataFrame(air_data) | |
| return dataframes | |
| def create_heating_load_dataframes(results: Dict[str, Any]) -> Dict[str, pd.DataFrame]: | |
| """ | |
| Create DataFrames for heating load results. | |
| Args: | |
| results: Dictionary with calculation results | |
| Returns: | |
| Dictionary with DataFrames for Excel export | |
| """ | |
| dataframes = {} | |
| # Create summary DataFrame | |
| summary_data = { | |
| "Metric": [ | |
| "Total Heating Load", | |
| "Heating Load per Area", | |
| "Design Heat Loss", | |
| "Safety Factor" | |
| ], | |
| "Value": [ | |
| results["heating"]["total_load"], | |
| results["heating"]["load_per_area"], | |
| results["heating"]["design_heat_loss"], | |
| results["heating"]["safety_factor"] | |
| ], | |
| "Unit": [ | |
| "kW", | |
| "W/m²", | |
| "kW", | |
| "%" | |
| ] | |
| } | |
| dataframes["Heating Summary"] = pd.DataFrame(summary_data) | |
| # Create component breakdown DataFrame | |
| component_data = { | |
| "Component": [ | |
| "Walls", | |
| "Roof", | |
| "Floor", | |
| "Windows", | |
| "Doors", | |
| "Infiltration", | |
| "Ventilation" | |
| ], | |
| "Load (kW)": [ | |
| results["heating"]["component_loads"]["walls"], | |
| results["heating"]["component_loads"]["roof"], | |
| results["heating"]["component_loads"]["floor"], | |
| results["heating"]["component_loads"]["windows"], | |
| results["heating"]["component_loads"]["doors"], | |
| results["heating"]["component_loads"]["infiltration"], | |
| results["heating"]["component_loads"]["ventilation"] | |
| ], | |
| "Percentage (%)": [ | |
| results["heating"]["component_loads"]["walls"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["roof"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["floor"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["windows"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["doors"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["infiltration"] / results["heating"]["total_load"] * 100, | |
| results["heating"]["component_loads"]["ventilation"] / results["heating"]["total_load"] * 100 | |
| ] | |
| } | |
| dataframes["Heating Components"] = pd.DataFrame(component_data) | |
| # Create detailed loads DataFrames | |
| # Walls | |
| wall_data = [] | |
| for wall in results["heating"]["detailed_loads"]["walls"]: | |
| wall_data.append({ | |
| "Name": wall["name"], | |
| "Orientation": wall["orientation"], | |
| "Area (m²)": wall["area"], | |
| "U-Value (W/m²·K)": wall["u_value"], | |
| "Temperature Difference (°C)": wall["delta_t"], | |
| "Load (kW)": wall["load"] | |
| }) | |
| if wall_data: | |
| dataframes["Heating Walls"] = pd.DataFrame(wall_data) | |
| # Roofs | |
| roof_data = [] | |
| for roof in results["heating"]["detailed_loads"]["roofs"]: | |
| roof_data.append({ | |
| "Name": roof["name"], | |
| "Orientation": roof["orientation"], | |
| "Area (m²)": roof["area"], | |
| "U-Value (W/m²·K)": roof["u_value"], | |
| "Temperature Difference (°C)": roof["delta_t"], | |
| "Load (kW)": roof["load"] | |
| }) | |
| if roof_data: | |
| dataframes["Heating Roofs"] = pd.DataFrame(roof_data) | |
| # Floors | |
| floor_data = [] | |
| for floor in results["heating"]["detailed_loads"]["floors"]: | |
| floor_data.append({ | |
| "Name": floor["name"], | |
| "Area (m²)": floor["area"], | |
| "U-Value (W/m²·K)": floor["u_value"], | |
| "Temperature Difference (°C)": floor["delta_t"], | |
| "Load (kW)": floor["load"] | |
| }) | |
| if floor_data: | |
| dataframes["Heating Floors"] = pd.DataFrame(floor_data) | |
| # Windows | |
| window_data = [] | |
| for window in results["heating"]["detailed_loads"]["windows"]: | |
| window_data.append({ | |
| "Name": window["name"], | |
| "Orientation": window["orientation"], | |
| "Area (m²)": window["area"], | |
| "U-Value (W/m²·K)": window["u_value"], | |
| "Temperature Difference (°C)": window["delta_t"], | |
| "Load (kW)": window["load"] | |
| }) | |
| if window_data: | |
| dataframes["Heating Windows"] = pd.DataFrame(window_data) | |
| # Doors | |
| door_data = [] | |
| for door in results["heating"]["detailed_loads"]["doors"]: | |
| door_data.append({ | |
| "Name": door["name"], | |
| "Orientation": door["orientation"], | |
| "Area (m²)": door["area"], | |
| "U-Value (W/m²·K)": door["u_value"], | |
| "Temperature Difference (°C)": door["delta_t"], | |
| "Load (kW)": door["load"] | |
| }) | |
| if door_data: | |
| dataframes["Heating Doors"] = pd.DataFrame(door_data) | |
| # Infiltration and ventilation | |
| air_data = [ | |
| { | |
| "Type": "Infiltration", | |
| "Air Flow (m³/s)": results["heating"]["detailed_loads"]["infiltration"]["air_flow"], | |
| "Temperature Difference (°C)": results["heating"]["detailed_loads"]["infiltration"]["delta_t"], | |
| "Load (kW)": results["heating"]["detailed_loads"]["infiltration"]["load"] | |
| }, | |
| { | |
| "Type": "Ventilation", | |
| "Air Flow (m³/s)": results["heating"]["detailed_loads"]["ventilation"]["air_flow"], | |
| "Temperature Difference (°C)": results["heating"]["detailed_loads"]["ventilation"]["delta_t"], | |
| "Load (kW)": results["heating"]["detailed_loads"]["ventilation"]["load"] | |
| } | |
| ] | |
| dataframes["Heating Air Exchange"] = pd.DataFrame(air_data) | |
| return dataframes | |
| def display_export_interface(session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display export interface in Streamlit. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.header("Export Results") | |
| # Check if calculations have been performed | |
| if "calculation_results" not in session_state or not session_state["calculation_results"]: | |
| st.warning("No calculation results available. Please run calculations first.") | |
| return | |
| # Create tabs for different export options | |
| tab1, tab2, tab3 = st.tabs(["CSV Export", "Excel Export", "Scenario Export"]) | |
| with tab1: | |
| DataExport._display_csv_export(session_state) | |
| with tab2: | |
| DataExport._display_excel_export(session_state) | |
| with tab3: | |
| DataExport._display_scenario_export(session_state) | |
| def _display_csv_export(session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display CSV export interface. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("CSV Export") | |
| # Get results | |
| results = session_state["calculation_results"] | |
| # Create tabs for cooling and heating loads | |
| tab1, tab2 = st.tabs(["Cooling Load CSV", "Heating Load CSV"]) | |
| with tab1: | |
| # Create cooling load DataFrames | |
| cooling_dfs = DataExport.create_cooling_load_dataframes(results) | |
| # Display and export each DataFrame | |
| for sheet_name, df in cooling_dfs.items(): | |
| st.write(f"### {sheet_name}") | |
| st.dataframe(df) | |
| # Add download button | |
| csv_data = DataExport.export_to_csv(df) | |
| if csv_data: | |
| filename = f"{sheet_name.replace(' ', '_').lower()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" | |
| download_link = DataExport.get_download_link(csv_data, filename, f"Download {sheet_name} CSV") | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| with tab2: | |
| # Create heating load DataFrames | |
| heating_dfs = DataExport.create_heating_load_dataframes(results) | |
| # Display and export each DataFrame | |
| for sheet_name, df in heating_dfs.items(): | |
| st.write(f"### {sheet_name}") | |
| st.dataframe(df) | |
| # Add download button | |
| csv_data = DataExport.export_to_csv(df) | |
| if csv_data: | |
| filename = f"{sheet_name.replace(' ', '_').lower()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" | |
| download_link = DataExport.get_download_link(csv_data, filename, f"Download {sheet_name} CSV") | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| def _display_excel_export(session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display Excel export interface. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Excel Export") | |
| # Get results | |
| results = session_state["calculation_results"] | |
| # Create tabs for cooling, heating, and combined loads | |
| tab1, tab2, tab3 = st.tabs(["Cooling Load Excel", "Heating Load Excel", "Combined Excel"]) | |
| with tab1: | |
| # Create cooling load DataFrames | |
| cooling_dfs = DataExport.create_cooling_load_dataframes(results) | |
| # Add download button | |
| excel_data = DataExport.export_to_excel(cooling_dfs) | |
| if excel_data: | |
| filename = f"cooling_load_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" | |
| download_link = DataExport.get_download_link( | |
| excel_data, | |
| filename, | |
| "Download Cooling Load Excel", | |
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| # Display preview | |
| st.write("### Excel Preview") | |
| st.write("The Excel file will contain the following sheets:") | |
| for sheet_name in cooling_dfs.keys(): | |
| st.write(f"- {sheet_name}") | |
| with tab2: | |
| # Create heating load DataFrames | |
| heating_dfs = DataExport.create_heating_load_dataframes(results) | |
| # Add download button | |
| excel_data = DataExport.export_to_excel(heating_dfs) | |
| if excel_data: | |
| filename = f"heating_load_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" | |
| download_link = DataExport.get_download_link( | |
| excel_data, | |
| filename, | |
| "Download Heating Load Excel", | |
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| # Display preview | |
| st.write("### Excel Preview") | |
| st.write("The Excel file will contain the following sheets:") | |
| for sheet_name in heating_dfs.keys(): | |
| st.write(f"- {sheet_name}") | |
| with tab3: | |
| # Create combined DataFrames | |
| combined_dfs = {} | |
| # Add project information | |
| if "building_info" in session_state: | |
| project_info = [ | |
| {"Parameter": "Project Name", "Value": session_state["building_info"].get("project_name", "")}, | |
| {"Parameter": "Building Name", "Value": session_state["building_info"].get("building_name", "")}, | |
| {"Parameter": "Location", "Value": session_state["building_info"].get("location", "")}, | |
| {"Parameter": "Climate Zone", "Value": session_state["building_info"].get("climate_zone", "")}, | |
| {"Parameter": "Building Type", "Value": session_state["building_info"].get("building_type", "")}, | |
| {"Parameter": "Floor Area", "Value": session_state["building_info"].get("floor_area", "")}, | |
| {"Parameter": "Number of Floors", "Value": session_state["building_info"].get("num_floors", "")}, | |
| {"Parameter": "Floor Height", "Value": session_state["building_info"].get("floor_height", "")}, | |
| {"Parameter": "Orientation", "Value": session_state["building_info"].get("orientation", "")}, | |
| {"Parameter": "Occupancy", "Value": session_state["building_info"].get("occupancy", "")}, | |
| {"Parameter": "Operating Hours", "Value": session_state["building_info"].get("operating_hours", "")}, | |
| {"Parameter": "Date", "Value": datetime.now().strftime("%Y-%m-%d")}, | |
| {"Parameter": "Time", "Value": datetime.now().strftime("%H:%M:%S")} | |
| ] | |
| combined_dfs["Project Information"] = pd.DataFrame(project_info) | |
| # Add cooling load DataFrames | |
| cooling_dfs = DataExport.create_cooling_load_dataframes(results) | |
| for sheet_name, df in cooling_dfs.items(): | |
| combined_dfs[sheet_name] = df | |
| # Add heating load DataFrames | |
| heating_dfs = DataExport.create_heating_load_dataframes(results) | |
| for sheet_name, df in heating_dfs.items(): | |
| combined_dfs[sheet_name] = df | |
| # Add download button | |
| excel_data = DataExport.export_to_excel(combined_dfs) | |
| if excel_data: | |
| filename = f"hvac_load_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" | |
| download_link = DataExport.get_download_link( | |
| excel_data, | |
| filename, | |
| "Download Combined Excel Report", | |
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| # Display preview | |
| st.write("### Excel Preview") | |
| st.write("The Excel file will contain the following sheets:") | |
| for sheet_name in combined_dfs.keys(): | |
| st.write(f"- {sheet_name}") | |
| def _display_scenario_export(session_state: Dict[str, Any]) -> None: | |
| """ | |
| Display scenario export interface. | |
| Args: | |
| session_state: Streamlit session state containing calculation results | |
| """ | |
| st.subheader("Scenario Export") | |
| # Check if there are saved scenarios | |
| if "saved_scenarios" not in session_state or not session_state["saved_scenarios"]: | |
| st.info("No saved scenarios available for export. Save the current results as a scenario to enable export.") | |
| # Add button to save current results as a scenario | |
| scenario_name = st.text_input("Scenario Name", value="Baseline") | |
| if st.button("Save Current Results as Scenario"): | |
| if "saved_scenarios" not in session_state: | |
| session_state["saved_scenarios"] = {} | |
| # Save current results as a scenario | |
| session_state["saved_scenarios"][scenario_name] = { | |
| "results": session_state["calculation_results"], | |
| "building_info": session_state["building_info"], | |
| "components": session_state["components"], | |
| "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| } | |
| st.success(f"Scenario '{scenario_name}' saved successfully!") | |
| st.experimental_rerun() | |
| else: | |
| # Display saved scenarios | |
| st.write("### Saved Scenarios") | |
| # Create selectbox for scenarios | |
| scenario_names = list(session_state["saved_scenarios"].keys()) | |
| selected_scenario = st.selectbox("Select Scenario to Export", scenario_names) | |
| if selected_scenario: | |
| # Get selected scenario | |
| scenario = session_state["saved_scenarios"][selected_scenario] | |
| # Display scenario information | |
| st.write(f"**Scenario:** {selected_scenario}") | |
| st.write(f"**Timestamp:** {scenario['timestamp']}") | |
| # Add download button | |
| json_data = DataExport.export_scenario_to_json(scenario) | |
| if json_data: | |
| filename = f"{selected_scenario.replace(' ', '_').lower()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" | |
| download_link = DataExport.get_download_link( | |
| json_data, | |
| filename, | |
| "Download Scenario JSON", | |
| "application/json" | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| # Add button to export all scenarios | |
| if st.button("Export All Scenarios"): | |
| # Create a zip file in memory | |
| import zipfile | |
| from io import BytesIO | |
| zip_buffer = BytesIO() | |
| with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file: | |
| for scenario_name, scenario in session_state["saved_scenarios"].items(): | |
| # Export scenario to JSON | |
| json_data = DataExport.export_scenario_to_json(scenario) | |
| if json_data: | |
| filename = f"{scenario_name.replace(' ', '_').lower()}.json" | |
| zip_file.writestr(filename, json_data) | |
| # Add download button for zip file | |
| zip_buffer.seek(0) | |
| zip_data = zip_buffer.getvalue() | |
| filename = f"all_scenarios_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip" | |
| download_link = DataExport.get_download_link( | |
| zip_data, | |
| filename, | |
| "Download All Scenarios (ZIP)", | |
| "application/zip" | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| # Create a singleton instance | |
| data_export = DataExport() | |
| # Example usage | |
| if __name__ == "__main__": | |
| import streamlit as st | |
| # Initialize session state with dummy data for testing | |
| if "calculation_results" not in st.session_state: | |
| st.session_state["calculation_results"] = { | |
| "cooling": { | |
| "total_load": 25.5, | |
| "sensible_load": 20.0, | |
| "latent_load": 5.5, | |
| "load_per_area": 85.0, | |
| "component_loads": { | |
| "walls": 5.0, | |
| "roof": 3.0, | |
| "windows": 8.0, | |
| "doors": 1.0, | |
| "people": 2.5, | |
| "lighting": 2.0, | |
| "equipment": 1.5, | |
| "infiltration": 1.0, | |
| "ventilation": 1.5 | |
| }, | |
| "detailed_loads": { | |
| "walls": [ | |
| {"name": "North Wall", "orientation": "NORTH", "area": 20.0, "u_value": 0.5, "cltd": 10.0, "load": 1.0} | |
| ], | |
| "roofs": [ | |
| {"name": "Main Roof", "orientation": "HORIZONTAL", "area": 100.0, "u_value": 0.3, "cltd": 15.0, "load": 3.0} | |
| ], | |
| "windows": [ | |
| {"name": "South Window", "orientation": "SOUTH", "area": 10.0, "u_value": 2.8, "shgc": 0.7, "scl": 800.0, "load": 8.0} | |
| ], | |
| "doors": [ | |
| {"name": "Main Door", "orientation": "NORTH", "area": 2.0, "u_value": 2.0, "cltd": 10.0, "load": 1.0} | |
| ], | |
| "internal": [ | |
| {"type": "People", "name": "Occupants", "quantity": 10, "heat_gain": 250, "clf": 1.0, "load": 2.5}, | |
| {"type": "Lighting", "name": "General Lighting", "quantity": 1000, "heat_gain": 2000, "clf": 1.0, "load": 2.0}, | |
| {"type": "Equipment", "name": "Office Equipment", "quantity": 5, "heat_gain": 300, "clf": 1.0, "load": 1.5} | |
| ], | |
| "infiltration": { | |
| "air_flow": 0.05, | |
| "sensible_load": 0.8, | |
| "latent_load": 0.2, | |
| "total_load": 1.0 | |
| }, | |
| "ventilation": { | |
| "air_flow": 0.1, | |
| "sensible_load": 1.0, | |
| "latent_load": 0.5, | |
| "total_load": 1.5 | |
| } | |
| } | |
| }, | |
| "heating": { | |
| "total_load": 30.0, | |
| "load_per_area": 100.0, | |
| "design_heat_loss": 27.0, | |
| "safety_factor": 10.0, | |
| "component_loads": { | |
| "walls": 8.0, | |
| "roof": 5.0, | |
| "floor": 4.0, | |
| "windows": 7.0, | |
| "doors": 1.0, | |
| "infiltration": 2.0, | |
| "ventilation": 3.0 | |
| }, | |
| "detailed_loads": { | |
| "walls": [ | |
| {"name": "North Wall", "orientation": "NORTH", "area": 20.0, "u_value": 0.5, "delta_t": 25.0, "load": 8.0} | |
| ], | |
| "roofs": [ | |
| {"name": "Main Roof", "orientation": "HORIZONTAL", "area": 100.0, "u_value": 0.3, "delta_t": 25.0, "load": 5.0} | |
| ], | |
| "floors": [ | |
| {"name": "Ground Floor", "area": 100.0, "u_value": 0.4, "delta_t": 10.0, "load": 4.0} | |
| ], | |
| "windows": [ | |
| {"name": "South Window", "orientation": "SOUTH", "area": 10.0, "u_value": 2.8, "delta_t": 25.0, "load": 7.0} | |
| ], | |
| "doors": [ | |
| {"name": "Main Door", "orientation": "NORTH", "area": 2.0, "u_value": 2.0, "delta_t": 25.0, "load": 1.0} | |
| ], | |
| "infiltration": { | |
| "air_flow": 0.05, | |
| "delta_t": 25.0, | |
| "load": 2.0 | |
| }, | |
| "ventilation": { | |
| "air_flow": 0.1, | |
| "delta_t": 25.0, | |
| "load": 3.0 | |
| } | |
| } | |
| } | |
| } | |
| # Display export interface | |
| data_export.display_export_interface(st.session_state) | |