Cooperativismo, floresta e renda na Amazônia — dados
  • Início
  • Mapa principal
  • Catálogo de bases
  • Indicadores
  • Mapas
    • Desmatamento e áreas protegidas (mapa principal)
    • Municípios da Amazônia Legal
    • Áreas designadas e entorno
    • Setores censitários
    • Cooperativas e associações
    • Cooperados × não cooperados (Censo Agro, por UF)
    • Páginas dos municípios do Acre
  • Análises
    • Pressão por desmatamento nas reservas extrativistas
  • Metodologia
    • Níveis de análise e definições
    • Metodologia dos cruzamentos
    • Registro de decisões
    • Política de dados
    • Dados para baixar
  • Sobre
    • Sobre o site
    • Pendências e próximos passos
Versão de trabalho para a equipe do projeto · dados preliminares, não citar

Pressão por desmatamento nas reservas extrativistas

A RESEX Chico Mendes e as demais reservas extrativistas da Amazônia Legal: o desmatamento por faixa de distância do limite, para dentro e para fora da reserva

NotaComo ler esta página
  • Faixas de distância. Para dentro da reserva: 0–5, 5–10 e 10–20 km a partir do limite, e o núcleo, a mais de 20 km dele. Para fora: anéis de 0–5, 5–10 e 10–20 km. Muitas RESEX são estreitas (seguem um rio, por exemplo) e não têm as faixas internas mais profundas. Por isso, os gráficos dizem quantas reservas entram em cada faixa.
  • Duas medidas.
    • Acumulado: todo o desmatamento que o PRODES já mapeou, antes e depois de 2007, dividido pela floresta original da faixa. Mostra a história.
    • Desde 2008: o que foi desmatado de 2008 até o ano escolhido, dividido pela floresta que existia em 2007. Mostra a pressão recente, e é a medida das outras páginas do site.
  • Grupo de comparação.
    • As medianas e os quartis usam as RESEX criadas até julho de 2007, que existem na série inteira.
    • Ficam de fora as RESEX criadas numa paisagem já inteiramente desmatada em 2007 (listadas ao lado do mapa).
    • As RESEX fora do grupo continuam no mapa e podem ser escolhidas em destaque.
  • Quadrantes. “Entorno pressionado” e “interior desmatado” querem dizer acima da mediana das RESEX do grupo de comparação, no anel de 0–5 km e na reserva inteira. É uma posição relativa, não um limiar absoluto.
  • Dentro × fora não é efeito da reserva. As reservas ficam em lugares diferentes, e o desmatamento pode se deslocar para o entorno. E desmatamento dentro de uma RESEX não é sinônimo de ilegalidade: o plano de manejo admite roçado e criação em cada colocação.
  • Manchas pequenas. Desde 2022, o INPE registra também desmatamentos de 1 a 6,25 ha, e eles estão incluídos aqui. Parte do salto de 2022 é do método, não do desmatamento.
  • Limites. Os limites das reservas são os atuais (CNUC 2026_07), e só entra a parte no bioma Amazônia.
  • Relação com a Entrega 2. A medida acumulada é a mesma ideia da Entrega 2 revisada do painel da RESEX, mas com outro limite da reserva e outro denominador. A conferência entre as duas está na metodologia.
import {temTipo, registrarPmtiles, primeiraCamadaDeRotulos, opcoesMapa, janela, numeroPt, fmt, caixa} from "../assets/mapas.js"
maplibregl = require("maplibre-gl@4.7.1/dist/maplibre-gl.js")
pmtiles = import("https://cdn.jsdelivr.net/npm/pmtiles@3.2.1/+esm")  // o dist/pmtiles.js não é UMD: o require() do OJS recusa
css = html`<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css">`
P = FileAttachment("../gerado/dados/resex_perfil.json").json()
PERFIL = ["nucleo", "interno_10_20", "interno_5_10", "interno_0_5", "anel_0_5", "anel_5_10", "anel_10_20"]
CURTO = ({nucleo: "núcleo", interno_10_20: "10–20 km", interno_5_10: "5–10 km", interno_0_5: "0–5 km",
          anel_0_5: "0–5 km", anel_5_10: "5–10 km", anel_10_20: "10–20 km"})
