elismasilva's picture
ajusted structure
f7824b9
import plotly.graph_objects as go
import pandas as pd
def create_verdict_donut(df: pd.DataFrame) -> go.Figure:
"""
Creates a High-Fidelity Donut Chart.
"""
if df.empty:
return _create_empty_figure("No Data")
color_map = {
'resolved': '#10B981', # Emerald 500
'possibly_resolved': '#34D399', # Emerald 400
'duplicate': '#F59E0B', # Amber 500
'unresolved': '#64748B', # Slate 500
'error': '#EF4444', # Red 500
'unknown': '#CBD5E1' # Slate 300
}
colors = [color_map.get(v, '#999') for v in df['verdict']]
total = df['count'].sum()
fig = go.Figure(data=[go.Pie(
labels=df['verdict'],
values=df['count'],
hole=0.7,
marker=dict(colors=colors, line=dict(color='#1F2937', width=0)),
textinfo='value',
hoverinfo='label+percent',
textfont=dict(size=14, color='white')
)])
fig.update_layout(
title=dict(
text="Analysis Distribution",
font=dict(size=14, color="#6B7280"),
x=0.5,
xanchor='center'
),
showlegend=True,
legend=dict(
orientation="h",
yanchor="top",
y=-0.1,
xanchor="center",
x=0.5,
font=dict(color="#9CA3AF", size=11)
),
margin=dict(t=40, b=60, l=20, r=20),
height=250,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
annotations=[dict(text=str(total), x=0.5, y=0.5, font_size=32, showarrow=False, font_color="#E5E7EB")],
modebar_remove=['zoom', 'pan', 'select', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d', 'toImage']
)
return fig
def create_timeline_chart(full_df: pd.DataFrame) -> go.Figure:
"""
Creates a Timeline showing activity over time.
"""
if full_df.empty:
return _create_empty_figure("No Timeline Data")
df = full_df.copy()
df['date'] = pd.to_datetime(df['updated_at'], errors='coerce').dt.date
daily_counts = df.groupby('date').size().reset_index(name='count')
fig = go.Figure()
fig.add_trace(go.Scatter(
x=daily_counts['date'],
y=daily_counts['count'],
mode='lines+markers',
name='Activity',
line=dict(color='#3B82F6', width=2, shape='spline'),
marker=dict(size=4, color='#60A5FA', line=dict(width=0)),
fill='tozeroy',
fillcolor='rgba(59, 130, 246, 0.1)'
))
fig.update_layout(
title=dict(
text="Activity Timeline (Last Updates)",
font=dict(size=14, color="#6B7280"),
x=0.5,
xanchor='center'
),
xaxis=dict(
showgrid=False,
color="#9CA3AF",
gridcolor="rgba(255,255,255,0.1)",
tickformat="%b %d"
),
yaxis=dict(
showgrid=True,
gridcolor="rgba(255,255,255,0.05)",
color="#9CA3AF",
zeroline=False
),
margin=dict(t=40, b=20, l=30, r=10),
height=250,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
showlegend=False,
modebar_remove=['zoom', 'pan', 'select', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d', 'toImage']
)
return fig
def _create_empty_figure(text):
fig = go.Figure()
fig.add_annotation(text=text, showarrow=False, font=dict(color="gray"))
fig.update_layout(
height=250,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
xaxis=dict(visible=False),
yaxis=dict(visible=False),
modebar_remove=['zoom', 'pan', 'select', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d', 'toImage']
)
return fig
def create_efficiency_funnel(stats_df: pd.DataFrame, total_open_issues: int) -> go.Figure:
"""
Creates a Funnel Chart showing how the AI filters the noise.
"""
if stats_df.empty:
return _create_empty_figure("No Data")
total_backlog = total_open_issues
total_analyzed = stats_df['count'].sum()
ai_solved = stats_df[stats_df['verdict'].isin(['resolved', 'duplicate', 'possibly_resolved'])]['count'].sum()
values = [total_backlog, total_analyzed, ai_solved]
stages = ["Total Backlog", "Analyzed by AI", "Actionable Findings"]
fig = go.Figure(go.Funnel(
y=stages,
x=values,
textinfo="value+percent initial",
textfont=dict(color="#e5e5e5", size=12),
marker=dict(color=["#64748B", "#4486F0", "#10B981"]),
connector=dict(line=dict(color="rgba(128,128,128,0.5)", width=1))
))
fig.update_layout(
title=dict(
text="AI Efficiency Funnel",
font=dict(size=14, color="#6B7280"),
x=0.5, xanchor='center'
),
xaxis=dict(
showgrid=False,
color="#9CA3AF",
gridcolor="rgba(255,255,255,0.1)",
tickformat="%b %d"
),
yaxis=dict(
showgrid=True,
gridcolor="rgba(255,255,255,0.1)",
color="#9CA3AF",
zeroline=False
),
margin=dict(t=40, b=20, l=100, r=10),
height=250,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
showlegend=False,
modebar_remove=['pan', 'select', 'lasso2d', 'autoScale2d', 'resetScale2d']
)
return fig