Download visualization.py from mabuseif/HVAC: direct link, hf CLI and curl.
- Browser
- Download file 14.3 kB
-
https://huggingface.co/spaces/mabuseif/HVAC/resolve/main/visualization.py
- Command line
-
hf download hf://spaces/mabuseif/HVAC/visualization.py
-
curl -L -o visualization.py https://huggingface.co/spaces/mabuseif/HVAC/resolve/main/visualization.py
14.3 kB
| """ | |
| Visualization utilities for HVAC Load Calculator | |
| This module provides enhanced visualization functions for creating interactive | |
| and informative charts for the HVAC Load Calculator application. | |
| """ | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| import pandas as pd | |
| import numpy as np | |
| def create_load_breakdown_chart(load_components, title="Load Breakdown"): | |
| """ | |
| Create an enhanced pie chart for load components breakdown. | |
| Args: | |
| load_components (dict): Dictionary of load components and their values | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive pie chart | |
| """ | |
| # Remove zero values | |
| load_components = {k: v for k, v in load_components.items() if v > 0} | |
| # Create figure | |
| fig = go.Figure() | |
| # Add pie chart | |
| fig.add_trace(go.Pie( | |
| labels=list(load_components.keys()), | |
| values=list(load_components.values()), | |
| textinfo='label+percent', | |
| insidetextorientation='radial', | |
| marker=dict( | |
| colors=px.colors.qualitative.Bold, | |
| line=dict(color='white', width=2) | |
| ), | |
| pull=[0.05 if x == max(load_components.values()) else 0 for x in load_components.values()], | |
| hovertemplate='<b>%{label}</b><br>%{value:.1f} W<br>%{percent}<extra></extra>' | |
| )) | |
| # Update layout | |
| fig.update_layout( | |
| title={ | |
| 'text': title, | |
| 'y': 0.95, | |
| 'x': 0.5, | |
| 'xanchor': 'center', | |
| 'yanchor': 'top', | |
| 'font': dict(size=20) | |
| }, | |
| legend=dict( | |
| orientation="h", | |
| yanchor="bottom", | |
| y=-0.2, | |
| xanchor="center", | |
| x=0.5, | |
| font=dict(size=12) | |
| ), | |
| height=500, | |
| margin=dict(t=80, b=80, l=40, r=40), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| def create_component_bar_chart(df, x_col, y_col, color_col=None, title="Component Breakdown"): | |
| """ | |
| Create an enhanced bar chart for component breakdown. | |
| Args: | |
| df (pd.DataFrame): DataFrame containing the data | |
| x_col (str): Column name for x-axis | |
| y_col (str): Column name for y-axis | |
| color_col (str, optional): Column name for color grouping | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive bar chart | |
| """ | |
| # Create figure | |
| if color_col: | |
| fig = px.bar( | |
| df, | |
| x=x_col, | |
| y=y_col, | |
| color=color_col, | |
| title=title, | |
| color_discrete_sequence=px.colors.qualitative.Bold, | |
| height=500, | |
| text=y_col | |
| ) | |
| else: | |
| fig = px.bar( | |
| df, | |
| x=x_col, | |
| y=y_col, | |
| title=title, | |
| color_discrete_sequence=px.colors.qualitative.Bold, | |
| height=500, | |
| text=y_col | |
| ) | |
| # Update layout | |
| fig.update_layout( | |
| xaxis_title=x_col, | |
| yaxis_title=y_col, | |
| legend_title=color_col if color_col else "", | |
| font=dict(size=12), | |
| xaxis={'categoryorder': 'total descending'}, | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| hovermode="x unified" | |
| ) | |
| # Add data labels | |
| fig.update_traces( | |
| texttemplate='%{y:.1f}', | |
| textposition='outside', | |
| hovertemplate='<b>%{x}</b><br>%{y:.1f}<extra></extra>' | |
| ) | |
| # Add grid lines | |
| fig.update_yaxes( | |
| showgrid=True, | |
| gridwidth=1, | |
| gridcolor='rgba(211,211,211,0.3)' | |
| ) | |
| return fig | |
| def create_stacked_bar_chart(df, x_col, y_cols, names, title="Stacked Bar Chart"): | |
| """ | |
| Create an enhanced stacked bar chart. | |
| Args: | |
| df (pd.DataFrame): DataFrame containing the data | |
| x_col (str): Column name for x-axis | |
| y_cols (list): List of column names for y-axis values | |
| names (list): List of names for each y-column | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive stacked bar chart | |
| """ | |
| # Create figure | |
| fig = go.Figure() | |
| # Add bars for each y column | |
| for i, y_col in enumerate(y_cols): | |
| fig.add_trace(go.Bar( | |
| x=df[x_col], | |
| y=df[y_col], | |
| name=names[i], | |
| hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>' | |
| )) | |
| # Update layout | |
| fig.update_layout( | |
| title=title, | |
| xaxis_title=x_col, | |
| yaxis_title="Value", | |
| barmode='stack', | |
| height=500, | |
| legend=dict( | |
| orientation="h", | |
| yanchor="bottom", | |
| y=1.02, | |
| xanchor="center", | |
| x=0.5 | |
| ), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| hovermode="x unified" | |
| ) | |
| # Add grid lines | |
| fig.update_yaxes( | |
| showgrid=True, | |
| gridwidth=1, | |
| gridcolor='rgba(211,211,211,0.3)' | |
| ) | |
| return fig | |
| def create_grouped_bar_chart(df, x_col, y_cols, names, title="Grouped Bar Chart"): | |
| """ | |
| Create an enhanced grouped bar chart. | |
| Args: | |
| df (pd.DataFrame): DataFrame containing the data | |
| x_col (str): Column name for x-axis | |
| y_cols (list): List of column names for y-axis values | |
| names (list): List of names for each y-column | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive grouped bar chart | |
| """ | |
| # Create figure | |
| fig = go.Figure() | |
| # Add bars for each y column | |
| for i, y_col in enumerate(y_cols): | |
| fig.add_trace(go.Bar( | |
| x=df[x_col], | |
| y=df[y_col], | |
| name=names[i], | |
| hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>' | |
| )) | |
| # Update layout | |
| fig.update_layout( | |
| title=title, | |
| xaxis_title=x_col, | |
| yaxis_title="Value", | |
| barmode='group', | |
| height=500, | |
| legend=dict( | |
| orientation="h", | |
| yanchor="bottom", | |
| y=1.02, | |
| xanchor="center", | |
| x=0.5 | |
| ), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| hovermode="x unified" | |
| ) | |
| # Add grid lines | |
| fig.update_yaxes( | |
| showgrid=True, | |
| gridwidth=1, | |
| gridcolor='rgba(211,211,211,0.3)' | |
| ) | |
| return fig | |
| def create_heat_map_chart(df, x_col, y_col, z_col, title="Heat Map"): | |
| """ | |
| Create an enhanced heat map chart. | |
| Args: | |
| df (pd.DataFrame): DataFrame containing the data | |
| x_col (str): Column name for x-axis | |
| y_col (str): Column name for y-axis | |
| z_col (str): Column name for z-axis (color) | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive heat map chart | |
| """ | |
| # Create figure | |
| fig = px.density_heatmap( | |
| df, | |
| x=x_col, | |
| y=y_col, | |
| z=z_col, | |
| title=title, | |
| color_continuous_scale="Viridis", | |
| height=500 | |
| ) | |
| # Update layout | |
| fig.update_layout( | |
| xaxis_title=x_col, | |
| yaxis_title=y_col, | |
| font=dict(size=12), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| def create_line_chart(df, x_col, y_cols, names, title="Line Chart"): | |
| """ | |
| Create an enhanced line chart. | |
| Args: | |
| df (pd.DataFrame): DataFrame containing the data | |
| x_col (str): Column name for x-axis | |
| y_cols (list): List of column names for y-axis values | |
| names (list): List of names for each y-column | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive line chart | |
| """ | |
| # Create figure | |
| fig = go.Figure() | |
| # Add lines for each y column | |
| for i, y_col in enumerate(y_cols): | |
| fig.add_trace(go.Scatter( | |
| x=df[x_col], | |
| y=df[y_col], | |
| mode='lines+markers', | |
| name=names[i], | |
| hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>' | |
| )) | |
| # Update layout | |
| fig.update_layout( | |
| title=title, | |
| xaxis_title=x_col, | |
| yaxis_title="Value", | |
| height=500, | |
| legend=dict( | |
| orientation="h", | |
| yanchor="bottom", | |
| y=1.02, | |
| xanchor="center", | |
| x=0.5 | |
| ), | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| hovermode="x unified" | |
| ) | |
| # Add grid lines | |
| fig.update_yaxes( | |
| showgrid=True, | |
| gridwidth=1, | |
| gridcolor='rgba(211,211,211,0.3)' | |
| ) | |
| fig.update_xaxes( | |
| showgrid=True, | |
| gridwidth=1, | |
| gridcolor='rgba(211,211,211,0.3)' | |
| ) | |
| return fig | |
| def create_sankey_diagram(nodes, links, title="Energy Flow"): | |
| """ | |
| Create a Sankey diagram for energy flow visualization. | |
| Args: | |
| nodes (list): List of node labels | |
| links (dict): Dictionary with source, target, and value lists | |
| title (str): Chart title | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive Sankey diagram | |
| """ | |
| # Create figure | |
| fig = go.Figure(data=[go.Sankey( | |
| node=dict( | |
| pad=15, | |
| thickness=20, | |
| line=dict(color="black", width=0.5), | |
| label=nodes, | |
| color="blue" | |
| ), | |
| link=dict( | |
| source=links['source'], | |
| target=links['target'], | |
| value=links['value'], | |
| hovertemplate='%{source.label} → %{target.label}: %{value:.1f} W<extra></extra>' | |
| ) | |
| )]) | |
| # Update layout | |
| fig.update_layout( | |
| title=title, | |
| font=dict(size=12), | |
| height=600, | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| def create_gauge_chart(value, min_val, max_val, title="Gauge", threshold_values=None, threshold_colors=None): | |
| """ | |
| Create a gauge chart for displaying a value within a range. | |
| Args: | |
| value (float): Value to display | |
| min_val (float): Minimum value of the range | |
| max_val (float): Maximum value of the range | |
| title (str): Chart title | |
| threshold_values (list, optional): List of threshold values | |
| threshold_colors (list, optional): List of colors for each threshold | |
| Returns: | |
| plotly.graph_objects.Figure: Interactive gauge chart | |
| """ | |
| # Set default thresholds if not provided | |
| if threshold_values is None: | |
| threshold_values = [min_val, (min_val + max_val) / 2, max_val] | |
| if threshold_colors is None: | |
| threshold_colors = ["green", "yellow", "red"] | |
| # Create figure | |
| fig = go.Figure(go.Indicator( | |
| mode="gauge+number", | |
| value=value, | |
| domain={'x': [0, 1], 'y': [0, 1]}, | |
| title={'text': title}, | |
| gauge={ | |
| 'axis': {'range': [min_val, max_val]}, | |
| 'bar': {'color': "darkblue"}, | |
| 'steps': [ | |
| {'range': [threshold_values[i], threshold_values[i+1]], 'color': threshold_colors[i]} | |
| for i in range(len(threshold_values)-1) | |
| ], | |
| 'threshold': { | |
| 'line': {'color': "red", 'width': 4}, | |
| 'thickness': 0.75, | |
| 'value': value | |
| } | |
| } | |
| )) | |
| # Update layout | |
| fig.update_layout( | |
| height=300, | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| plot_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| def create_enhanced_results_visualization(results): | |
| """ | |
| Create enhanced visualizations for HVAC load calculation results. | |
| Args: | |
| results (dict): Dictionary containing calculation results | |
| Returns: | |
| dict: Dictionary of plotly figures | |
| """ | |
| figures = {} | |
| # Prepare data for load breakdown pie chart | |
| load_components = { | |
| 'Walls': results.get('wall_loss', 0), | |
| 'Roof': results.get('roof_loss', 0), | |
| 'Floor': results.get('floor_loss', 0), | |
| 'Windows & Doors': results.get('window_loss', 0), | |
| 'Infiltration': results.get('infiltration_loss', 0), | |
| 'Ventilation': results.get('ventilation_loss', 0) - results.get('infiltration_loss', 0) | |
| } | |
| # Create load breakdown pie chart | |
| figures['load_breakdown'] = create_load_breakdown_chart( | |
| load_components, | |
| title="Heating Load Components" | |
| ) | |
| # Create energy flow Sankey diagram | |
| if 'internal_gain' in results and results['internal_gain'] > 0: | |
| # Create nodes and links for Sankey diagram | |
| nodes = [ | |
| "Walls", "Roof", "Floor", "Windows & Doors", | |
| "Infiltration", "Ventilation", "Internal Gains", | |
| "Total Heat Loss", "Net Heating Load" | |
| ] | |
| links = { | |
| 'source': [0, 1, 2, 3, 4, 5, 7, 6], | |
| 'target': [7, 7, 7, 7, 7, 7, 8, 8], | |
| 'value': [ | |
| load_components['Walls'], | |
| load_components['Roof'], | |
| load_components['Floor'], | |
| load_components['Windows & Doors'], | |
| load_components['Infiltration'], | |
| load_components['Ventilation'], | |
| results['internal_gain'], | |
| results['total_heat_loss'] | |
| ] | |
| } | |
| figures['energy_flow'] = create_sankey_diagram( | |
| nodes, | |
| links, | |
| title="Heating Energy Flow" | |
| ) | |
| # Create gauge chart for heating load per area | |
| if 'net_heating_load' in results and 'building_info' in results: | |
| floor_area = results['building_info'].get('floor_area', 80.0) | |
| heating_load_per_area = results['net_heating_load'] / floor_area | |
| figures['load_per_area_gauge'] = create_gauge_chart( | |
| heating_load_per_area, | |
| 0, | |
| 200, | |
| title="Heating Load per Area (W/m²)", | |
| threshold_values=[0, 50, 100, 150, 200], | |
| threshold_colors=["green", "lightgreen", "yellow", "orange", "red"] | |
| ) | |
| return figures | |