ROTULO = Object.fromEntries(P.faixas.map(f => [f.id, f.rotulo]))
LIMIARES = [0.01, 0.025, 0.05, 0.1, 0.2, 0.4]
CORES = ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#e6550d", "#a63603"]
cor = v => v == null ? "#d9d9d9" : CORES[LIMIARES.filter(l => v >= l).length]
COR_CM = "#c51b7d"
COR_DESTAQUE = "#2166ac"
titulo = n => n.toLowerCase().replace("reserva extrativista", "RESEX").split(" ")
  .map((w, i) => i > 0 && ["de", "do", "da", "dos", "das", "e"].includes(w) ? w
       : w.split("-").map(p => p.charAt(0).toUpperCase() + p.slice(1)).join("-")).join(" ")
nomeResex = id => `${titulo(P.areas[id].nome)} (${P.areas[id].uf})`
// quadrante em relação às medianas do grupo de comparação ("alto" = acima da mediana)
QUADRANTES = ["Entorno pressionado, interior desmatado", "Entorno pressionado, interior preservado",
              "Interior desmatado, entorno menos pressionado", "Pouca pressão"]
quadranteDe = (x, y, mx, my) => x == null || y == null ? null : y > my ? (x > mx ? QUADRANTES[0] : QUADRANTES[1]) : (x > mx ? QUADRANTES[2] : QUADRANTES[3])
// deslocamento horizontal fixo por RESEX nos pontos do perfil (o mesmo a cada redesenho)
desloca = id => (([...id].reduce((h, c) => (h * 31 + c.charCodeAt(0)) >>> 0, 7) % 1000) / 1000 - 0.5) * 0.55
marcador2022 = [Plot.ruleX([2021.5], {stroke: "#8a8a8a", strokeDasharray: "4,3"}),
                Plot.text([2021.5], {x: d => d, frameAnchor: "top", dx: -4, textAnchor: "end", fill: "#6b6b6b", fontSize: 10, stroke: "#ffffff", strokeWidth: 4, paintOrder: "stroke",
                                     text: () => "desde 2022: inclui manchas de 1–6,25 ha →"})]

O que os dados mostram sobre a RESEX Chico Mendes

{
  const cm = P.id_chico_mendes, U = P.anos.length - 1, fim = P.anos.at(-1), i2018 = P.anos.indexOf(2018);
  const v = (m, z, i = U) => P.areas[cm].frac[m][z]?.[i] ?? null;
  const r = (m, z, c, i = U) => P.resumo_comparacao[m][z][c][i];
  const pct = x => fmt(x, "pct");
  const posicao = (m, z) => v(m, z) > r(m, z, "p75") ? "acima do 3º quartil do grupo" : v(m, z) > r(m, z, "mediana") ? "acima da mediana do grupo" : "abaixo da mediana do grupo";
  const q = m => quadranteDe(v(m, "dentro"), v(m, "anel_0_5"), r(m, "dentro", "mediana"), r(m, "anel_0_5", "mediana"));
  const largas = Object.entries(P.areas).filter(([id, a]) => a.comparacao && id !== cm && a.frac.acum.nucleo?.[U] != null).map(([, a]) => a);
  const nucleos = largas.map(a => a.frac.acum.nucleo[U]);
  const aneisLargas = largas.map(a => a.frac.acum.anel_0_5?.[U]).filter(x => x != null);
  const depois2018 = (v("acum", "dentro") - v("acum", "dentro", i2018)) / (v("acum", "dentro") - v("acum", "dentro", 0));
  return md`Comparação com as ${r("acum", "dentro", "resex")} RESEX do grupo de comparação, em ${fim}:

- **Entorno.** No anel de 0–5 km em volta da Chico Mendes, ${pct(v("acum", "anel_0_5"))} da floresta original já foi desmatada. A mediana das RESEX é ${pct(r("acum", "anel_0_5", "mediana"))}, e metade delas fica entre ${pct(r("acum", "anel_0_5", "p25"))} e ${pct(r("acum", "anel_0_5", "p75"))}. Muitas dessas reservas são pequenas e ficam em paisagens desmatadas antes de 2008; entre as ${largas.length} outras RESEX que têm núcleo, como a Chico Mendes, a mediana do anel é ${pct(d3.median(aneisLargas))}.
- **Interior.** Na reserva inteira, ${pct(v("acum", "dentro"))} da floresta original (mediana ${pct(r("acum", "dentro", "mediana"))}; ${posicao("acum", "dentro")}). Só desde 2008, ${pct(v("desde_2008", "dentro"))} da floresta de 2007 (mediana ${pct(r("desde_2008", "dentro", "mediana"))}; ${posicao("desde_2008", "dentro")}).
- **Profundidade.** A mais de 20 km do limite, ${pct(v("acum", "nucleo"))} da floresta original está desmatada; nas outras ${nucleos.length} RESEX do grupo que têm núcleo, a mediana é ${pct(d3.median(nucleos))}. Na faixa de 0–5 km para dentro do limite, ${pct(v("acum", "interno_0_5"))}.
- **Ritmo.** Dentro da reserva, o acumulado passou de ${pct(v("acum", "dentro", 0))} em ${P.anos[0]} para ${pct(v("acum", "dentro", i2018))} em 2018 e ${pct(v("acum", "dentro"))} em ${fim}: ${pct(depois2018)} do aumento desde ${P.anos[0]} aconteceu depois de 2018. A mediana do grupo foi de ${pct(r("acum", "dentro", "mediana", 0))} para ${pct(r("acum", "dentro", "mediana"))}.
- **Quadrantes.** A Chico Mendes fica em "${q("acum")}" no acumulado e em "${q("desde_2008")}" desde 2008.

<small>O PRODES não distingue o roçado e a criação dos moradores, que o plano de manejo admite, do desmatamento ilegal, e não mapeia desmatamentos menores que 1 ha. Os números descrevem o desmatamento mapeado, não a sua causa.</small>`;
}

