Spaces:
Sleeping
Sleeping
| 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() |