File size: 17,769 Bytes
b16492a
4477750
7922418
 
 
 
a0f1ca1
7922418
1ec8606
 
 
 
 
7922418
f299934
ee760b7
 
 
e08c501
 
ee760b7
f299934
 
e08c501
ee760b7
f299934
ee760b7
 
 
 
e08c501
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1ec8606
4c3c53a
e08c501
 
4c3c53a
e08c501
 
4c3c53a
 
 
e08c501
 
 
 
 
 
 
 
 
 
 
 
 
1ec8606
 
e08c501
b9da37d
 
 
1ec8606
 
f299934
4c3c53a
1ec8606
df3cdd5
040c5fa
0b95db3
1ec8606
e08c501
0b95db3
1ec8606
ee760b7
 
 
b9da37d
4c3c53a
f299934
 
ee760b7
 
a0f1ca1
ee760b7
7d1db74
0b95db3
4c3c53a
0b95db3
 
f299934
 
5de7dfa
f299934
ee760b7
 
7d1db74
0b95db3
 
4c3c53a
b16492a
f299934
ee760b7
 
 
 
0b95db3
4c3c53a
f299934
 
 
ee760b7
f299934
 
 
 
 
 
72c82aa
5de7dfa
f299934
 
 
 
 
 
 
 
 
 
72c82aa
f299934
 
 
 
4c3c53a
f299934
ee760b7
f299934
4c3c53a
ee760b7
f299934
 
b16492a
4c3c53a
ee760b7
 
e08c501
4c3c53a
f299934
ee760b7
f299934
ee760b7
1ec8606
 
ee760b7
 
f299934
 
ee760b7
1ec8606
f299934
ee760b7
f299934
ee760b7
 
f299934
 
 
ee760b7
f299934
4c3c53a
f299934
 
ee760b7
f299934
ee760b7
0b95db3
ee760b7
e08c501
 
 
 
ee760b7
f299934
ee760b7
 
 
 
e08c501
 
 
f299934
b9da37d
f299934
ee760b7
f299934
ee760b7
4c3c53a
f299934
a0f1ca1
b9da37d
f299934
ee760b7
f299934
0b95db3
ee760b7
 
b16492a
ee760b7
e08c501
 
4c3c53a
f299934
ee760b7
 
 
 
f299934
a0f1ca1
e08c501
 
 
 
 
 
 
f299934
 
 
ee760b7
f299934
ee760b7
e08c501
ee760b7
e08c501
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# --- 1. IMPORTAÇÕES E CONFIGURAÇÃO DA PÁGINA ---
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import numpy_financial as npf

st.set_page_config(
    layout="wide",
    page_title="Dashboard Estratégico de Reciclagem",
    page_icon="♻️"
)

# --- 2. ESTILO CSS PROFISSIONAL ---
st.markdown("""
<style>
    .stMetric {
        border-radius: 10px; padding: 15px; background-color: #FFFFFF;
        border: 1px solid #E6E6E6; box-shadow: 0 4px 8px rgba(0,0,0,0.04);
    }
    .stTabs [data-baseweb="tab-list"] { gap: 24px; }
    .stTabs [data-baseweb="tab"] {
        height: 50px; background-color: #F0F2F6; border-radius: 4px 4px 0px 0px; padding: 10px 15px;
    }
    .stTabs [aria-selected="true"] { background-color: #FFFFFF; }
</style>
""", unsafe_allow_html=True)


# --- 3. DEFINIÇÃO DAS FUNÇÕES GLOBAIS ---
def formatar_brl(valor): return f"R$ {valor:,.2f}"
def formatar_percentual(valor): return f"{valor:.2%}" if pd.notna(valor) and not np.isinf(valor) else "N/A"

def calcular_vpl(fluxo_caixa, taxa_desconto):
    try: return npf.npv(taxa_desconto, fluxo_caixa)
    except: return np.nan