Explore os dados

viewof medida = Inputs.radio(new Map([["Acumulado (inclui o desmatamento antes de 2007)", "acum"], ["Desde 2008 (sobre a floresta de 2007)", "desde_2008"]]),
                             {label: "Medida", value: "acum"})
viewof ano = Inputs.range([P.anos[0], P.anos.at(-1)], {step: 1, value: P.anos.at(-1), label: "Ano (PRODES)"})
viewof destaque = Inputs.select(new Map(Object.keys(P.areas).map(id => [nomeResex(id), id]).sort((a, b) => a[0].localeCompare(b[0], "pt"))),
                                {label: "RESEX em destaque", value: P.id_chico_mendes})
idx = P.anos.indexOf(ano)
valor = (id, z) => P.areas[id]?.frac[medida][z]?.[idx] ?? null
resumo = z => { const r = P.resumo_comparacao[medida][z]; return {p25: r.p25[idx], mediana: r.mediana[idx], p75: r.p75[idx], n: r.resex[idx]}; }
nomeMedida = medida === "acum" ? "desmatado até o ano (com o anterior a 2007), % da floresta original" : "desmatado de 2008 até o ano, % da floresta de 2007"
{
  const cm = P.id_chico_mendes, d = resumo("dentro"), pct = v => fmt(v, "pct");
  const faixa = z => `${pct(valor(cm, z))} (mediana ${pct(resumo(z).mediana)}, ${resumo(z).n} RESEX)`;
  return md`**Em ${ano}, ${medida === "acum" ? "no acumulado" : "desde 2008"}:** na RESEX Chico Mendes inteira, ${pct(valor(cm, "dentro"))} da floresta ${medida === "acum" ? "original" : "de 2007"} estava desmatada, contra a mediana de ${pct(d.mediana)} entre as ${d.n} RESEX do grupo de comparação. Por faixa:
- 0–5 km para dentro: ${faixa("interno_0_5")};
- núcleo, a mais de 20 km do limite: ${faixa("nucleo")};
- 0–5 km para fora: ${faixa("anel_0_5")}.`;
}

Perfil de distância

O desmatamento em cada faixa, do núcleo da reserva (à esquerda) até 20 km para fora (à direita). Cada ponto cinza é uma RESEX do grupo de comparação; o traço preto é a mediana da faixa. Embaixo de cada faixa, o número de RESEX que a têm: muitas reservas são estreitas e não têm as faixas mais internas, então a mediana de cada faixa descreve um conjunto diferente de reservas. Para comparar a Chico Mendes só com as reservas que têm as mesmas faixas, marque a opção abaixo. O eixo vertical está em escala de raiz quadrada.

