joaopimenta's picture
Update app.py
e914943 verified
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()