def calcular_tir(fluxo_caixa):
    try:
        return npf.irr(fluxo_caixa) if np.any(np.sign(fluxo_caixa)) and np.any(np.sign(fluxo_caixa) * -1) else np.nan
    except: return np.nan

def calcular_mtir(fluxo_caixa, taxa_desconto, taxa_reinvestimento):
    try:
        return npf.mirr(fluxo_caixa, taxa_desconto, taxa_reinvestimento) if np.any(np.sign(fluxo_caixa)) and np.any(np.sign(fluxo_caixa) * -1) else np.nan
    except: return np.nan

def calcular_payback_descontado(fluxo_caixa, taxa_desconto):
    investimento_inicial = abs(fluxo_caixa[0])
    fluxo_acumulado_descontado = 0
    for periodo, valor in enumerate(fluxo_caixa[1:], 1):
        fluxo_acumulado_descontado += valor / ((1 + taxa_desconto) ** periodo)
        if fluxo_acumulado_descontado >= investimento_inicial:
            ultimo_fluxo_necessario = investimento_inicial - (fluxo_acumulado_descontado - (valor / ((1 + taxa_desconto) ** periodo)))
            return (periodo - 1) + (ultimo_fluxo_necessario / (valor / ((1 + taxa_desconto) ** periodo)))
    return np.inf

@st.cache_data
def simular_faturamento_bootstrap(_df_dados_mensais_numeric, precos_dict, cenarios_dict, eficiencia_geral_coleta, n_simulacoes=2000, seed=42):
    np.random.seed(seed)
    faturamentos_simulados = {nome: [] for nome in cenarios_dict.keys()}
    for nome_cen, fator_cenario in cenarios_dict.items():
        for _ in range(n_simulacoes):
            df_amostrado = _df_dados_mensais_numeric.sample(n=12, replace=True)
            faturamento_bruto_iteracao = sum(df_amostrado[material].sum() * preco for material, preco in precos_dict.items())
            faturamento_liquido = faturamento_bruto_iteracao * eficiencia_geral_coleta * fator_cenario
            faturamentos_simulados[nome_cen].append(faturamento_liquido)
    return {nome: np.array(data) for nome, data in faturamentos_simulados.items()}

def gerar_fluxo_caixa_projeto(investimento_inicial, receita_anual_base, custos_operacionais_anuais, horizonte_anos, taxa_crescimento):
    fluxo_caixa = [-abs(investimento_inicial)]
    for ano in range(1, horizonte_anos + 1):
        fator_crescimento = (1 + taxa_crescimento) ** (ano - 1)
        fluxo_liquido_ano = (receita_anual_base * fator_crescimento) - (custos_operacionais_anuais * fator_crescimento)
        fluxo_caixa.append(fluxo_liquido_ano)
    return fluxo_caixa

# --- 4. CARREGAMENTO DE DADOS (FUNÇÃO CACHEADA) ---
@st.cache_data
def carregar_dados():
    meses = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
    dados_2024 = {
        'Mes': meses, 'Papel_Papelao': [8047, 11287, 8184, 10183, 5699, 5830, 7465, 5600, 2960, 5175, 9656, 3960],
        'Plastico': [6353, 8771, 6993, 8050, 4880, 5296, 5937, 4747, 2446, 4109, 7667, 3367],
        'Metal': [1061, 2025, 1121, 1832, 716, 936, 1553, 904, 361, 630, 1904, 569],
        'Vidro': [5248, 6929, 6014, 5821, 3697, 3655, 4950, 3360, 1580, 3261, 6173, 2357]
    }
    df_2024 = pd.DataFrame(dados_2024)
    df_2024_numeric = df_2024.drop(columns='Mes')
    dados_anuais = {'Ano': [2022, 2023, 2024], 'Papel_Papelao': [18780, 58718, df_2024_numeric['Papel_Papelao'].sum()], 'Plastico': [5340, 1041, df_2024_numeric['Plastico'].sum()], 'Metal': [1300, 1737, df_2024_numeric['Metal'].sum()], 'Vidro': [0, 725, df_2024_numeric['Vidro'].sum()]}
    df_anuais = pd.DataFrame(dados_anuais).set_index('Ano')
    precos_iniciais = {'Papel_Papelao': 0.50, 'Plastico': 2.00, 'Metal': 2.30, 'Vidro': 0.90}
    custos_mensais_iniciais = {"Locacao_Maquina": 4400, "Coleta_Destinacao": 1400, "Outros": 500}
    return df_2024, df_anuais, precos_iniciais, df_2024_numeric, custos_mensais_iniciais