viewof soComNucleoSel = Inputs.checkbox(["Comparar só com as RESEX que têm núcleo, como a Chico Mendes"])
soComNucleo = soComNucleoSel.length > 0
{
  const grupo = Object.entries(P.areas).filter(([id, a]) => a.comparacao && (!soComNucleo || a.frac[medida].nucleo?.[idx] != null)).map(([id]) => id);
  const pontos = grupo.flatMap(id => PERFIL.map((z, i) => ({id, i, z, v: valor(id, z), quem: nomeResex(id)}))).filter(d => d.v != null);
  const meds = PERFIL.map((z, i) => { const vs = pontos.filter(d => d.z === z).map(d => d.v); return {i, z, n: vs.length, mediana: vs.length ? d3.median(vs) : null}; });
  const linha = id => PERFIL.map((z, i) => ({i, z, v: valor(id, z), quem: nomeResex(id)})).filter(d => d.v != null);
  const ids = destaque === P.id_chico_mendes ? [P.id_chico_mendes] : [P.id_chico_mendes, destaque];
  const corDe = id => id === P.id_chico_mendes ? COR_CM : COR_DESTAQUE;
  return Plot.plot({
    width: 760, height: 420, marginLeft: 55, marginBottom: 55,
    x: {domain: [-0.5, 6.5], ticks: PERFIL.map((_, i) => i), tickFormat: i => `${CURTO[PERFIL[i]]}\n(${meds[i].n})`, label: null},
    y: {type: "sqrt", domain: [0, 1], label: "Desmatado (%)", grid: true, ticks: [0, 0.01, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1], tickFormat: v => numeroPt(0)(100 * v)},
    marks: [
      Plot.ruleX([3.5], {stroke: "#333", strokeDasharray: "3,3"}),
      Plot.text([3.5], {x: d => d, frameAnchor: "top", dx: -6, textAnchor: "end", text: () => "← dentro da RESEX", fill: "#444", fontSize: 11}),
      Plot.text([3.5], {x: d => d, frameAnchor: "top", dx: 6, textAnchor: "start", text: () => "fora da RESEX →", fill: "#444", fontSize: 11}),
      Plot.dot(pontos.filter(d => !ids.includes(d.id)), {x: d => d.i + desloca(d.id), y: "v", r: 3, fill: "#8c8c8c", fillOpacity: 0.45,
                                                         tip: true, title: d => `${d.quem}\n${ROTULO[d.z]}: ${fmt(d.v, "pct")}`}),
      Plot.link(meds.filter(d => d.mediana != null), {x1: d => d.i - 0.32, x2: d => d.i + 0.32, y1: "mediana", y2: "mediana", stroke: "#111", strokeWidth: 3,
                                                       title: d => `${ROTULO[d.z]}: mediana ${fmt(d.mediana, "pct")} (${d.n} RESEX)`}),
      ...ids.flatMap(id => [
        Plot.line(linha(id), {x: "i", y: "v", stroke: corDe(id), strokeWidth: 2.5}),
        Plot.dot(linha(id), {x: "i", y: "v", fill: corDe(id), stroke: "white", r: 5,
                             tip: true, title: d => `${d.quem}\n${ROTULO[d.z]}: ${fmt(d.v, "pct")}`})])
    ]
  });
}
html`<p class="legenda-analise"><small>${caixa(COR_CM)} RESEX Chico Mendes ${destaque !== P.id_chico_mendes ? html`&nbsp; ${caixa(COR_DESTAQUE)} ${nomeResex(destaque)}` : ""} &nbsp; ${caixa("#8c8c8c")} outras RESEX do grupo &nbsp; ${caixa("#111")} mediana da faixa. Medida: ${nomeMedida}.</small></p>`

No tempo

A mesma medida, ano a ano, numa faixa escolhida.

