charts.py
1 """ 2 Reusable Chart Components 3 4 Provides consistent chart creation across the dashboard. 5 """ 6 7 from typing import Optional, Dict, List 8 import plotly.graph_objects as go 9 import plotly.express as px 10 import pandas as pd 11 from dashboard import config 12 13 14 def create_funnel_chart(data: pd.DataFrame, x_col: str, y_col: str, title: str = "Pipeline Funnel") -> go.Figure: 15 """ 16 Create a funnel chart for pipeline visualization. 17 18 Args: 19 data: DataFrame with pipeline data 20 x_col: Column name for counts 21 y_col: Column name for stage names 22 title: Chart title 23 24 Returns: 25 Plotly Figure 26 """ 27 fig = go.Figure(go.Funnel( 28 y=data[y_col], 29 x=data[x_col], 30 textinfo="value", 31 marker={"color": list(config.STATUS_COLORS.values())[:len(data)]} 32 )) 33 fig.update_layout( 34 title=title, 35 height=400, 36 margin=dict(l=20, r=20, t=40, b=20) 37 ) 38 return fig 39 40 41 def create_bar_chart(data: pd.DataFrame, x_col: str, y_col: str, title: str, color_col: Optional[str] = None) -> go.Figure: 42 """ 43 Create a bar chart. 44 45 Args: 46 data: DataFrame 47 x_col: X-axis column 48 y_col: Y-axis column 49 title: Chart title 50 color_col: Optional column for color mapping 51 52 Returns: 53 Plotly Figure 54 """ 55 if color_col and color_col in data.columns: 56 fig = px.bar(data, x=x_col, y=y_col, title=title, color=color_col) 57 else: 58 fig = px.bar(data, x=x_col, y=y_col, title=title) 59 60 fig.update_layout(height=400, margin=dict(l=20, r=20, t=40, b=20)) 61 return fig 62 63 64 def create_pie_chart(data: pd.DataFrame, values_col: str, names_col: str, title: str, color_map: Optional[Dict] = None) -> go.Figure: 65 """ 66 Create a pie chart. 67 68 Args: 69 data: DataFrame 70 values_col: Column with values 71 names_col: Column with names 72 title: Chart title 73 color_map: Optional color mapping dict 74 75 Returns: 76 Plotly Figure 77 """ 78 fig = px.pie( 79 data, 80 values=values_col, 81 names=names_col, 82 title=title, 83 color=names_col if color_map else None, 84 color_discrete_map=color_map 85 ) 86 fig.update_traces(textposition='inside', textinfo='percent+label') 87 fig.update_layout(height=400, margin=dict(l=20, r=20, t=40, b=20)) 88 return fig 89 90 91 def create_line_chart(data: pd.DataFrame, x_col: str, y_col: str, title: str, group_col: Optional[str] = None) -> go.Figure: 92 """ 93 Create a line chart. 94 95 Args: 96 data: DataFrame 97 x_col: X-axis column (usually date) 98 y_col: Y-axis column 99 title: Chart title 100 group_col: Optional column for grouping (creates multiple lines) 101 102 Returns: 103 Plotly Figure 104 """ 105 if group_col: 106 fig = px.line(data, x=x_col, y=y_col, color=group_col, title=title) 107 else: 108 fig = px.line(data, x=x_col, y=y_col, title=title) 109 110 fig.update_layout(height=400, margin=dict(l=20, r=20, t=40, b=20)) 111 return fig 112 113 114 def create_stacked_bar_chart(data: pd.DataFrame, x_col: str, y_cols: List[str], title: str, colors: Optional[List[str]] = None) -> go.Figure: 115 """ 116 Create a stacked bar chart. 117 118 Args: 119 data: DataFrame 120 x_col: X-axis column 121 y_cols: List of columns to stack 122 title: Chart title 123 colors: Optional list of colors for bars 124 125 Returns: 126 Plotly Figure 127 """ 128 fig = go.Figure() 129 130 if not colors: 131 colors = px.colors.qualitative.Plotly 132 133 for i, col in enumerate(y_cols): 134 fig.add_trace(go.Bar( 135 name=col.replace('_', ' ').title(), 136 x=data[x_col], 137 y=data[col], 138 marker_color=colors[i % len(colors)] 139 )) 140 141 fig.update_layout( 142 barmode='stack', 143 title=title, 144 xaxis_title=x_col.replace('_', ' ').title(), 145 yaxis_title='Count', 146 height=400, 147 margin=dict(l=20, r=20, t=40, b=20) 148 ) 149 return fig 150 151 152 def create_gauge_chart(value: float, title: str, max_value: float = 100, thresholds: Optional[Dict] = None) -> go.Figure: 153 """ 154 Create a gauge chart (for coverage, etc.). 155 156 Args: 157 value: Current value 158 title: Chart title 159 max_value: Maximum value for gauge 160 thresholds: Optional dict with 'good', 'warning', 'critical' values 161 162 Returns: 163 Plotly Figure 164 """ 165 if not thresholds: 166 thresholds = {'good': 80, 'warning': 70, 'critical': 0} 167 168 fig = go.Figure(go.Indicator( 169 mode="gauge+number+delta", 170 value=value, 171 title={'text': title}, 172 gauge={ 173 'axis': {'range': [None, max_value]}, 174 'bar': {'color': "darkblue"}, 175 'steps': [ 176 {'range': [0, thresholds['warning']], 'color': "lightgray"}, 177 {'range': [thresholds['warning'], thresholds['good']], 'color': "lightyellow"}, 178 {'range': [thresholds['good'], max_value], 'color': "lightgreen"} 179 ], 180 'threshold': { 181 'line': {'color': "red", 'width': 4}, 182 'thickness': 0.75, 183 'value': thresholds['good'] 184 } 185 } 186 )) 187 fig.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20)) 188 return fig