# --- 5. EXECUÇÃO INICIAL E SIDEBAR DE CONTROLES ---
df_2024, df_anuais, precos_iniciais, df_2024_numeric, custos_mensais_iniciais = carregar_dados()

st.sidebar.title(" Painel de Controle")
st.sidebar.markdown("Use os menus abaixo para navegar entre as análises e ajustar os parâmetros do projeto.")
st.sidebar.divider()

pagina_selecionada = st.sidebar.radio("Menu de Navegação",
    ["🔎 Análise Exploratória (EDA)", "🎯 Simulação de Faturamento", "📊 Análise de Viabilidade"],
    captions=["Análise dos dados históricos", "Projeção de receitas via simulação", "Cálculos de VPL, TIR e Risco"]
)
st.sidebar.divider()

with st.sidebar.expander("⚙️ Premissas Financeiras do Projeto", expanded=True):
    investimento_inicial = st.number_input("Investimento Inicial (R$)", min_value=1000.0, value=5000.0, step=1000.0)
    st.markdown("**Custos Fixos Mensais (R$)**")
    custos_mensais_editaveis = {custo: st.number_input(custo.replace("_", " "), value=valor, step=50, key=custo) for custo, valor in custos_mensais_iniciais.items()}
    custos_operacionais_anuais = sum(custos_mensais_editaveis.values()) * 12
    st.info(f"Custo Anual Calculado: **{formatar_brl(custos_operacionais_anuais)}**")
    horizonte_projeto = st.slider("Horizonte do Projeto (anos)", 3, 20, 10)
    taxa_desconto = st.slider("Taxa de Desconto (TMA) (%)", 5.0, 25.0, 12.0, 0.5) / 100
    taxa_crescimento = st.slider("Crescimento Anual (Receitas/Custos) (%)", 0.0, 10.0, 3.0, 0.5) / 100
    taxa_reinvestimento = st.slider("Taxa de Reinvestimento (MTIR) (%)", 2.0, 18.0, 10.0, 0.5) / 100

with st.sidebar.expander("📈 Preços e Cenários de Simulação", expanded=False):
    eficiencia_coleta_geral = st.slider("Eficiência Geral da Coleta (%)", 0, 100, 30, help="Fator mestre que afeta a quantidade de material coletado em todos os cenários.") / 100
    st.markdown("**Preços dos Materiais (R$/kg)**")
    precos_editaveis = {material: st.number_input(f"{material.replace('_', ' ')}", value=preco, step=0.1, key=f"preco_{material}") for material, preco in precos_iniciais.items()}
    st.markdown("**Fatores de Variação de Cenário**")
    fator_pessimista = st.slider("Cenário Pessimista (%)", 0, 100, 80) / 100
    fator_otimista = st.slider("Cenário Otimista (%)", 100, 200, 115) / 100

st.sidebar.divider()
st.sidebar.info(f"Última atualização: {pd.Timestamp.now(tz='America/Sao_Paulo').strftime('%d/%m/%Y %H:%M')}")