viewof faixaTempo = Inputs.select(["dentro", ...PERFIL], {label: "Faixa", format: z => ROTULO[z], value: "dentro"})
{
  const r = P.resumo_comparacao[medida][faixaTempo];
  const banda = P.anos.map((a, i) => ({a, p25: r.p25[i], mediana: r.mediana[i], p75: r.p75[i]})).filter(d => d.mediana != null);
  const serie = id => P.anos.map((a, i) => ({a, v: P.areas[id].frac[medida][faixaTempo]?.[i] ?? null, quem: nomeResex(id)})).filter(d => d.v != null);
  const ids = destaque === P.id_chico_mendes ? [P.id_chico_mendes] : [P.id_chico_mendes, destaque];
  return Plot.plot({
    width: 760, height: 380, marginLeft: 55,
    x: {label: "Ano-safra (PRODES)", tickFormat: d => String(d)},
    y: {label: "Desmatado (%)", grid: true, tickFormat: numeroPt(0), zero: true},
    marks: [
      ...marcador2022,
      Plot.ruleX([ano], {stroke: "#999"}),
      Plot.areaY(banda, {x: "a", y1: d => 100 * d.p25, y2: d => 100 * d.p75, fill: "#bdbdbd", fillOpacity: 0.5}),
      Plot.line(banda, {x: "a", y: d => 100 * d.mediana, stroke: "#737373", strokeWidth: 2,
                        tip: true, title: d => `${d.a}: mediana ${fmt(d.mediana, "pct")}`}),
      ...ids.map(id => Plot.line(serie(id), {x: "a", y: d => 100 * d.v, stroke: id === P.id_chico_mendes ? COR_CM : COR_DESTAQUE, strokeWidth: 2.5,
                                             tip: true, title: d => `${d.quem}\n${d.a}: ${fmt(d.v, "pct")}`}))
    ]
  });
}

A Chico Mendes e as outras reservas, dentro × entorno

Cada ponto é uma RESEX do grupo de comparação: na horizontal, o desmatamento na reserva inteira; na vertical, no anel de 0–5 km em volta. As linhas tracejadas são as medianas do grupo e dividem o gráfico em quatro quadrantes. “Pressionado” e “desmatado” são relativos às outras RESEX — acima da mediana —, e não um limiar absoluto; os quadrantes mudam com a medida e o ano escolhidos. Os eixos estão em escala de raiz quadrada, para separar as reservas com pouco desmatamento.

