### ===================================================================================================================
### MYVIIA dashboard helper functions
### ===================================================================================================================
# Copyright ©VIIA 2025
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
import streamlit as st
from typing import TYPE_CHECKING, List
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.project_information import fem_get_building_volume
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
from viiapackage import viia_create_project
from viiapackage.project_information.viia_get_total_load_bearing_wall_length import \
viia_get_total_load_bearing_wall_length
from viiapackage.tools.myviia_dashboard.MVDashboardConfig import MYVIIADashboardConfig
### ===================================================================================================================
### 2. Helper functions for the MYVIIA dashboard
### ===================================================================================================================
[docs]def initialise(obj_nr: str, obj_part: str):
"""
Function initialise the session by adding info to the session state of streamlit for later use.
Input:
- obj_nr (str): Name of the object.
- obj_part (str): In case of multiple parts (separate TVA reports will be delivered), select the correct part
for this analysis. On MYVIIA you can see which object parts are available. If the object is not split in
separate parts, this input is not required.
Output:
- The streamlit session state is initialised.
"""
st.session_state['project'] = viia_create_project(project_name=obj_nr, object_part=obj_part)
st.session_state['plots'] = {}
st.session_state['saved_data'] = {}
st.session_state['updated_data'] = {}
[docs]def create_overview(project: ViiaProject, container):
"""
Function to create an overview about the project in the sidebar.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- container (obj): Streamlit sidebar container.
Output:
- Overview is created in the sidebar.
"""
container.info(
f"""
# Overview\n
{project.name} - {project.project_information['objectdeel']}\n
{project.project_information['object_adressen'][0]['straatnaam']}
{project.project_information['object_adressen'][0]['huisnummer']}\n
{project.project_information['object_adressen'][0]['postcode']},
{project.project_information['object_adressen'][0]['plaatsnaam']}\n
{project.project_information['npr_versie']}\n
{project.analysis_type}\n
Cluster: {project.project_information['cluster_nen']}\n
Consequence class: {project.project_information['consequence_class']}\n
Reference period: {project.project_information['reference_period']}\n
PGA: {project.project_information['pga']}g\n
[Box folder]({project.project_information['boxmap']})""")
[docs]def create_3d_plotly_fig(
project: ViiaProject, obj_part: str, load_bearing: bool = False, calculate_volume: bool = False):
"""
Function to create the 3D plotly figure of the model with requested info.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- obj_part (str): Name of the object-part in MYVIIA.
- load_bearing (bool): Select to create the image for the load-bearing walls. Default value is False.
- calculate_volume (bool): Select to create the image for the volume of the model. Default value is False.
Output:
- Returns the 3D plotly Figure object.
"""
if load_bearing:
total_length, lines, fig = viia_get_total_load_bearing_wall_length(project=project, create_plot_objects=True)
fig.update_layout(height=MYVIIADashboardConfig.PIC_HEIGHT)
fig.update_layout(title=f"{project.name} {obj_part} (Total Load Bearing Length: {total_length} m)")
elif calculate_volume:
volume, fig = fem_get_building_volume(project=project, create_plot_object=True)
fig.update_layout(height=MYVIIADashboardConfig.PIC_HEIGHT)
fig.update_layout(title=f"{project.name} {obj_part} (Volume: {volume} m³)")
else:
pic, fig = project.viia_create_plots(
show=False, use_plotly=True, return_figure=True, save_plot=False, alpha=1.0)
fig.update_layout(height=MYVIIADashboardConfig.PIC_HEIGHT)
fig.update_layout(title=project.name + obj_part)
return fig
[docs]def first_non_zero_from_bottom_dict(data: list, keys: List[str]) -> dict:
"""
Function to retrieve the first non-zero value from the bottom of a list of dictionaries for specified keys.
Input:
- data (list): The list of dictionaries containing various attributes.
- keys (list): The list of keys to check for non-zero values.
Output:
- Returns s dictionary with the first non-zero values for each specified key.
"""
results = {key: None for key in keys}
for entry in reversed(data):
for key in keys:
value = entry.get(key)
if value and value != 0 and results[key] is None:
results[key] = value
return results
[docs]def round_values(df):
"""
Function to round numerical values in the DataFrame to the first decimal place and remove any trailing zeros.
Input:
- df (pd.DataFrame): The pandas DataFrame with numerical values to be rounded.
Output:
- Returns the pandas DataFrame with rounded numerical values without trailing zeros.
"""
for col in df.columns:
if col not in ['name', 'date']:
df[col] = df[col].apply(
lambda x: '{:.1f}'.format(x).rstrip('0').rstrip('.') if isinstance(x, (int, float)) else x)
return df
[docs]def get_max_from_specific_columns(df, columns: List[str]) -> dict:
"""
Function to get the maximum value from specific columns in the DataFrame.
Input:
- df (pd.DataFrame): The DataFrame from which to get the maximum values.
- columns (list of str): A list of column names to get the maximum values from.
Output:
- Returns dictionary with the maximum values for each specified column.
"""
max_values = df[columns].max()
return max_values.to_dict()
[docs]def determine_folder_name(signal_name: str) -> str:
"""
Function determines the folder name based on the name of the signal.
Input:
- signal_name (str): The name of the signal to evaluate.
Output:
- Returns the corresponding folder name. Returns 'A12' if the signal name ends with 'v001', 'A15' if it ends
with 'vXXX' with XXX>1, and 'Unusual folder name' otherwise.
"""
if signal_name.endswith('v001'):
return 'A12'
elif 'v' in signal_name:
version_number = signal_name.split('v')[-1]
if version_number.isdigit() and int(version_number) > 1:
return 'A15'
return 'Unusual folder name'
[docs]def highlight_max(s) -> List[str]:
"""
Highlight the maximum value in a Pandas Series.
PInput:
- s (pd.Series): The Pandas Series to evaluate.
Output:
- Returns a list of strings representing the background color for each element in the Series. The maximum value
(excluding the first element) will have a background color of yellow.
"""
is_max = s == s[1:].max()
return ['background-color: yellow' if v else '' for v in is_max]
### ===================================================================================================================
### 3. End of script
### ===================================================================================================================