File size: 7,182 Bytes
7a703ad
 
 
 
 
 
e914943
7a703ad
 
e914943
 
 
1f115ec
e914943
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959f7ba
e914943
 
 
7a703ad
 
e914943
7a703ad
e914943
 
 
7a703ad
 
e914943
7a703ad
d3438ea
e914943
 
 
 
 
7a703ad
d3438ea
 
7a703ad
 
 
 
 
e914943
7a703ad
e914943
7a703ad
959f7ba
 
7a703ad
e914943
d3438ea
 
7a703ad
e914943
 
 
 
 
7a703ad
 
 
 
e914943
 
 
 
7a703ad
 
 
 
 
e914943
a01ffab
e914943
 
 
 
 
7a703ad
e914943
 
959f7ba
7a703ad
e914943
7a703ad
 
959f7ba
7a703ad
e914943
7a703ad
 
e914943
7a703ad
e914943
 
 
 
7a703ad
 
e914943
7a703ad
 
e914943
 
 
 
 
 
 
7a703ad
e914943
 
7a703ad
e914943
 
 
 
 
 
 
7a703ad
e914943
 
7a703ad
e914943
 
7a703ad
e914943
 
 
 
 
 
 
 
 
 
7a703ad
e914943
7a703ad
 
d3438ea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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()