{
  const pts = Object.entries(P.areas).filter(([id, a]) => a.comparacao || id === destaque)
    .map(([id, a]) => ({id, quem: nomeResex(id), x: valor(id, "dentro"), y: valor(id, "anel_0_5")}))
    .filter(d => d.x != null && d.y != null);
  const corDe = id => id === P.id_chico_mendes ? COR_CM : id === destaque ? COR_DESTAQUE : "#9e9e9e";
  const mx = resumo("dentro").mediana, my = resumo("anel_0_5").mediana;
  const canto = (texto, frameAnchor) => Plot.text([texto], {frameAnchor, dx: frameAnchor.endsWith("left") ? 8 : -8, dy: frameAnchor.startsWith("top") ? 8 : -8,
                                                            fill: "#555", fontSize: 12, fontStyle: "italic"});
  return Plot.plot({
    width: 1000, height: 460, marginLeft: 60,
    x: {type: "sqrt", domain: [0, 1], label: "Reserva inteira, desmatado (%)", tickFormat: v => numeroPt(0)(100 * v), ticks: [0, 0.01, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1], grid: true},
    y: {type: "sqrt", domain: [0, 1], label: "Anel de 0–5 km, desmatado (%)", tickFormat: v => numeroPt(0)(100 * v), ticks: [0, 0.01, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1], grid: true},
    marks: [
      Plot.ruleX([mx], {stroke: "#666", strokeDasharray: "5,4"}),
      Plot.ruleY([my], {stroke: "#666", strokeDasharray: "5,4"}),
      canto(QUADRANTES[1], "top-left"), canto(QUADRANTES[0], "top-right"),
      canto(QUADRANTES[3], "bottom-left"), canto(QUADRANTES[2], "bottom-right"),
      Plot.dot(pts.filter(d => d.id !== P.id_chico_mendes && d.id !== destaque), {x: "x", y: "y", fill: "#9e9e9e", fillOpacity: 0.7, r: 4}),
      Plot.dot(pts.filter(d => d.id === P.id_chico_mendes || d.id === destaque), {x: "x", y: "y", fill: d => corDe(d.id), r: 7, stroke: "white"}),
      Plot.text(pts.filter(d => d.id === P.id_chico_mendes || d.id === destaque), {x: "x", y: "y", text: "quem", dx: 9, textAnchor: "start", fill: d => corDe(d.id), fontWeight: "bold"}),
      Plot.tip(pts, Plot.pointer({x: "x", y: "y", title: d => `${d.quem}\nreserva inteira: ${fmt(d.x, "pct")}\nanel de 0–5 km: ${fmt(d.y, "pct")}`}))
    ]
  });
}
{
  const mx = resumo("dentro").mediana, my = resumo("anel_0_5").mediana;
  const grupo = Object.keys(P.areas).filter(id => P.areas[id].comparacao)
    .map(id => ({id, q: quadranteDe(valor(id, "dentro"), valor(id, "anel_0_5"), mx, my)})).filter(d => d.q);
  const qd = quadranteDe(valor(destaque, "dentro"), valor(destaque, "anel_0_5"), mx, my);
  const lista = q => grupo.filter(d => d.q === q).map(d => nomeResex(d.id)).sort((a, b) => a.localeCompare(b, "pt"));
  return html`<div><p><small>Em ${ano}, das ${grupo.length} RESEX: ${QUADRANTES.map(q => `${lista(q).length} em “${q}”`).join("; ")}.
    ${qd ? html`<strong>${nomeResex(destaque)}</strong>: ${qd.toLowerCase()}.` : ""}</small></p>
    <details><summary><small>Quais RESEX estão em cada quadrante</small></summary>
    ${QUADRANTES.map(q => html`<p><small><strong>${q}</strong> (${lista(q).length}): ${lista(q).join("; ")}</small></p>`)}</details></div>`;
}

Mapa

As RESEX coloridas pelo desmatamento na reserva inteira, no ano e na medida escolhidos acima. A RESEX em destaque mostra também as suas faixas, para dentro e para fora; ao trocar a RESEX em destaque, o mapa vai até ela. Passe o mouse ou toque numa reserva ou faixa para ver os números.

{
  const rot = i => i === 0 ? `menos de ${numeroPt(1)(100 * LIMIARES[0])}%` : i === LIMIARES.length ? `${numeroPt(1)(100 * LIMIARES.at(-1))}% ou mais`
                 : `${numeroPt(1)(100 * LIMIARES[i - 1])}–${numeroPt(1)(100 * LIMIARES[i])}%`;
  const conv = Object.values(P.areas).filter(a => a.painel_fixo && a.convertida_2007).map(a => titulo(a.nome) + ` (${a.uf})`);
  return html`<div><p><strong>Desmatado</strong><br><small>${nomeMedida}</small></p>
    ${CORES.map((c, i) => html`<div>${caixa(c)} ${rot(i)}</div>`)}
    <div>${caixa("#d9d9d9")} sem dado (pouca floresta)</div>
    <p style="margin-top:.8rem"><small><strong>Fora do grupo de comparação</strong> (continuam no mapa): as criadas depois de julho de 2007, e as criadas em paisagem já inteiramente desmatada em 2007: ${conv.join("; ")}.</small></p></div>`;
}

Fontes: PRODES (INPE), limites das RESEX do CNUC 2026_07 (MMA). Cálculo: etapa 28 de amazonia-legal/ (metodologia).

