prev_ibge = await FileAttachment ('dados/base_dados/projecoes_ibge.csv' ). csv ()
prev_arima_ets = await FileAttachment ('dados/arima-ets/previsoes_2020_2070.csv' ). csv ()
prev_lm = await FileAttachment ('dados/lc-lm/previsoes_lm.csv' ). csv ()
prev_lc = await FileAttachment ('dados/lc-lm/previsoes_lc.csv' ). csv ()
prev_comb = await FileAttachment ('dados/combinado/previsoes_2020_2070_comb.csv' ). csv ()
modelos = ["ARIMA+ETS" , "Lee-Carter" , "Lee-Miller" , "IBGE" , "MLP-Shallow" ]
regioes = ["Brasil" , "Centro-Oeste" , "Nordeste" , "Norte" , "Sudeste" , "Sul" , "Acre" , "Alagoas" , "Amapá" , "Amazonas" , "Bahia" , "Ceará" , "Distrito Federal" , "Espírito Santo" , "Goiás" , "Maranhão" , "Mato Grosso" , "Mato Grosso do Sul" , "Minas Gerais" , "Pará" , "Paraíba" , "Paraná" , "Pernambuco" , "Piauí" , "Rio de Janeiro" , "Rio Grande do Norte" , "Rio Grande do Sul" , "Rondônia" , "Roraima" , "Santa Catarina" , "São Paulo" , "Sergipe" , "Tocantins" ]
// Definição do componente reativo
// Define o componente de seleção
viewof seletores2 = {
const form = html `<form style="
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 30px;
justify-content: center;
">
<!-- Select para Região -->
<div style="min-width: 200px; max-width: 300px;">
<label style="display: block; text-align: center; margin-bottom: 8px;">Local:</label>
<select name="regiao" style="
display: block;
margin: 0 auto;
padding: 6px 12px;
border: 1px solid #ccc;
border-radius: 20px;
font-size: 16px;
text-align: center;
width: fit-content;
min-width: 180px;
background-color: #f8f9fa;
">
${ regioes. map (r => `<option value=" ${ r} "> ${ r} </option>` ). join ('' )}
</select>
</div>
<!-- Checkboxes para Modelos -->
<div style="min-width: 200px; max-width: 300px;">
<label style="display: block; text-align: center; margin-bottom: 8px;">Modelo:</label>
<select name="modelo" style="
display: block;
margin: 0 auto;
padding: 6px 12px;
border: 1px solid #ccc;
border-radius: 20px;
font-size: 16px;
text-align: center;
width: fit-content;
min-width: 180px;
background-color: #f8f9fa;
">
${ modelos. map (r => `<option value=" ${ r} "> ${ r} </option>` ). join ('' )}
</select>
</div>
<!-- Radio para Sexo -->
<div style="min-width: 200px; max-width: 300px;">
<label style="display: block; text-align: center; margin-bottom: 8px;">Sexo:</label>
<div style="
display: flex;
gap: 15px;
justify-content: center;
">
<label style="display: flex; align-items: center; gap: 5px;">
<input type="radio" name="sexo" value="Ambos" checked>
Ambos
</label>
<label style="display: flex; align-items: center; gap: 5px;">
<input type="radio" name="sexo" value="Homens">
Homens
</label>
<label style="display: flex; align-items: center; gap: 5px;">
<input type="radio" name="sexo" value="Mulheres">
Mulheres
</label>
</div>
</div>
</form>` ;
// Definir valor inicial
form. value = {
regiao : regioes[0 ],
modelo : 'ARIMA+ETS' ,
sexo : 'Ambos'
};
// Atualizar valor ao modificar select
form. querySelector ('select[name="regiao"]' ). addEventListener ('change' , e => {
form. value = {
... form. value ,
regiao : e. target . value
};
form. dispatchEvent (new Event ('input' ));
});
// Atualizar valor ao modificar checkboxes
form. querySelector ('select[name="modelo"]' ). addEventListener ('change' , e => {
form. value = {
... form. value ,
modelo : e. target . value
};
form. dispatchEvent (new Event ('input' ));
});
// Atualizar valor ao modificar radios
const radios = form. querySelectorAll ('input[name="sexo"]' );
for (const radio of radios) {
radio. addEventListener ('change' , () => {
form. value = {
... form. value ,
sexo : radio. value
};
form. dispatchEvent (new Event ('input' ));
});
}
return form;
}
// Extrair valores individuais em células separadas
regiao2 = seletores2. regiao
modelo2 = seletores2. modelo
sexo = seletores2. sexo
data_filter0 = prev_ibge. filter (d => d. regiao === regiao2 && d. Sexo === sexo). map (d => ({
ano : + d. Ano ,
faixa : d. faixa_etaria ,
prev : Math . log (d. nqx )
}))
data_filter1 = prev_arima_ets. filter (d => d. LOCAL === regiao2 && d. SEXO === sexo). map (d => ({
ano : + d. ANO ,
faixa : d. IDADE ,
prev : Math . log (d. Previsao )
}))
data_filter2 = prev_lm. filter (d => d. regiao === regiao2 && d. taxa === sexo). map (d => ({
ano : + d. ano ,
faixa : d. Faixa_Etaria ,
prev : Math . log (d. previsto )
}))
data_filter3 = prev_lc. filter (d => d. regiao === regiao2 && d. taxa === sexo). map (d => ({
ano : + d. ano ,
faixa : d. Faixa_Etaria ,
prev : Math . log (d. previsto )
}))
data_filter4 = prev_comb. filter (d => d. LOCAL === regiao2 && d. SEXO === sexo). map (d => ({
ano : + d. ANO ,
faixa : d. IDADE ,
prev : Math . log (d. Previsao )
}))
// Função principal para criar gráficos
function createChart (data, title) {
const ptBRLocaleDefinition = {
decimal : "," ,
thousands : "" ,
grouping : [3 ],
currency : ["R$" , "" ]
};
d3. formatDefaultLocale (ptBRLocaleDefinition);
const width = 760 ;
const height = 500 ;
const margin = {top : 30 , right : 20 , bottom : 40 , left : 50 };
const svg = d3. create ("svg" )
. attr ("viewBox" , [0 , 0 , width, height])
. attr ("width" , width)
. attr ("height" , height)
. attr ("style" , "max-width: 100%; height: auto; height: intrinsic; font: 10px sans-serif;" )
. style ("-webkit-tap-highlight-color" , "transparent" )
. style ("overflow" , "visible" );
// Escalas
const x = d3. scalePoint ()
. domain ([... new Set (data. map (d => d. faixa ))])
. range ([margin. left , width - margin. right ])
. padding (0.5 );
const y = d3. scaleLinear ()
. domain ([- 11 , 0 ])
. range ([height - margin. bottom , margin. top ]);
// Eixos
svg. append ("g" )
. attr ("transform" , `translate(0, ${ height - margin. bottom } )` )
. call (d3. axisBottom (x))
. selectAll ("text" )
. style ("text-anchor" , "end" )
. attr ("dx" , "-.8em" )
. attr ("dy" , ".15em" )
. attr ("transform" , "rotate(-45)" );
svg. append ("text" )
. attr ("text-anchor" , "middle" )
. attr ("x" , width / 2 )
. attr ("y" , height) // Posição abaixo do eixo
. style ("font-size" , "14px" )
. style ("fill" , "currentColor" )
. text ("Faixa Etária" );
svg. append ("g" )
. attr ("transform" , `translate( ${ margin. left } ,0)` )
. call (d3. axisLeft (y). ticks (height / 40 ))
. call (g => g. select (".domain" ). remove ())
. style ("font-size" , "12px" )
. call (g => g. selectAll (".tick line" ). clone ()
. attr ("x2" , width - margin. left - margin. right )
. attr ("stroke-opacity" , 0.1 ))
. call (g => g. append ("text" )
. attr ("transform" , "rotate(-90)" )
. attr ("x" , - (height / 2 ))
. attr ("y" , - margin. left + 15 )
. attr ("fill" , "currentColor" )
. attr ("text-anchor" , "middle" )
. style ("font-size" , "18px" )
. text ("log(Mx)" ));
// Gradiente e cores
const colorScale = d3. scaleSequential (d3. interpolateViridis )
. domain ([2024 , 2070 ]);
const defs = svg. append ("defs" );
const nestedData = d3. groups (data, d => d. ano );
nestedData. forEach (([year, values]) => {
const gradientId = `gradient- ${ title} - ${ year} ` ;
const gradient = defs. append ("linearGradient" )
. attr ("id" , gradientId)
. attr ("gradientUnits" , "userSpaceOnUse" )
. attr ("x1" , margin. left )
. attr ("y1" , 0 )
. attr ("x2" , width - margin. right )
. attr ("y2" , 0 );
gradient. append ("stop" )
. attr ("offset" , "0%" )
. attr ("stop-color" , colorScale (year));
gradient. append ("stop" )
. attr ("offset" , "100%" )
. attr ("stop-color" , colorScale (Math . min (year + 10 , 2070 )));
});
// Linhas
const line = d3. line ()
. x (d => x (d. faixa ))
. y (d => y (d. prev ));
nestedData. forEach (([year, values]) => {
svg. append ("path" )
. datum (values)
. attr ("fill" , "none" )
. attr ("stroke" , `url(#gradient- ${ title} - ${ year} )` )
. attr ("stroke-width" , 2.5 )
. attr ("d" , line);
});
// Legenda
const legendWidth = 200 ;
const legendHeight = 20 ;
const legendX = width - margin. right - legendWidth;
const legendY = 400 ;
const legendGradient = defs. append ("linearGradient" )
. attr ("id" , `legend- ${ title} ` )
. attr ("x1" , "0%" )
. attr ("y1" , "0%" )
. attr ("x2" , "100%" )
. attr ("y2" , "0%" );
const years = [2024 , 2035 , 2045 , 2055 , 2070 ];
years. forEach ((year, i) => {
legendGradient. append ("stop" )
. attr ("offset" , ` ${ i * 100 / (years. length - 1 )} %` )
. attr ("stop-color" , colorScale (year));
});
svg. append ("rect" )
. attr ("x" , legendX)
. attr ("y" , legendY)
. attr ("width" , legendWidth)
. attr ("height" , legendHeight)
. style ("fill" , `url(#legend- ${ title} )` );
svg. append ("text" )
. attr ("x" , legendX)
. attr ("y" , legendY - 5 )
. attr ("font-size" , "12px" )
. text ("Anos (2024-2070)" );
years. forEach ((year, i) => {
svg. append ("text" )
. attr ("x" , legendX + (i * legendWidth / (years. length - 1 )))
. attr ("y" , legendY + legendHeight + 15 )
. attr ("text-anchor" , "middle" )
. attr ("font-size" , "10px" )
. text (year);
});
// Título
svg. append ("text" )
. attr ("x" , width / 2 )
. attr ("y" , 20 )
. attr ("text-anchor" , "middle" )
. style ("font-size" , "1.2em" )
. text (title);
return svg. node ();
}
// Renderização dos gráficos
{
const container = document . createElement ('div' );
container. style . display = "grid" ;
container. style . gap = "2rem" ;
container. style . justifyContent = "center" ;
if (modelo2. includes ("ARIMA+ETS" )) {
container. appendChild (createChart (data_filter1, "ARIMA+ETS" ));
}
if (modelo2. includes ("Lee-Miller" )) {
container. appendChild (createChart (data_filter2, "Lee-Miller" ));
}
if (modelo2. includes ("Lee-Carter" )) {
container. appendChild (createChart (data_filter3, "Lee-Carter" ));
}
if (modelo2. includes ("IBGE" )) {
container. appendChild (createChart (data_filter0, "IBGE" ));
}
if (modelo2. includes ("MLP-Shallow" )) {
container. appendChild (createChart (data_filter4, "MLP-Shallow" ));
}
return modelo2. length === 0
? html `<p>Nenhum dado selecionado.</p>`
: container;
}