Pegumenezes commited on
Commit
e08c501
·
verified ·
1 Parent(s): f299934

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +92 -98
src/streamlit_app.py CHANGED
@@ -16,34 +16,74 @@ st.set_page_config(
16
  st.markdown("""
17
  <style>
18
  .stMetric {
19
- border-radius: 10px;
20
- padding: 15px;
21
- background-color: #FFFFFF;
22
- border: 1px solid #E6E6E6;
23
- box-shadow: 0 4px 8px rgba(0,0,0,0.04);
24
  }
25
  .stTabs [data-baseweb="tab-list"] { gap: 24px; }
26
  .stTabs [data-baseweb="tab"] {
27
- height: 50px;
28
- background-color: #F0F2F6;
29
- border-radius: 4px 4px 0px 0px;
30
- padding: 10px 15px;
31
  }
32
  .stTabs [aria-selected="true"] { background-color: #FFFFFF; }
33
  </style>
34
  """, unsafe_allow_html=True)
35
 
36
 
37
- # --- 3. CARREGAMENTO DE DADOS E FUNÇÕES DE CÁLCULO ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  @st.cache_data
39
- def carregar_dados_e_funcoes():
40
- """Carrega todos os dados iniciais e retorna as funções de cálculo para evitar poluição do escopo global."""
41
-
42
- # --- DADOS ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  meses = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
44
  dados_2024 = {
45
- 'Mes': meses,
46
- 'Papel_Papelao': [8047, 11287, 8184, 10183, 5699, 5830, 7465, 5600, 2960, 5175, 9656, 3960],
47
  'Plastico': [6353, 8771, 6993, 8050, 4880, 5296, 5937, 4747, 2446, 4109, 7667, 3367],
48
  'Metal': [1061, 2025, 1121, 1832, 716, 936, 1553, 904, 361, 630, 1904, 569],
49
  'Vidro': [5248, 6929, 6014, 5821, 3697, 3655, 4950, 3360, 1580, 3261, 6173, 2357]
@@ -52,8 +92,7 @@ def carregar_dados_e_funcoes():
52
  df_2024_numeric = df_2024.drop(columns='Mes')
53
 
54
  dados_anuais = {
55
- 'Ano': [2022, 2023, 2024],
56
- 'Papel_Papelao': [18780, 58718, df_2024_numeric['Papel_Papelao'].sum()],
57
  'Plastico': [5340, 1041, df_2024_numeric['Plastico'].sum()],
58
  'Metal': [1300, 1737, df_2024_numeric['Metal'].sum()],
59
  'Vidro': [0, 725, df_2024_numeric['Vidro'].sum()]
@@ -61,69 +100,22 @@ def carregar_dados_e_funcoes():
61
  df_anuais = pd.DataFrame(dados_anuais).set_index('Ano')
62
 
63
  precos_iniciais = {'Papel_Papelao': 0.50, 'Plastico': 0.80, 'Metal': 2.00, 'Vidro': 0.30}
 
64
 
65
- # --- FUNÇÕES ---
66
- def formatar_brl(valor): return f"R$ {valor:,.2f}"
67
- def formatar_percentual(valor): return f"{valor:.2%}" if pd.notna(valor) and not np.isinf(valor) else "N/A"
68
-
69
- def calcular_vpl(fluxo_caixa, taxa_desconto):
70
- try: return npf.npv(taxa_desconto, fluxo_caixa)
71
- except: return np.nan
72
-
73
- def calcular_tir(fluxo_caixa):
74
- try:
75
- return npf.irr(fluxo_caixa) if np.any(np.sign(fluxo_caixa)) and np.any(np.sign(fluxo_caixa) * -1) else np.nan
76
- except: return np.nan
77
-
78
- def calcular_mtir(fluxo_caixa, taxa_desconto, taxa_reinvestimento):
79
- try:
80
- 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
81
- except: return np.nan
82
-
83
- def calcular_payback_descontado(fluxo_caixa, taxa_desconto):
84
- investimento_inicial = abs(fluxo_caixa[0])
85
- fluxo_acumulado_descontado = 0
86
- for periodo, valor in enumerate(fluxo_caixa[1:], 1):
87
- fluxo_acumulado_descontado += valor / ((1 + taxa_desconto) ** periodo)
88
- if fluxo_acumulado_descontado >= investimento_inicial:
89
- ultimo_fluxo_necessario = investimento_inicial - (fluxo_acumulado_descontado - (valor / ((1 + taxa_desconto) ** periodo)))
90
- return (periodo - 1) + (ultimo_fluxo_necessario / (valor / ((1 + taxa_desconto) ** periodo)))
91
- return np.inf
92
-
93
- def simular_faturamento_bootstrap(_df_dados_mensais_numeric, precos_dict, cenarios_dict, n_simulacoes=2000, seed=42):
94
- np.random.seed(seed)
95
- faturamentos_simulados = {nome: [] for nome in cenarios_dict.keys()}
96
- for nome_cen, fator in cenarios_dict.items():
97
- for _ in range(n_simulacoes):
98
- df_amostrado = _df_dados_mensais_numeric.sample(n=12, replace=True)
99
- faturamento_anual_iteracao = sum(df_amostrado[material].sum() * preco for material, preco in precos_dict.items())
100
- faturamentos_simulados[nome_cen].append(faturamento_anual_iteracao * fator)
101
- return {nome: np.array(data) for nome, data in faturamentos_simulados.items()}
102
-
103
- def gerar_fluxo_caixa_projeto(investimento_inicial, receita_anual_base, custos_operacionais_anuais, horizonte_anos, taxa_crescimento):
104
- fluxo_caixa = [-abs(investimento_inicial)]
105
- for ano in range(1, horizonte_anos + 1):
106
- fator_crescimento = (1 + taxa_crescimento) ** (ano - 1)
107
- fluxo_liquido_ano = (receita_anual_base * fator_crescimento) - (custos_operacionais_anuais * fator_crescimento)
108
- fluxo_caixa.append(fluxo_liquido_ano)
109
- return fluxo_caixa
110
-
111
- return df_2024, df_anuais, precos_iniciais, df_2024_numeric, locals()
112
-
113
- # --- 4. EXECUÇÃO INICIAL E SIDEBAR DE CONTROLES ---
114
- df_2024, df_anuais, precos_iniciais, df_2024_numeric, funcoes = carregar_dados_e_funcoes()
115
 
116
  st.sidebar.title(" Painel de Controle")
117
  st.sidebar.markdown("Use os menus abaixo para navegar entre as análises e ajustar os parâmetros do projeto.")
118
  st.sidebar.divider()
119
 
120
- pagina_selecionada = st.sidebar.radio(
121
- "Menu de Navegação",
122
  ["🔎 Análise Exploratória (EDA)", "🎯 Simulação de Faturamento", "📊 Análise de Viabilidade"],
123
  captions=["Análise dos dados históricos", "Projeção de receitas via simulação", "Cálculos de VPL, TIR e Risco"]
124
  )
125
  st.sidebar.divider()
126
 
 
127
  with st.sidebar.expander("⚙️ Premissas Financeiras do Projeto", expanded=True):
128
  investimento_inicial = st.number_input("Investimento Inicial (R$)", min_value=1000.0, value=150000.0, step=10000.0)
129
  custos_operacionais = st.number_input("Custos Operacionais Anuais (R$)", min_value=0.0, value=50000.0, step=5000.0)
@@ -140,20 +132,21 @@ with st.sidebar.expander("📈 Preços e Cenários de Simulação", expanded=Fal
140
  st.sidebar.divider()
141
  st.sidebar.info(f"Última atualização: {pd.Timestamp.now(tz='America/Sao_Paulo').strftime('%d/%m/%Y %H:%M')}")
142
 
 
 
 
143
 
144
- # --- 5. LÓGICA DE RENDERIZAÇÃO DAS PÁGINAS ---
145
  if pagina_selecionada == "🔎 Análise Exploratória (EDA)":
 
146
  st.title("🔎 Análise Exploratória dos Dados de Coleta")
147
  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.")
148
  st.divider()
149
-
150
  st.subheader("Evolução da Coleta Total Anual (Histórico)")
151
  df_coleta_anual = df_anuais.sum(axis=1).reset_index()
152
  df_coleta_anual.columns = ['Ano', 'Coleta Total (kg)']
153
  fig_evol_coleta = px.bar(df_coleta_anual, x='Ano', y='Coleta Total (kg)', text_auto='.3s', title="Volume Total Anual de Materiais Coletados")
154
  st.plotly_chart(fig_evol_coleta, use_container_width=True)
155
  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.")
156
-
157
  col1, col2 = st.columns(2)
158
  with col1:
159
  st.subheader("Coleta Mensal por Material (2024)")
@@ -166,13 +159,14 @@ if pagina_selecionada == "🔎 Análise Exploratória (EDA)":
166
  st.plotly_chart(fig_boxplot, use_container_width=True)
167
  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.")
168
 
 
169
  elif pagina_selecionada == "🎯 Simulação de Faturamento":
170
  st.title("🎯 Simulação e Projeção de Faturamento Anual")
171
  st.markdown("Utilizando a técnica de bootstrapping, simulamos 2.000 possíveis anos de faturamento com base na volatilidade dos dados de 2024. Isso nos dá uma visão probabilística das receitas do projeto.")
172
  st.divider()
173
 
174
  cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
175
- simulacoes_faturamento = funcoes['simular_faturamento_bootstrap'](df_2024_numeric, precos_editaveis, cenarios)
176
 
177
  kpi1, kpi2, kpi3 = st.columns(3)
178
  media_faturamento_base = np.mean(simulacoes_faturamento['Base'])
@@ -180,8 +174,8 @@ elif pagina_selecionada == "🎯 Simulação de Faturamento":
180
  faturamento_material_base = {m: df_2024_numeric[m].sum() * p for m, p in precos_editaveis.items()}
181
  material_mais_rentavel = max(faturamento_material_base, key=faturamento_material_base.get)
182
 
183
- kpi1.metric("Faturamento Anual Médio (Base)", funcoes['formatar_brl'](media_faturamento_base))
184
- kpi2.metric("Intervalo de Confiança 90% (Base)", f"{funcoes['formatar_brl'](p05_base)} - {funcoes['formatar_brl'](p95_base)}")
185
  kpi3.metric("Material Mais Rentável (Base 2024)", material_mais_rentavel.replace('_', ' '))
186
  st.divider()
187
 
@@ -204,27 +198,27 @@ elif pagina_selecionada == "📊 Análise de Viabilidade":
204
  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.")
205
 
206
  cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
207
- simulacoes_faturamento = funcoes['simular_faturamento_bootstrap'](df_2024_numeric, precos_editaveis, cenarios)
208
 
209
  cenario_analise = st.radio("Selecione o cenário para a análise detalhada:", options=list(cenarios.keys()), index=1, horizontal=True)
210
  st.divider()
211
 
212
  receita_anual_media = np.mean(simulacoes_faturamento[cenario_analise])
213
- fluxo_caixa_projeto = funcoes['gerar_fluxo_caixa_projeto'](investimento_inicial, receita_anual_media, custos_operacionais, horizonte_projeto, taxa_crescimento)
214
 
215
- vpl = funcoes['calcular_vpl'](fluxo_caixa_projeto, taxa_desconto)
216
- tir = funcoes['calcular_tir'](fluxo_caixa_projeto)
217
- mtir = funcoes['calcular_mtir'](fluxo_caixa_projeto, taxa_desconto, taxa_reinvestimento)
218
- payback_desc = funcoes['calcular_payback_descontado'](fluxo_caixa_projeto, taxa_desconto)
219
 
220
  tab_kpis, tab_fluxo, tab_risco, tab_resumo = st.tabs(["📈 Indicadores Chave", "📂 Fluxo de Caixa", "🎲 Análise de Risco (Monte Carlo)", "📋 Resumo Executivo"])
221
 
222
  with tab_kpis:
223
  st.subheader(f"Indicadores para o Cenário: {cenario_analise}")
224
  col1, col2, col3, col4 = st.columns(4)
225
- col1.metric("VPL", funcoes['formatar_brl'](vpl), "Viável" if vpl >= 0 else "Inviável")
226
- col2.metric("TIR", funcoes['formatar_percentual'](tir), "Superior à TMA" if pd.notna(tir) and tir > taxa_desconto else "Inferior à TMA")
227
- col3.metric("MTIR", funcoes['formatar_percentual'](mtir), "Superior à TMA" if pd.notna(mtir) and mtir > taxa_desconto else "Inferior à TMA")
228
  col4.metric("Payback Descontado", f"{payback_desc:.1f} anos" if not np.isinf(payback_desc) else "Não recupera")
229
 
230
  with tab_fluxo:
@@ -241,15 +235,15 @@ elif pagina_selecionada == "📊 Análise de Viabilidade":
241
  with tab_risco:
242
  st.subheader(f"Simulação Monte Carlo para o VPL (Cenário: {cenario_analise})")
243
  receitas_mc = np.random.choice(simulacoes_faturamento[cenario_analise], size=5000, replace=True)
244
- vpls_mc = [funcoes['calcular_vpl'](funcoes['gerar_fluxo_caixa_projeto'](investimento_inicial, r, custos_operacionais, horizonte_projeto, taxa_crescimento), taxa_desconto) for r in receitas_mc]
245
 
246
  prob_viabilidade = (np.array(vpls_mc) >= 0).mean()
247
  vpl_medio_mc = np.mean(vpls_mc)
248
 
249
  mc1, mc2, mc3 = st.columns(3)
250
- mc1.metric("VPL Médio Simulado", funcoes['formatar_brl'](vpl_medio_mc))
251
- mc2.metric("Probabilidade de Viabilidade", funcoes['formatar_percentual'](prob_viabilidade))
252
- mc3.metric("Intervalo 90% do VPL", f"{funcoes['formatar_brl'](np.percentile(vpls_mc, 5))} a {funcoes['formatar_brl'](np.percentile(vpls_mc, 95))}")
253
 
254
  fig_mc = px.histogram(x=vpls_mc, nbins=50, title=f"Distribuição do VPL ({len(vpls_mc)} Simulações)")
255
  fig_mc.add_vline(x=0, line_dash="dash", line_color="red", annotation_text="Viabilidade")
@@ -258,15 +252,15 @@ elif pagina_selecionada == "📊 Análise de Viabilidade":
258
  with tab_resumo:
259
  st.subheader("Resumo Executivo e Parecer Final")
260
  conclusoes = []
261
- if vpl >= 0: conclusoes.append(f"✅ **Projeto VIÁVEL** no cenário '{cenario_analise}', com um VPL de **{funcoes['formatar_brl'](vpl)}**.")
262
- else: conclusoes.append(f"❌ **Projeto INVIÁVEL** no cenário '{cenario_analise}', com um VPL de **{funcoes['formatar_brl'](vpl)}**.")
263
 
264
- if not pd.isna(tir) and tir > taxa_desconto: conclusoes.append(f"✅ A **TIR de {funcoes['formatar_percentual'](tir)} é superior à TMA de {funcoes['formatar_percentual'](taxa_desconto)}**, reforçando a atratividade.")
265
- else: conclusoes.append(f"❌ A **TIR de {funcoes['formatar_percentual'](tir)} é inferior à TMA**, um forte indicador contra o investimento.")
266
 
267
- if prob_viabilidade > 0.75: conclusoes.append(f"✅ A simulação de Monte Carlo aponta uma **alta probabilidade de sucesso de {funcoes['formatar_percentual'](prob_viabilidade)}**.")
268
- elif prob_viabilidade > 0.5: conclusoes.append(f"⚠️ A probabilidade de sucesso de **{funcoes['formatar_percentual'](prob_viabilidade)} é moderada**.")
269
- else: conclusoes.append(f"❌ A probabilidade de sucesso de **{funcoes['formatar_percentual'](prob_viabilidade)} é baixa**, indicando risco elevado.")
270
 
271
  st.markdown("#### Conclusões Chave:")
272
  for c in conclusoes: st.markdown(f"- {c}")
@@ -275,6 +269,6 @@ elif pagina_selecionada == "📊 Análise de Viabilidade":
275
  if vpl > 0 and prob_viabilidade > 0.7:
276
  st.success("**RECOMENDAÇÃO: APROVAR O PROJETO.** Os indicadores são fortemente positivos e a análise de risco confere robustez à decisão.")
277
  elif vpl > 0 and prob_viabilidade > 0.5:
278
- st.warning("**RECOMENDAÇÃO: APROVAR COM CAUTELA.** O projeto é viável no cenário base, mas a análise de risco mostra sensibilidade. Recomenda-se um plano de monitoramento de riscos focado em garantir as receitas projetadas.")
279
  else:
280
- 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.")
 
16
  st.markdown("""
17
  <style>
18
  .stMetric {
19
+ border-radius: 10px; padding: 15px; background-color: #FFFFFF;
20
+ border: 1px solid #E6E6E6; box-shadow: 0 4px 8px rgba(0,0,0,0.04);
 
 
 
21
  }
22
  .stTabs [data-baseweb="tab-list"] { gap: 24px; }
23
  .stTabs [data-baseweb="tab"] {
24
+ height: 50px; background-color: #F0F2F6; border-radius: 4px 4px 0px 0px; padding: 10px 15px;
 
 
 
25
  }
26
  .stTabs [aria-selected="true"] { background-color: #FFFFFF; }
27
  </style>
28
  """, unsafe_allow_html=True)
29
 
30
 
31
+ # --- 3. DEFINIÇÃO DAS FUNÇÕES GLOBAIS ---
32
+ # Todas as funções foram movidas para o escopo global para evitar o erro de cache.
33
+
34
+ def formatar_brl(valor): return f"R$ {valor:,.2f}"
35
+ def formatar_percentual(valor): return f"{valor:.2%}" if pd.notna(valor) and not np.isinf(valor) else "N/A"
36
+
37
+ def calcular_vpl(fluxo_caixa, taxa_desconto):
38
+ try: return npf.npv(taxa_desconto, fluxo_caixa)
39
+ except: return np.nan
40
+
41
+ def calcular_tir(fluxo_caixa):
42
+ try:
43
+ return npf.irr(fluxo_caixa) if np.any(np.sign(fluxo_caixa)) and np.any(np.sign(fluxo_caixa) * -1) else np.nan
44
+ except: return np.nan
45
+
46
+ def calcular_mtir(fluxo_caixa, taxa_desconto, taxa_reinvestimento):
47
+ try:
48
+ 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
49
+ except: return np.nan
50
+
51
+ def calcular_payback_descontado(fluxo_caixa, taxa_desconto):
52
+ investimento_inicial = abs(fluxo_caixa[0])
53
+ fluxo_acumulado_descontado = 0
54
+ for periodo, valor in enumerate(fluxo_caixa[1:], 1):
55
+ fluxo_acumulado_descontado += valor / ((1 + taxa_desconto) ** periodo)
56
+ if fluxo_acumulado_descontado >= investimento_inicial:
57
+ ultimo_fluxo_necessario = investimento_inicial - (fluxo_acumulado_descontado - (valor / ((1 + taxa_desconto) ** periodo)))
58
+ return (periodo - 1) + (ultimo_fluxo_necessario / (valor / ((1 + taxa_desconto) ** periodo)))
59
+ return np.inf
60
+
61
  @st.cache_data
62
+ def simular_faturamento_bootstrap(_df_dados_mensais_numeric, precos_dict, cenarios_dict, n_simulacoes=2000, seed=42):
63
+ np.random.seed(seed)
64
+ faturamentos_simulados = {nome: [] for nome in cenarios_dict.keys()}
65
+ for nome_cen, fator in cenarios_dict.items():
66
+ for _ in range(n_simulacoes):
67
+ df_amostrado = _df_dados_mensais_numeric.sample(n=12, replace=True)
68
+ faturamento_anual_iteracao = sum(df_amostrado[material].sum() * preco for material, preco in precos_dict.items())
69
+ faturamentos_simulados[nome_cen].append(faturamento_anual_iteracao * fator)
70
+ return {nome: np.array(data) for nome, data in faturamentos_simulados.items()}
71
+
72
+ def gerar_fluxo_caixa_projeto(investimento_inicial, receita_anual_base, custos_operacionais_anuais, horizonte_anos, taxa_crescimento):
73
+ fluxo_caixa = [-abs(investimento_inicial)]
74
+ for ano in range(1, horizonte_anos + 1):
75
+ fator_crescimento = (1 + taxa_crescimento) ** (ano - 1)
76
+ fluxo_liquido_ano = (receita_anual_base * fator_crescimento) - (custos_operacionais_anuais * fator_crescimento)
77
+ fluxo_caixa.append(fluxo_liquido_ano)
78
+ return fluxo_caixa
79
+
80
+ # --- 4. CARREGAMENTO DE DADOS (FUNÇÃO CACHEADA) ---
81
+ @st.cache_data
82
+ def carregar_dados():
83
+ """Carrega apenas os dados iniciais do projeto. É seguro cachear esta função."""
84
  meses = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
85
  dados_2024 = {
86
+ 'Mes': meses, 'Papel_Papelao': [8047, 11287, 8184, 10183, 5699, 5830, 7465, 5600, 2960, 5175, 9656, 3960],
 
87
  'Plastico': [6353, 8771, 6993, 8050, 4880, 5296, 5937, 4747, 2446, 4109, 7667, 3367],
88
  'Metal': [1061, 2025, 1121, 1832, 716, 936, 1553, 904, 361, 630, 1904, 569],
89
  'Vidro': [5248, 6929, 6014, 5821, 3697, 3655, 4950, 3360, 1580, 3261, 6173, 2357]
 
92
  df_2024_numeric = df_2024.drop(columns='Mes')
93
 
94
  dados_anuais = {
95
+ 'Ano': [2022, 2023, 2024], 'Papel_Papelao': [18780, 58718, df_2024_numeric['Papel_Papelao'].sum()],
 
96
  'Plastico': [5340, 1041, df_2024_numeric['Plastico'].sum()],
97
  'Metal': [1300, 1737, df_2024_numeric['Metal'].sum()],
98
  'Vidro': [0, 725, df_2024_numeric['Vidro'].sum()]
 
100
  df_anuais = pd.DataFrame(dados_anuais).set_index('Ano')
101
 
102
  precos_iniciais = {'Papel_Papelao': 0.50, 'Plastico': 0.80, 'Metal': 2.00, 'Vidro': 0.30}
103
+ return df_2024, df_anuais, precos_iniciais, df_2024_numeric
104
 
105
+ # --- 5. EXECUÇÃO INICIAL E SIDEBAR DE CONTROLES ---
106
+ df_2024, df_anuais, precos_iniciais, df_2024_numeric = carregar_dados()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  st.sidebar.title(" Painel de Controle")
109
  st.sidebar.markdown("Use os menus abaixo para navegar entre as análises e ajustar os parâmetros do projeto.")
110
  st.sidebar.divider()
111
 
112
+ pagina_selecionada = st.sidebar.radio( "Menu de Navegação",
 
113
  ["🔎 Análise Exploratória (EDA)", "🎯 Simulação de Faturamento", "📊 Análise de Viabilidade"],
114
  captions=["Análise dos dados históricos", "Projeção de receitas via simulação", "Cálculos de VPL, TIR e Risco"]
115
  )
116
  st.sidebar.divider()
117
 
118
+ # Parâmetros Editáveis na Sidebar (código igual ao anterior)
119
  with st.sidebar.expander("⚙️ Premissas Financeiras do Projeto", expanded=True):
120
  investimento_inicial = st.number_input("Investimento Inicial (R$)", min_value=1000.0, value=150000.0, step=10000.0)
121
  custos_operacionais = st.number_input("Custos Operacionais Anuais (R$)", min_value=0.0, value=50000.0, step=5000.0)
 
132
  st.sidebar.divider()
133
  st.sidebar.info(f"Última atualização: {pd.Timestamp.now(tz='America/Sao_Paulo').strftime('%d/%m/%Y %H:%M')}")
134
 
135
+ # --- 6. LÓGICA DE RENDERIZAÇÃO DAS PÁGINAS ---
136
+ # O código aqui dentro permanece o mesmo, mas agora chama as funções globais diretamente.
137
+ # Exemplo de chamada direta: formatar_brl(vpl) em vez de funcoes['formatar_brl'](vpl)
138
 
 
139
  if pagina_selecionada == "🔎 Análise Exploratória (EDA)":
140
+ # ... (código desta página não precisa de alteração nas chamadas)
141
  st.title("🔎 Análise Exploratória dos Dados de Coleta")
142
  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.")
143
  st.divider()
 
144
  st.subheader("Evolução da Coleta Total Anual (Histórico)")
145
  df_coleta_anual = df_anuais.sum(axis=1).reset_index()
146
  df_coleta_anual.columns = ['Ano', 'Coleta Total (kg)']
147
  fig_evol_coleta = px.bar(df_coleta_anual, x='Ano', y='Coleta Total (kg)', text_auto='.3s', title="Volume Total Anual de Materiais Coletados")
148
  st.plotly_chart(fig_evol_coleta, use_container_width=True)
149
  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.")
 
150
  col1, col2 = st.columns(2)
151
  with col1:
152
  st.subheader("Coleta Mensal por Material (2024)")
 
159
  st.plotly_chart(fig_boxplot, use_container_width=True)
160
  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.")
161
 
162
+
163
  elif pagina_selecionada == "🎯 Simulação de Faturamento":
164
  st.title("🎯 Simulação e Projeção de Faturamento Anual")
165
  st.markdown("Utilizando a técnica de bootstrapping, simulamos 2.000 possíveis anos de faturamento com base na volatilidade dos dados de 2024. Isso nos dá uma visão probabilística das receitas do projeto.")
166
  st.divider()
167
 
168
  cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
169
+ simulacoes_faturamento = simular_faturamento_bootstrap(df_2024_numeric, precos_editaveis, cenarios)
170
 
171
  kpi1, kpi2, kpi3 = st.columns(3)
172
  media_faturamento_base = np.mean(simulacoes_faturamento['Base'])
 
174
  faturamento_material_base = {m: df_2024_numeric[m].sum() * p for m, p in precos_editaveis.items()}
175
  material_mais_rentavel = max(faturamento_material_base, key=faturamento_material_base.get)
176
 
177
+ kpi1.metric("Faturamento Anual Médio (Base)", formatar_brl(media_faturamento_base))
178
+ kpi2.metric("Intervalo de Confiança 90% (Base)", f"{formatar_brl(p05_base)} - {formatar_brl(p95_base)}")
179
  kpi3.metric("Material Mais Rentável (Base 2024)", material_mais_rentavel.replace('_', ' '))
180
  st.divider()
181
 
 
198
  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.")
199
 
200
  cenarios = {'Pessimista': fator_pessimista, 'Base': 1.0, 'Otimista': fator_otimista}
201
+ simulacoes_faturamento = simular_faturamento_bootstrap(df_2024_numeric, precos_editaveis, cenarios)
202
 
203
  cenario_analise = st.radio("Selecione o cenário para a análise detalhada:", options=list(cenarios.keys()), index=1, horizontal=True)
204
  st.divider()
205
 
206
  receita_anual_media = np.mean(simulacoes_faturamento[cenario_analise])
207
+ fluxo_caixa_projeto = gerar_fluxo_caixa_projeto(investimento_inicial, receita_anual_media, custos_operacionais, horizonte_projeto, taxa_crescimento)
208
 
209
+ vpl = calcular_vpl(fluxo_caixa_projeto, taxa_desconto)
210
+ tir = calcular_tir(fluxo_caixa_projeto)
211
+ mtir = calcular_mtir(fluxo_caixa_projeto, taxa_desconto, taxa_reinvestimento)
212
+ payback_desc = calcular_payback_descontado(fluxo_caixa_projeto, taxa_desconto)
213
 
214
  tab_kpis, tab_fluxo, tab_risco, tab_resumo = st.tabs(["📈 Indicadores Chave", "📂 Fluxo de Caixa", "🎲 Análise de Risco (Monte Carlo)", "📋 Resumo Executivo"])
215
 
216
  with tab_kpis:
217
  st.subheader(f"Indicadores para o Cenário: {cenario_analise}")
218
  col1, col2, col3, col4 = st.columns(4)
219
+ col1.metric("VPL", formatar_brl(vpl), "Viável" if vpl >= 0 else "Inviável")
220
+ col2.metric("TIR", formatar_percentual(tir), "Superior à TMA" if pd.notna(tir) and tir > taxa_desconto else "Inferior à TMA")
221
+ col3.metric("MTIR", formatar_percentual(mtir), "Superior à TMA" if pd.notna(mtir) and mtir > taxa_desconto else "Inferior à TMA")
222
  col4.metric("Payback Descontado", f"{payback_desc:.1f} anos" if not np.isinf(payback_desc) else "Não recupera")
223
 
224
  with tab_fluxo:
 
235
  with tab_risco:
236
  st.subheader(f"Simulação Monte Carlo para o VPL (Cenário: {cenario_analise})")
237
  receitas_mc = np.random.choice(simulacoes_faturamento[cenario_analise], size=5000, replace=True)
238
+ vpls_mc = [calcular_vpl(gerar_fluxo_caixa_projeto(investimento_inicial, r, custos_operacionais, horizonte_projeto, taxa_crescimento), taxa_desconto) for r in receitas_mc]
239
 
240
  prob_viabilidade = (np.array(vpls_mc) >= 0).mean()
241
  vpl_medio_mc = np.mean(vpls_mc)
242
 
243
  mc1, mc2, mc3 = st.columns(3)
244
+ mc1.metric("VPL Médio Simulado", formatar_brl(vpl_medio_mc))
245
+ mc2.metric("Probabilidade de Viabilidade", formatar_percentual(prob_viabilidade))
246
+ mc3.metric("Intervalo 90% do VPL", f"{formatar_brl(np.percentile(vpls_mc, 5))} a {formatar_brl(np.percentile(vpls_mc, 95))}")
247
 
248
  fig_mc = px.histogram(x=vpls_mc, nbins=50, title=f"Distribuição do VPL ({len(vpls_mc)} Simulações)")
249
  fig_mc.add_vline(x=0, line_dash="dash", line_color="red", annotation_text="Viabilidade")
 
252
  with tab_resumo:
253
  st.subheader("Resumo Executivo e Parecer Final")
254
  conclusoes = []
255
+ if vpl >= 0: conclusoes.append(f"✅ **Projeto VIÁVEL** no cenário '{cenario_analise}', com um VPL de **{formatar_brl(vpl)}**.")
256
+ else: conclusoes.append(f"❌ **Projeto INVIÁVEL** no cenário '{cenario_analise}', com um VPL de **{formatar_brl(vpl)}**.")
257
 
258
+ 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.")
259
+ else: conclusoes.append(f"❌ A **TIR de {formatar_percentual(tir)} é inferior à TMA**, um forte indicador contra o investimento.")
260
 
261
+ 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)}**.")
262
+ elif prob_viabilidade > 0.5: conclusoes.append(f"⚠️ A probabilidade de sucesso de **{formatar_percentual(prob_viabilidade)} é moderada**.")
263
+ else: conclusoes.append(f"❌ A probabilidade de sucesso de **{formatar_percentual(prob_viabilidade)} é baixa**, indicando risco elevado.")
264
 
265
  st.markdown("#### Conclusões Chave:")
266
  for c in conclusoes: st.markdown(f"- {c}")
 
269
  if vpl > 0 and prob_viabilidade > 0.7:
270
  st.success("**RECOMENDAÇÃO: APROVAR O PROJETO.** Os indicadores são fortemente positivos e a análise de risco confere robustez à decisão.")
271
  elif vpl > 0 and prob_viabilidade > 0.5:
272
+ 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.")
273
  else:
274
+ 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.")