mapaResex = {
  const div = html`<div class="mapa"></div>`;
  div.pronto = new Promise(resolve => setTimeout(() => {
    registrarPmtiles(maplibregl, pmtiles);
    const urlAreas = new URL("../gerado/dados/areas_designadas.pmtiles", document.baseURI).href;
    const urlFaixas = new URL("../gerado/dados/resex_faixas.pmtiles", document.baseURI).href;
    const m = new maplibregl.Map(opcoesMapa(div));
    m.addControl(new maplibregl.NavigationControl({showCompass: false}));
    m.on("load", () => {
      const rotulos = primeiraCamadaDeRotulos(m);
      m.addSource("areas", {type: "vector", url: "pmtiles://" + urlAreas, attribution: "MMA/CNUC"});
      m.addSource("faixas", {type: "vector", url: "pmtiles://" + urlFaixas, attribution: "INPE/PRODES"});
      const soResex = ["all", temTipo("resex"), ["has", "id_area"]];
      m.addLayer({id: "resex-fill", type: "fill", source: "areas", "source-layer": "areas", filter: soResex,
                  paint: {"fill-color": "#d9d9d9", "fill-opacity": 0.85}}, rotulos);
      m.addLayer({id: "resex-linha", type: "line", source: "areas", "source-layer": "areas", filter: soResex,
                  paint: {"line-color": "#636363", "line-width": 0.6}}, rotulos);
      m.addLayer({id: "faixas-fill", type: "fill", source: "faixas", "source-layer": "faixas", filter: ["==", ["get", "id_area"], ""],
                  paint: {"fill-color": "#d9d9d9", "fill-opacity": 0.85}}, rotulos);
      m.addLayer({id: "faixas-linha", type: "line", source: "faixas", "source-layer": "faixas", filter: ["==", ["get", "id_area"], ""],
                  paint: {"line-color": "#525252", "line-width": 0.8}}, rotulos);
      resolve(m);
    });
  }, 0));
  invalidation.then(async () => (await div.pronto).remove());
  return div;
}
{
  const m = await mapaResex.pronto;
  const pares = Object.keys(P.areas).flatMap(id => [id, cor(valor(id, "dentro"))]);
  m.setPaintProperty("resex-fill", "fill-color", ["match", ["get", "id_area"], ...pares, "#d9d9d9"]);
  const pf = ["dentro", ...PERFIL].flatMap(z => [z, cor(valor(destaque, z))]);
  for (const c of ["faixas-fill", "faixas-linha"]) m.setFilter(c, ["==", ["get", "id_area"], destaque]);
  m.setPaintProperty("faixas-fill", "fill-color", ["match", ["get", "zona"], ...pf, "#d9d9d9"]);
  // o mapa só se move quando a RESEX em destaque muda (não quando muda o ano ou a medida)
  if (m.__destaque !== destaque) {
    m.__destaque = destaque;
    const [o, s, l, n] = P.areas[destaque].bbox;
    m.fitBounds([[o - 0.25, s - 0.25], [l + 0.25, n + 0.25]], {padding: 20, duration: 800});
  }
  if (!m.__janela) {
    m.__janela = true;
    janela(maplibregl, m, ["faixas-fill", "resex-fill"], fs => {
      const f = fs[0], p = f.properties;
      if (f.layer.id === "faixas-fill") {
        const v = P.areas[p.id_area]?.frac[m.__medida]?.[p.zona]?.[m.__idx];
        return `<strong>${nomeResex(p.id_area)}</strong><br>${ROTULO[p.zona]}: ${fmt(v, "pct")} desmatado em ${m.__ano}`;
      }
      const a = P.areas[p.id_area];
      if (!a) return null;
      const fora = !a.painel_fixo ? "<br><small>Criada depois de julho de 2007: fora do grupo de comparação.</small>"
                 : a.convertida_2007 ? "<br><small>Paisagem já inteiramente desmatada em 2007: fora do grupo de comparação.</small>" : "";
      return `<strong>${nomeResex(p.id_area)}</strong><br>Reserva inteira: ${fmt(a.frac[m.__medida].dentro?.[m.__idx], "pct")} desmatado em ${m.__ano}${fora}`;
    });
  }
  Object.assign(m, {__medida: medida, __idx: idx, __ano: ano});
  return html`<span></span>`;
}

Gerado em 03/11/2026 22:41 a partir do commit 2209fa1 do repositório do projeto. Dados: PRODES Amazônia Legal v20260408 (raster) e PRODES Cerrado v20260407 (INPE), com as manchas de 1–6,25 ha do PRODES bioma Amazônia vetorial v20260717 — outra versão que a do raster; limite da Amazônia Legal 2024 (IBGE); demais versões nas páginas de cada fonte.

Projeto UFAC · IESP-UERJ · IFAC (2026–2029). Versão de trabalho — dados preliminares, não citar.