# --- 6. LÓGICA DE RENDERIZAÇÃO DAS PÁGINAS ---
if pagina_selecionada == "🔎 Análise Exploratória (EDA)":
    st.title("🔎 Análise Exploratória dos Dados de Coleta")
    st.markdown("O primeiro passo para qualquer projeção é entender o passado. Aqui, exploramos os dados históricos de coleta para identificar padrões, sazonalidades e anomalias.")
    st.divider()
    st.subheader("Evolução da Coleta Total Anual (Histórico)")
    df_coleta_anual = df_anuais.sum(axis=1).reset_index()
    df_coleta_anual.columns = ['Ano', 'Coleta Total (kg)']
    fig_evol_coleta = px.bar(df_coleta_anual, x='Ano', y='Coleta Total (kg)', text_auto='.3s', title="Volume Total Anual de Materiais Coletados")
    st.plotly_chart(fig_evol_coleta, use_container_width=True)
    st.warning("**Observação:** Note a queda acentuada na coleta de Plástico e Metal em 2023 em comparação com 2022 nos dados fornecidos. É crucial investigar se isso reflete a realidade operacional ou uma anomalia nos dados antes de prosseguir com projeções críticas.")
    
    # CORREÇÃO: Este bloco de colunas agora está DENTRO da condição da página EDA
    col1, col2 = st.columns(2)
    with col1:
        st.subheader("Coleta Mensal por Material (2024)")
        df_melt_mensal = df_2024.melt(id_vars='Mes', var_name='Material', value_name='Quantidade (kg)')
        fig_evol_mensal = px.line(df_melt_mensal, x='Mes', y='Quantidade (kg)', color='Material', title="Variação Mensal da Coleta por Material", markers=True)
        st.plotly_chart(fig_evol_mensal, use_container_width=True)
    with col2:
        st.subheader("Distribuição da Coleta Mensal (2024)")
        fig_boxplot = px.box(df_melt_mensal, x='Material', y='Quantidade (kg)', color='Material', title="Variação e Volatilidade da Coleta Mensal")
        st.plotly_chart(fig_boxplot, use_container_width=True)
        
    st.info("O **gráfico de linhas** mostra a tendência e sazonalidade ao longo do ano. O **boxplot** revela a volatilidade de cada material: caixas mais 'altas' indicam maior variação mensal, o que se traduz em maior risco e incerteza no faturamento.")

elif pagina_selecionada == "🎯 Simulação de Faturamento":
    st.title("🎯 Simulação e Projeção de Faturamento Anual")
    st.markdown("Utilizando a técnica de bootstrapping, simulamos 2.000 possíveis anos de faturamento com base na volatilidade dos dados de 2024 e na eficiência de coleta definida.")
    st.divider()
    
    cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
    simulacoes_faturamento = simular_faturamento_bootstrap(df_2024_numeric, precos_editaveis, cenarios, eficiencia_coleta_geral)
    
    kpi1, kpi2, kpi3 = st.columns(3)
    media_faturamento_base = np.mean(simulacoes_faturamento['Base'])
    desvio_padrao_base = np.std(simulacoes_faturamento['Base'])
    faturamento_material_base = {m: df_2024_numeric[m].sum() * p * eficiencia_coleta_geral for m, p in precos_editaveis.items()}
    material_mais_rentavel = max(faturamento_material_base, key=faturamento_material_base.get)

    kpi1.metric("Faturamento Anual Médio (Base)", formatar_brl(media_faturamento_base))
    kpi2.metric("Desvio Padrão do Faturamento", formatar_brl(desvio_padrao_base), help="Mede a volatilidade ou risco do faturamento. Valores mais altos indicam maior incerteza.")
    kpi3.metric("Material Mais Rentável (Base 2024)", material_mais_rentavel.replace('_', ' '))
    st.divider()
    
    col_g1, col_g2 = st.columns([6, 4])
    with col_g1:
        st.subheader("Distribuição do Faturamento Anual Simulado")
        fig_dist = go.Figure()
        for nome, data in simulacoes_faturamento.items():
            fig_dist.add_trace(go.Histogram(x=data, name=nome, histnorm='probability density', opacity=0.75))
        fig_dist.update_layout(barmode='overlay', title_text="Comparativo de Cenários de Faturamento", xaxis_title="Faturamento Anual (R$)", yaxis_title="Densidade de Probabilidade", legend_title_text='Cenário')
        st.plotly_chart(fig_dist, use_container_width=True)
    with col_g2:
        st.subheader("Composição do Faturamento (Base 2024)")
        df_faturamento_material = pd.DataFrame(list(faturamento_material_base.items()), columns=['Material', 'Faturamento'])
        fig_comp = px.pie(df_faturamento_material, values='Faturamento', names='Material', hole=0.4, title="Faturamento por Material")
        st.plotly_chart(fig_comp, use_container_width=True)

