| """ |
| Visualization Utilities for Financial Data |
| |
| Creates Plotly charts for: |
| - Revenue/Expense trends |
| - Balance Sheet visualizations |
| - GL account transaction summaries |
| - Sales order analytics |
| """ |
|
|
| import pandas as pd |
| import plotly.graph_objects as go |
| import plotly.express as px |
| from typing import Optional, Dict, Any |
|
|
|
|
| def create_revenue_expense_chart(df: pd.DataFrame) -> Dict[str, Any]: |
| """ |
| Create a revenue and expense trend chart. |
| |
| Args: |
| df: DataFrame with financial statement data |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty or 'Period' not in df.columns: |
| return {} |
| |
| fig = go.Figure() |
| |
| if 'Revenue' in df.columns: |
| fig.add_trace(go.Scatter( |
| x=df['Period'], |
| y=df['Revenue'], |
| mode='lines+markers', |
| name='Revenue', |
| line=dict(color='#2ecc71', width=3), |
| marker=dict(size=8) |
| )) |
| |
| if 'Operating_Expenses' in df.columns: |
| fig.add_trace(go.Scatter( |
| x=df['Period'], |
| y=df['Operating_Expenses'], |
| mode='lines+markers', |
| name='Operating Expenses', |
| line=dict(color='#e74c3c', width=3), |
| marker=dict(size=8) |
| )) |
| |
| if 'Net_Income' in df.columns: |
| fig.add_trace(go.Scatter( |
| x=df['Period'], |
| y=df['Net_Income'], |
| mode='lines+markers', |
| name='Net Income', |
| line=dict(color='#3498db', width=3), |
| marker=dict(size=8) |
| )) |
| |
| fig.update_layout( |
| title='Revenue and Expense Trends', |
| xaxis_title='Period', |
| yaxis_title='Amount (USD)', |
| hovermode='x unified', |
| template='plotly_white', |
| height=400 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_balance_sheet_chart(df: pd.DataFrame) -> Dict[str, Any]: |
| """ |
| Create a balance sheet visualization. |
| |
| Args: |
| df: DataFrame with balance sheet data |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty: |
| return {} |
| |
| |
| latest = df.iloc[-1] if len(df) > 0 else df.iloc[0] |
| |
| |
| assets = { |
| 'Cash': latest.get('Cash', 0), |
| 'Accounts Receivable': latest.get('Accounts_Receivable', 0), |
| 'Inventory': latest.get('Inventory', 0), |
| 'PPE': latest.get('PPE', 0) |
| } |
| |
| |
| liabilities = { |
| 'Accounts Payable': latest.get('Accounts_Payable', 0), |
| 'Short-term Debt': latest.get('Short_Term_Debt', 0), |
| 'Long-term Debt': latest.get('Long_Term_Debt', 0) |
| } |
| |
| |
| equity = { |
| 'Equity': latest.get('Equity', 0) |
| } |
| |
| fig = go.Figure() |
| |
| |
| fig.add_trace(go.Bar( |
| name='Assets', |
| x=list(assets.keys()), |
| y=list(assets.values()), |
| marker_color='#2ecc71' |
| )) |
| |
| |
| fig.add_trace(go.Bar( |
| name='Liabilities', |
| x=list(liabilities.keys()), |
| y=list(liabilities.values()), |
| marker_color='#e74c3c' |
| )) |
| |
| |
| fig.add_trace(go.Bar( |
| name='Equity', |
| x=list(equity.keys()), |
| y=list(equity.values()), |
| marker_color='#3498db' |
| )) |
| |
| fig.update_layout( |
| title='Balance Sheet Overview', |
| xaxis_title='Category', |
| yaxis_title='Amount (USD)', |
| barmode='group', |
| template='plotly_white', |
| height=400 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_gl_summary_chart(df: pd.DataFrame) -> Dict[str, Any]: |
| """ |
| Create a GL account transaction summary chart. |
| |
| Args: |
| df: DataFrame with GL transaction data |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty or 'Account_Description' not in df.columns: |
| return {} |
| |
| |
| account_summary = df.groupby('Account_Description').agg({ |
| 'Debit': 'sum', |
| 'Credit': 'sum' |
| }).reset_index() |
| |
| account_summary['Net'] = account_summary['Debit'] - account_summary['Credit'] |
| account_summary = account_summary.sort_values('Net', ascending=True).tail(15) |
| |
| fig = go.Figure() |
| |
| fig.add_trace(go.Bar( |
| y=account_summary['Account_Description'], |
| x=account_summary['Net'], |
| orientation='h', |
| marker=dict( |
| color=account_summary['Net'], |
| colorscale='RdYlGn', |
| showscale=True |
| ) |
| )) |
| |
| fig.update_layout( |
| title='Top 15 GL Accounts by Net Balance', |
| xaxis_title='Net Balance (USD)', |
| yaxis_title='Account', |
| template='plotly_white', |
| height=500 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_sales_analytics_chart(df: pd.DataFrame) -> Dict[str, Any]: |
| """ |
| Create sales order analytics chart. |
| |
| Args: |
| df: DataFrame with sales order data |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty: |
| return {} |
| |
| fig = go.Figure() |
| |
| |
| if 'Region' in df.columns and 'Total_Amount' in df.columns: |
| region_sales = df.groupby('Region')['Total_Amount'].sum().reset_index() |
| |
| fig.add_trace(go.Bar( |
| x=region_sales['Region'], |
| y=region_sales['Total_Amount'], |
| marker_color='#3498db', |
| text=region_sales['Total_Amount'].apply(lambda x: f'${x:,.0f}'), |
| textposition='outside' |
| )) |
| |
| fig.update_layout( |
| title='Sales by Region', |
| xaxis_title='Region', |
| yaxis_title='Total Sales (USD)', |
| template='plotly_white', |
| height=400 |
| ) |
| elif 'Product_Name' in df.columns and 'Total_Amount' in df.columns: |
| |
| product_sales = df.groupby('Product_Name')['Total_Amount'].sum().reset_index() |
| product_sales = product_sales.sort_values('Total_Amount', ascending=False).head(10) |
| |
| fig.add_trace(go.Bar( |
| x=product_sales['Product_Name'], |
| y=product_sales['Total_Amount'], |
| marker_color='#9b59b6', |
| text=product_sales['Total_Amount'].apply(lambda x: f'${x:,.0f}'), |
| textposition='outside' |
| )) |
| |
| fig.update_layout( |
| title='Top 10 Products by Sales', |
| xaxis_title='Product', |
| yaxis_title='Total Sales (USD)', |
| template='plotly_white', |
| height=400, |
| xaxis_tickangle=-45 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_sales_trend_chart(df: pd.DataFrame) -> Dict[str, Any]: |
| """ |
| Create a sales trend over time chart. |
| |
| Args: |
| df: DataFrame with sales order data |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty or 'Order_Date' not in df.columns: |
| return {} |
| |
| df['Order_Date'] = pd.to_datetime(df['Order_Date']) |
| df['Month'] = df['Order_Date'].dt.to_period('M').astype(str) |
| |
| monthly_sales = df.groupby('Month')['Total_Amount'].sum().reset_index() |
| |
| fig = go.Figure() |
| |
| fig.add_trace(go.Scatter( |
| x=monthly_sales['Month'], |
| y=monthly_sales['Total_Amount'], |
| mode='lines+markers', |
| name='Monthly Sales', |
| line=dict(color='#3498db', width=3), |
| marker=dict(size=8), |
| fill='tonexty', |
| fillcolor='rgba(52, 152, 219, 0.2)' |
| )) |
| |
| fig.update_layout( |
| title='Sales Trend Over Time', |
| xaxis_title='Month', |
| yaxis_title='Total Sales (USD)', |
| hovermode='x unified', |
| template='plotly_white', |
| height=400 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_pie_chart(df: pd.DataFrame, column: str, title: str) -> Dict[str, Any]: |
| """ |
| Create a pie chart for categorical data. |
| |
| Args: |
| df: DataFrame with data |
| column: Column name to aggregate |
| title: Chart title |
| |
| Returns: |
| Plotly figure as dictionary (JSON-serializable) |
| """ |
| if df.empty or column not in df.columns: |
| return {} |
| |
| value_counts = df[column].value_counts().head(10) |
| |
| fig = go.Figure(data=[go.Pie( |
| labels=value_counts.index, |
| values=value_counts.values, |
| hole=0.3 |
| )]) |
| |
| fig.update_layout( |
| title=title, |
| template='plotly_white', |
| height=400 |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def get_summary_metrics(df: pd.DataFrame, dataset_type: str) -> Dict[str, Any]: |
| """ |
| Get summary metrics for a dataset. |
| |
| Args: |
| df: DataFrame with data |
| dataset_type: Type of dataset ('gl', 'financial', 'sales') |
| |
| Returns: |
| Dictionary with summary metrics |
| """ |
| if df.empty: |
| return {} |
| |
| metrics = {} |
| |
| if dataset_type == 'gl': |
| metrics = { |
| 'Total Transactions': len(df), |
| 'Total Debit': df['Debit'].sum() if 'Debit' in df.columns else 0, |
| 'Total Credit': df['Credit'].sum() if 'Credit' in df.columns else 0, |
| 'Unique Accounts': df['Account_Code'].nunique() if 'Account_Code' in df.columns else 0 |
| } |
| elif dataset_type == 'financial': |
| latest = df.iloc[-1] if len(df) > 0 else df.iloc[0] |
| metrics = { |
| 'Periods': len(df), |
| 'Latest Revenue': latest.get('Revenue', 0), |
| 'Latest Net Income': latest.get('Net_Income', 0), |
| 'Total Assets': latest.get('Total_Assets', 0) |
| } |
| elif dataset_type == 'sales': |
| metrics = { |
| 'Total Orders': len(df), |
| 'Total Sales': df['Total_Amount'].sum() if 'Total_Amount' in df.columns else 0, |
| 'Average Order Value': df['Total_Amount'].mean() if 'Total_Amount' in df.columns else 0, |
| 'Unique Customers': df['Customer_ID'].nunique() if 'Customer_ID' in df.columns else 0 |
| } |
| |
| return metrics |
|
|
|
|
| def create_prediction_distribution_chart(predictions: list, labels: dict, title: str = "Prediction Distribution") -> Dict[str, Any]: |
| """ |
| Create a pie chart showing prediction distribution. |
| |
| Args: |
| predictions: List of prediction values (0, 1, etc.) |
| labels: Dictionary mapping values to labels |
| title: Chart title |
| |
| Returns: |
| Plotly figure as dictionary |
| """ |
| import numpy as np |
| |
| predictions = np.array(predictions) |
| unique, counts = np.unique(predictions, return_counts=True) |
| |
| pie_labels = [labels.get(int(val), f"Class {int(val)}") for val in unique] |
| |
| colors = ['#3498db', '#2ecc71', '#e74c3c', '#f39c12', '#9b59b6'] |
| |
| fig = go.Figure(data=[go.Pie( |
| labels=pie_labels, |
| values=counts, |
| hole=0.4, |
| marker=dict(colors=colors[:len(unique)]), |
| textinfo='label+percent+value', |
| textfont_size=14 |
| )]) |
| |
| fig.update_layout( |
| title=dict(text=title, font=dict(size=20, color='#2c3e50')), |
| template='plotly_white', |
| height=400, |
| showlegend=True, |
| legend=dict( |
| orientation="h", |
| yanchor="bottom", |
| y=-0.2, |
| xanchor="center", |
| x=0.5 |
| ) |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_prediction_bar_chart(predictions: list, labels: dict, title: str = "Prediction Summary") -> Dict[str, Any]: |
| """ |
| Create a bar chart showing prediction counts. |
| |
| Args: |
| predictions: List of prediction values |
| labels: Dictionary mapping values to labels |
| title: Chart title |
| |
| Returns: |
| Plotly figure as dictionary |
| """ |
| import numpy as np |
| |
| predictions = np.array(predictions) |
| unique, counts = np.unique(predictions, return_counts=True) |
| |
| bar_labels = [labels.get(int(val), f"Class {int(val)}") for val in unique] |
| percentages = (counts / len(predictions) * 100).round(1) |
| |
| colors = ['#3498db' if val == 0 else '#2ecc71' for val in unique] |
| |
| fig = go.Figure(data=[go.Bar( |
| x=bar_labels, |
| y=counts, |
| marker_color=colors, |
| text=[f'{count}<br>({pct}%)' for count, pct in zip(counts, percentages)], |
| textposition='outside', |
| textfont=dict(size=14, color='#2c3e50') |
| )]) |
| |
| fig.update_layout( |
| title=dict(text=title, font=dict(size=20, color='#2c3e50')), |
| xaxis_title="Classification", |
| yaxis_title="Count", |
| template='plotly_white', |
| height=400, |
| showlegend=False |
| ) |
| |
| return fig.to_dict() |
|
|
|
|
| def create_confidence_gauge(confidence_score: float, title: str = "Model Confidence") -> Dict[str, Any]: |
| """ |
| Create a gauge chart showing model confidence. |
| |
| Args: |
| confidence_score: Confidence score (0-100) |
| title: Chart title |
| |
| Returns: |
| Plotly figure as dictionary |
| """ |
| fig = go.Figure(go.Indicator( |
| mode="gauge+number+delta", |
| value=confidence_score, |
| domain={'x': [0, 1], 'y': [0, 1]}, |
| title={'text': title, 'font': {'size': 20}}, |
| delta={'reference': 50}, |
| gauge={ |
| 'axis': {'range': [None, 100], 'tickwidth': 1, 'tickcolor': "darkblue"}, |
| 'bar': {'color': "darkblue"}, |
| 'bgcolor': "white", |
| 'borderwidth': 2, |
| 'bordercolor': "gray", |
| 'steps': [ |
| {'range': [0, 33], 'color': '#e74c3c'}, |
| {'range': [33, 66], 'color': '#f39c12'}, |
| {'range': [66, 100], 'color': '#2ecc71'} |
| ], |
| 'threshold': { |
| 'line': {'color': "red", 'width': 4}, |
| 'thickness': 0.75, |
| 'value': 90 |
| } |
| } |
| )) |
| |
| fig.update_layout( |
| height=300, |
| margin=dict(l=20, r=20, t=40, b=20) |
| ) |
| |
| return fig.to_dict() |
|
|
|
|