""" Plotly visualizations - Interactive charts with hover tooltips. Used by Smart Dashboard for better user experience. """ import plotly.express as px import plotly.graph_objects as go import pandas as pd from typing import Optional def create_plotly_distribution(df: pd.DataFrame, column: str, title: Optional[str] = None): """Creates an interactive histogram with hover details.""" fig = px.histogram( df, x=column, nbins=30, title=title or f'Distribution of {column}', labels={column: column, 'count': 'Frequency'}, color_discrete_sequence=['#636EFA'], template='plotly_dark' ) # Add mean and median lines mean_val = df[column].mean() median_val = df[column].median() fig.add_vline(x=mean_val, line_dash="dash", line_color="red", annotation_text=f"Mean: {mean_val:.2f}", annotation_position="top") fig.add_vline(x=median_val, line_dash="dash", line_color="green", annotation_text=f"Median: {median_val:.2f}", annotation_position="bottom") fig.update_layout( hovermode='x unified', showlegend=False, height=400 ) return fig def create_plotly_category(df: pd.DataFrame, category_column: str, value_column: Optional[str] = None, agg_method: str = 'count', top_n: int = 10, offset: int = 0, title: Optional[str] = None): """Creates an interactive bar chart with hover details.""" # Aggregate data if value_column is None or agg_method == 'count': data = df[category_column].value_counts() total_items = len(data) data = data.iloc[offset : offset + top_n].reset_index() data.columns = [category_column, 'Count'] y_col = 'Count' else: if agg_method == 'sum': data = df.groupby(category_column)[value_column].sum() elif agg_method == 'mean': data = df.groupby(category_column)[value_column].mean() else: data = df.groupby(category_column)[value_column].sum() data = data.sort_values(ascending=False) total_items = len(data) data = data.iloc[offset : offset + top_n].reset_index() y_col = value_column # Update title to reflect pagination if title is None: end_idx = min(offset + top_n, total_items) title = f'Top {category_column} (Rank {offset+1}-{end_idx})' fig = px.bar( data, x=category_column, y=y_col, title=title or f'Top {top_n} {category_column}', color=y_col, color_continuous_scale='Viridis', template='plotly_dark' ) fig.update_layout( xaxis_tickangle=-45, showlegend=False, height=400 ) return fig def create_plotly_scatter(df: pd.DataFrame, x_col: str, y_col: str, color_col: Optional[str] = None, title: Optional[str] = None): """Creates an interactive scatter plot with hover details.""" fig = px.scatter( df, x=x_col, y=y_col, color=color_col, title=title or f'{y_col} vs {x_col}', opacity=0.7, template='plotly_dark' ) fig.update_layout( hovermode='closest', height=400 ) return fig def create_plotly_heatmap(df: pd.DataFrame, title: Optional[str] = None): """Creates an interactive correlation heatmap with hover details.""" from utils import get_column_types col_types = get_column_types(df) if len(col_types['numerical']) < 2: return None corr_matrix = df[col_types['numerical']].corr() fig = go.Figure(data=go.Heatmap( z=corr_matrix.values, x=corr_matrix.columns, y=corr_matrix.columns, colorscale='RdBu', zmid=0, text=corr_matrix.values, texttemplate='%{text:.2f}', textfont={"size": 10}, colorbar=dict(title="Correlation") )) fig.update_layout( title=title or 'Correlation Heatmap', xaxis_tickangle=-45, height=500, width=600 ) return fig def create_plotly_timeseries(df: pd.DataFrame, date_col: str, value_col: str, agg_method: str = 'sum', title: Optional[str] = None): """Creates an interactive time series with hover details.""" # Aggregate by date if agg_method == 'sum': data = df.groupby(date_col)[value_col].sum().reset_index() elif agg_method == 'mean': data = df.groupby(date_col)[value_col].mean().reset_index() else: data = df.groupby(date_col)[value_col].sum().reset_index() fig = px.line( data, x=date_col, y=value_col, title=title or f'{value_col} Trend', markers=True, template='plotly_dark' ) fig.update_layout( hovermode='x unified', height=400 ) return fig