import gradio as gr import pandas as pd import plotly.express as px import plotly.graph_objects as go # ========================================================= # 1. CARREGAMENTO E LIMPEZA DE DADOS # ========================================================= def load_data(): # --- SIMULAÇÃO DE DADOS --- # Se estiver usando seu arquivo real, descomente a linha abaixo: # df = pd.read_csv("seu_ficheiro.csv", sep=";") data = { 'Marca': ['VALTRA', 'KIOTI', 'JOHN DEERE', 'NEW HOLLAND', 'KUBOTA', 'VALTRA', 'KIOTI', 'SOLIS', 'FENDT', 'CLAAS'] * 50, 'Regiao': ['Norte', 'Centro', 'Alentejo', 'Norte', 'Algarve'] * 100, 'Tipo': ['="Agricola"'] * 500, 'Potencia kW': ['="75"', '="19"', '="88"', '="55"', '="70"', '="121"', '="44"', '="19"', '="176"', '="90"'] * 50, } df = pd.DataFrame(data) # ---------------------------------------------------------- # === SUA LIMPEZA === # 1. Limpar Tipo df['Tipo_clean'] = df['Tipo'].astype(str).str.replace('="', '', regex=False).str.replace('"', '', regex=False).str.strip().str.upper() df = df[df['Tipo_clean'] == 'AGRICOLA'].copy() # 2. Limpar Potência df["Potencia kW"] = df["Potencia kW"].astype(str).str.replace(r'[="]', '', regex=True) df["Potencia kW"] = pd.to_numeric(df["Potencia kW"], errors='coerce') df = df.dropna(subset=["Potencia kW"]) # 3. Criar Segmentos bins = [0, 25, 50, 100, 500] labels = ['< 25 kW (Compactos)', '25 - 50 kW', '50 - 100 kW', '> 100 kW (Alta)'] df['Cluster Potencia'] = pd.cut(df['Potencia kW'], bins=bins, labels=labels) df['Cluster Potencia'] = df['Cluster Potencia'].astype(str) return df # Carregar dados globais df_global = load_data() min_kw_global = int(df_global["Potencia kW"].min()) max_kw_global = int(df_global["Potencia kW"].max()) all_regions = sorted(df_global["Regiao"].unique().tolist()) # ========================================================= # 2. LÓGICA DO DASHBOARD # ========================================================= def update_dashboard(val_min, val_max, selected_regions): # Garantir que min não é maior que max if val_min > val_max: val_min, val_max = val_max, val_min # 1. Filtrar DataFrame mask = ( (df_global["Potencia kW"] >= val_min) & (df_global["Potencia kW"] <= val_max) & (df_global["Regiao"].isin(selected_regions)) ) df_filtered = df_global[mask] if df_filtered.empty: return "0", "0%", "0%", None, None, None, pd.DataFrame() # 2. KPIs total = len(df_filtered) v_valtra = len(df_filtered[df_filtered['Marca'].str.upper() == 'VALTRA']) v_kioti = len(df_filtered[df_filtered['Marca'].str.upper() == 'KIOTI']) # Evitar erro de divisão por zero share_valtra = (v_valtra / total * 100) if total > 0 else 0 share_kioti = (v_kioti / total * 100) if total > 0 else 0 kpi_total_txt = f"{total} Unidades" kpi_valtra_txt = f"{share_valtra:.1f}% ({v_valtra})" kpi_kioti_txt = f"{share_kioti:.1f}% ({v_kioti})" # 3. Gráfico Ranking (Cores Inteligentes) top_marcas = df_filtered['Marca'].value_counts().reset_index().head(15) top_marcas.columns = ['Marca', 'Vendas'] colors = [] for marca in top_marcas['Marca']: if marca.upper() == 'VALTRA': colors.append('#d62728') # Vermelho elif marca.upper() == 'KIOTI': colors.append('#ff7f0e') # Laranja else: colors.append('#cccccc') # Cinza fig_rank = go.Figure(data=[go.Bar( x=top_marcas['Marca'], y=top_marcas['Vendas'], marker_color=colors, text=top_marcas['Vendas'], textposition='auto' )]) fig_rank.update_layout(title="Ranking de Mercado (Top 15)", template="plotly_white", height=400) # 4. Gráfico Potência vendas_cluster = df_filtered['Cluster Potencia'].value_counts().reset_index() vendas_cluster.columns = ['Cluster', 'Vendas'] fig_pie = px.pie(vendas_cluster, values='Vendas', names='Cluster', title='Distribuição por Potência', hole=0.4) # 5. Gráfico Segmentos nossas = df_filtered[df_filtered['Marca'].isin(['VALTRA', 'KIOTI'])] if not nossas.empty: fig_seg = px.histogram(nossas, x="Cluster Potencia", color="Marca", barmode="group", title="Posicionamento: Valtra vs Kioti", color_discrete_map={'VALTRA': '#d62728', 'KIOTI': '#ff7f0e'}) else: fig_seg = go.Figure().add_annotation(text="Sem dados Valtra/Kioti", showarrow=False) return kpi_total_txt, kpi_valtra_txt, kpi_kioti_txt, fig_rank, fig_pie, fig_seg, df_filtered # ========================================================= # 3. INTERFACE GRADIO # ========================================================= with gr.Blocks(title="Dashboard Executivo", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🚜 Dashboard de Mercado: Valtra & KIOTI") gr.Markdown("_Visão estratégica para Direção Geral_") with gr.Row(): # --- COLUNA DE FILTROS --- with gr.Column(scale=1): gr.Label("⚙️ Filtros") # SUBSTITUIÇÃO DO RANGESLIDER POR DOIS SLIDERS SIMPLES slider_min = gr.Slider(minimum=min_kw_global, maximum=max_kw_global, value=min_kw_global, step=1, label="Potência Mínima (kW)") slider_max = gr.Slider(minimum=min_kw_global, maximum=max_kw_global, value=max_kw_global, step=1, label="Potência Máxima (kW)") chk_region = gr.CheckboxGroup(choices=all_regions, value=all_regions, label="Regiões") btn_refresh = gr.Button("Atualizar Dados", variant="primary") # --- COLUNA DOS GRÁFICOS --- with gr.Column(scale=3): with gr.Row(): kpi_total = gr.Text(label="Mercado Total (Filtro)") kpi_valtra = gr.Text(label="Share VALTRA") kpi_kioti = gr.Text(label="Share KIOTI") gr.Markdown("### 🏆 Performance de Mercado") plot_ranking = gr.Plot(label="Ranking de Vendas") with gr.Row(): plot_potencia = gr.Plot(label="Mix de Potência") plot_segmento = gr.Plot(label="Nossas Marcas por Segmento") with gr.Accordion("📂 Ver Dados Detalhados", open=False): data_table = gr.Dataframe(headers=list(df_global.columns)) # ========================================================= # 4. LIGAÇÕES (WIRING) # ========================================================= inputs = [slider_min, slider_max, chk_region] outputs = [kpi_total, kpi_valtra, kpi_kioti, plot_ranking, plot_potencia, plot_segmento, data_table] slider_min.change(fn=update_dashboard, inputs=inputs, outputs=outputs) slider_max.change(fn=update_dashboard, inputs=inputs, outputs=outputs) chk_region.change(fn=update_dashboard, inputs=inputs, outputs=outputs) btn_refresh.click(fn=update_dashboard, inputs=inputs, outputs=outputs) demo.load(fn=update_dashboard, inputs=inputs, outputs=outputs) if __name__ == "__main__": demo.launch()