elif pagina_selecionada == "📊 Análise de Viabilidade":
    st.title("📊 Análise de Viabilidade Financeira e Risco")
    st.markdown("Esta é a etapa final, onde combinamos as projeções de receita com as premissas de investimento e custos para avaliar a viabilidade do projeto sob a ótica do risco.")
    
    cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
    simulacoes_faturamento = simular_faturamento_bootstrap(df_2024_numeric, precos_editaveis, cenarios, eficiencia_coleta_geral)
    
    cenario_analise = st.radio("Selecione o cenário para a análise detalhada:", options=list(cenarios.keys()), index=1, horizontal=True)
    st.divider()
    
    receita_anual_media = np.mean(simulacoes_faturamento[cenario_analise])
    fluxo_caixa_projeto = gerar_fluxo_caixa_projeto(investimento_inicial, receita_anual_media, custos_operacionais_anuais, horizonte_projeto, taxa_crescimento)
    
    vpl = calcular_vpl(fluxo_caixa_projeto, taxa_desconto)
    tir = calcular_tir(fluxo_caixa_projeto)
    mtir = calcular_mtir(fluxo_caixa_projeto, taxa_desconto, taxa_reinvestimento)
    payback_desc = calcular_payback_descontado(fluxo_caixa_projeto, taxa_desconto)
    
    tab_kpis, tab_fluxo, tab_risco, tab_resumo = st.tabs(["📈 Indicadores Chave", "📂 Fluxo de Caixa", "🎲 Análise de Risco (Monte Carlo)", "📋 Resumo Executivo"])

    with tab_kpis:
        st.subheader(f"Indicadores para o Cenário: {cenario_analise}")
        col1, col2, col3, col4 = st.columns(4)
        col1.metric("VPL", formatar_brl(vpl), "Viável" if vpl >= 0 else "Inviável")
        col2.metric("TIR", formatar_percentual(tir), "Superior à TMA" if pd.notna(tir) and tir > taxa_desconto else "Inferior à TMA")
        col3.metric("MTIR", formatar_percentual(mtir), "Superior à TMA" if pd.notna(mtir) and mtir > taxa_desconto else "Inferior à TMA")
        col4.metric("Payback Descontado", f"{payback_desc:.1f} anos" if not np.isinf(payback_desc) else "Não recupera")

    with tab_fluxo:
        st.subheader("Visualização do Fluxo de Caixa do Projeto")
        df_fluxo = pd.DataFrame({'Ano': list(range(horizonte_projeto + 1)), 'Fluxo de Caixa': fluxo_caixa_projeto})
        df_fluxo['Fluxo Acumulado'] = df_fluxo['Fluxo de Caixa'].cumsum()
        fig_fluxo = go.Figure(data=[go.Bar(name='Fluxo Anual', x=df_fluxo['Ano'], y=df_fluxo['Fluxo de Caixa'], marker_color=['#d62728' if x < 0 else '#2ca02c' for x in df_fluxo['Fluxo de Caixa']]), go.Scatter(name='Fluxo Acumulado', x=df_fluxo['Ano'], y=df_fluxo['Fluxo Acumulado'], mode='lines+markers')])
        fig_fluxo.update_layout(title_text="Fluxo de Caixa Anual e Acumulado", hovermode='x unified')
        st.plotly_chart(fig_fluxo, use_container_width=True)

    with tab_risco:
        st.subheader(f"Simulação Monte Carlo para o VPL (Cenário: {cenario_analise})")
        receitas_mc = np.random.choice(simulacoes_faturamento[cenario_analise], size=5000, replace=True)
        vpls_mc = [calcular_vpl(gerar_fluxo_caixa_projeto(investimento_inicial, r, custos_operacionais_anuais, horizonte_projeto, taxa_crescimento), taxa_desconto) for r in receitas_mc]
        prob_viabilidade = (np.array(vpls_mc) >= 0).mean()
        vpl_medio_mc = np.mean(vpls_mc)
        vpl_std_mc = np.std(vpls_mc)
        mc1, mc2, mc3 = st.columns(3)
        mc1.metric("VPL Médio Simulado", formatar_brl(vpl_medio_mc))
        mc2.metric("Probabilidade de Viabilidade", formatar_percentual(prob_viabilidade))
        mc3.metric("Desvio Padrão do VPL", formatar_brl(vpl_std_mc), help="Mede a volatilidade ou risco do VPL. Valores mais altos indicam maior incerteza.")
        fig_mc = px.histogram(x=vpls_mc, nbins=50, title=f"Distribuição do VPL ({len(vpls_mc)} Simulações)")
        fig_mc.add_vline(x=0, line_dash="dash", line_color="red", annotation_text="Viabilidade")
        st.plotly_chart(fig_mc, use_container_width=True)

    with tab_resumo:
        st.subheader("Resumo Executivo e Parecer Final")
        conclusoes = []
        if vpl >= 0: conclusoes.append(f"✅ **Projeto VIÁVEL** no cenário '{cenario_analise}', com um VPL de **{formatar_brl(vpl)}**.")
        else: conclusoes.append(f"❌ **Projeto INVIÁVEL** no cenário '{cenario_analise}', com um VPL de **{formatar_brl(vpl)}**.")
        if not pd.isna(tir) and tir > taxa_desconto: conclusoes.append(f"✅ A **TIR de {formatar_percentual(tir)} é superior à TMA de {formatar_percentual(taxa_desconto)}**, reforçando a atratividade.")
        else: conclusoes.append(f"❌ A **TIR de {formatar_percentual(tir)} é inferior à TMA**, um forte indicador contra o investimento.")
        if prob_viabilidade > 0.75: conclusoes.append(f"✅ A simulação de Monte Carlo aponta uma **alta probabilidade de sucesso de {formatar_percentual(prob_viabilidade)}**.")
        elif prob_viabilidade > 0.5: conclusoes.append(f"⚠️ A probabilidade de sucesso de **{formatar_percentual(prob_viabilidade)} é moderada**.")
        else: conclusoes.append(f"❌ A probabilidade de sucesso de **{formatar_percentual(prob_viabilidade)} é baixa**, indicando risco elevado.")
        st.markdown("#### Conclusões Chave:")
        for c in conclusoes: st.markdown(f"- {c}")
        st.markdown("#### Parecer Final:")
        if vpl > 0 and prob_viabilidade > 0.7:
            st.success("**RECOMENDAÇÃO: APROVAR O PROJETO.** Os indicadores são fortemente positivos e a análise de risco confere robustez à decisão.")
        elif vpl > 0 and prob_viabilidade > 0.5:
            st.warning("**RECOMENDAÇÃO: APROVAR COM CAUTELA.** O projeto é viável, mas a análise de risco mostra sensibilidade. Recomenda-se um plano de monitoramento de riscos focado em garantir as receitas projetadas.")
        else:
            st.error("**RECOMENDAÇÃO: REAVALIAR OU REJEITAR O PROJETO.** Os indicadores atuais, combinados com o perfil de risco, não justificam o investimento. Revisar premissas de receita, custos ou investimento inicial.")