Ir ao conteúdo
SEED engenhariaDesign System

Dataviz

4. Sub-bloco DG — gráficos core

estávelseed-dataviz.md v0.22 · §04seção 6 de 1204-sub-bloco-dg-graficos-core-13-decisoes.md · MD5 cc8ee980

Título completo no canon: Sub-bloco DG — gráficos core (13 decisões + redesenho DG14–DG17; estável em 2026-08-09)

O que é o DG. O sub-bloco que especifica os sete tipos de gráfico que a SEED usa no dia a dia — barra, barra empilhada, barra agrupada, linha, área, pizza e dispersão — mais os três estados (carregando, vazio, erro). Não especifica painel (isso é F6), gauge nem sparkline (DM), mapa (DP) nem impresso (DI).

Consolidado aprovado pelo Rafael em 2026-08-09, após três rodadas encadeadas de pesquisa (R1 canon interno · R2 mercado e stack · R3 normas e fora-do-circuito) e duas emendas feitas durante a produção: a barra empilhada foi puxada para dentro do escopo a pedido do Rafael (o caso real: consumo por posto tarifário), e o DG13 nasceu do gate visual.

Artefatos: seed-dataviz-graficos-preview.htmlv1.2 (82.126 B, md5 8d1930598b9d124d3807fc80f70b0fbf) é o artefato do gate de 2026-08-10, reanexado e conferido por MD5 em 2026-08-11 (P6); a v1.3 corrige as erratas E4/E5/E6 e aguarda gate · validacao/suite-dataviz-dg.mjs163 PASS · 0 FAIL, RE-EXECUTADA em 2026-08-11 contra o artefato reanexado (o placar do gate deixou de ser reprodução e passou a ser execução) · validacao/contraste-dg.pydesatualizado (ainda mede DG11 e a paleta antiga — atualizar na próxima edição) · validacao/render-dg.mjs (6 cenários, puppeteer).

4.1 Anatomia e acesso#

DG1 — invólucro canônico obrigatório. Todo gráfico SEED é um <figure> com cinco partes: (a) título visível em figcaption; (b) descrição curta que identifica o gráfico e diz onde está a longa; (c) fallback textual sempre presente — tabela semântica (herda §40 do seed-componentes.md: caption, th scope, numérico em mono à direita, célula vazia como ) ou sumário do achado, dentro de <details> quando ocupar espaço; (d) legenda; (e) a área do gráfico, com role="img" e aria-labelledby apontando para (a) e (b). Sem as cinco, não é gráfico canônico.

Racional: o W3C classifica gráfico como imagem complexa e exige alternativa textual em duas partes — curta que identifica, longa que representa a informação essencial. E a auditoria pública do shadcn Charts (2024) reprovou a biblioteca em 1.1.1 (os gráficos testados não entregam alternativa textual: o leitor de tela recebe só rótulos de eixo e, às vezes, o tooltip) e em 1.3.1 (a legenda não tem relação codificada com o gráfico). Alternativa descartada: tratar o accessibilityLayer do Recharts como cumprimento do 1.1.1 — há evidência pública em contrário.

DG2 — teclado: um único tab-stop, depois setas. O gráfico inteiro é um ponto de parada na tabulação; dentro dele, percorrem os pontos e Home/End vão aos extremos, com cada movimento anunciado em região aria-live. Nenhum ponto de dado é focável individualmente.

Racional: é o padrão do APG e a posição oficial da própria biblioteca — se cada elemento virasse tab-stop, quem não se importa com o gráfico teria de tabular por todos os pontos. Risco declarado e NÃO resolvido: em modo de navegação, JAWS e NVDA interceptam as setas antes da página; o Recharts contorna com role="application", e o VoiceOver não tem equivalente. Por isso o teclado é enriquecimento, não o caminho de acesso — quem garante o acesso é o fallback textual do DG1.

4.2 Escolha do tipo e honestidade do eixo#

DG3 — uma pergunta por gráfico. Barra = comparar categorias · barra empilhada = total e composição · barra agrupada = comparar um subgrupo entre categorias · linha = tendência no tempo · área = tendência com magnitude · pizza = parte-do-todo num instante · dispersão = correlação entre duas variáveis. Gráfico que responde duas perguntas vira dois gráficos.

DG4 — eixo zero é regra dura ASSIMÉTRICA. Barra e área sempre partem do zero, sem exceção. Linha pode truncar, sob três condições cumulativas: eixo rotulado, valor mínimo explícito e marca visual de truncamento.

Racional: é geometria, não estilo — comprimento e área codificam o valor diretamente, então truncar mente; a linha codifica por posição e inclinação, então truncar acima de zero não quebra a leitura. Alternativa descartada: proibir truncamento em linha — cegaria justamente o que a SEED mais precisa ver (PR de usina e tensão de rede variam pouco e importam muito). Também descartada: permitir truncamento em barra — desonesto por construção.

DG5 — pizza com oito travas. Só parte-do-todo somando 100% · máximo 5 fatias, resto em "Outros" nomeado · nunca 3D, nunca fatia explodida · maior fatia às 12h, sentido horário · valor sempre rotulado, sem depender de legenda ou hover · fatias adjacentes com menos de 5 pontos percentuais de diferença → vira barra ordenada · dado ordinal ou sequencial → vira barra empilhada · valor negativo → nunca pizza. Donut é variante permitida quando o centro carrega o número.

Racional: limite cognitivo documentado de 5–6 itens comparados simultaneamente; a regra dos 5 p.p. para distinção visual; e o corte semântico do dado ordinal. Alternativa descartada: banir pizza — o público de proposta e laudo lê pizza, e banir empurraria o consumidor para fora do DS, o que é pior do que usá-la com regra.

DG5-b — rótulo dentro da fatia é condicional, e a condição é medida. A tinta do rótulo interno é escolhida pelo maior contraste contra o fill; se nenhuma opção atingir 4,5, o rótulo vai para fora, com linha-guia. Medido na §3c: sobre cat-1 a tinta escura dá 5,11 e sobre cat-2 dá 7,48 (ambas entram); sobre cat-3 nenhuma tinta atinge 4,5 (branco 3,32 · escura 4,17), logo a fatia cat-3 sempre leva rótulo externo.

REMEDIÇÃO da v0.5 (paleta categórica estendida v1.5) — a regra não muda; a tabela de resultados sim. Tinta escura (cinza-900) sobre os fills light novos: cat-1 4,30 (reprova o piso 4,5 — na paleta antiga dava 5,11) · cat-2 7,48 ✓ · cat-3 3,40 ✗ · cat-4 4,17 ✗ · cat-5 3,43 ✗ · cat-6 1,46 ✗, mas branco sobre cat-6 mede 9,52 ✓. Resultado vigente: rótulo interno só em cat-2 (tinta escura) e cat-6 (tinta branca); todas as demais fatias levam rótulo externo com linha-guia. Errata aberta contra o preview v1.2: a pizza aprovada no gate mostra o rótulo "45%" interno sobre cat-1 a 4,30 — defeito latente que a formalização encontrou; corrigir quando o preview for editado. A regra provou funcionar exatamente como desenhada: condicional e medida, ela absorve a troca de paleta sem supersede.

4.3 Empilhada e agrupada (DG10)#

DG10-a — uso. Empilhada só quando total e composição importam juntos. Se só a composição importa, é pizza com regras (DG5). Se importa comparar um subgrupo específico entre categorias, é agrupada — que entra como variante irmã, não como alternativa de gosto. Racional: só o segmento da base fica sobre a linha de zero comum; os de cima flutuam.

DG10-b — máximo 4 segmentos, resto em "Outros" nomeado. Aperto deliberado sobre os 5 do mercado, por motivo interno: acima de 4, a categórica SEED começa a parear matizes da mesma família (dois dourados, duas turquesas), e segmento preenchido não carrega tracejado para desambiguar — o teto é fato de paleta, não preferência.

Nota da v0.5 — o RACIONAL foi supersedido; o TETO permanece. Com a categórica estendida v1.5, as posições 1–5 são famílias todas distintas — o "fato de paleta" que sustentava o teto deixou de existir. O teto de 4 continua vigente porque nenhum gate o reavaliou (mudar limite aprovado sem gate seria decisão inventada); os motivos remanescentes são os do mercado (limite cognitivo de comparação em pilha). Pendência registrada no §5: reavaliar o teto (4→5) quando um caso real do ERP pedir 5 segmentos, com preview e gate.

DG10-c — ordem de empilhamento fixa, idêntica em todos os gráficos da mesma família, com o segmento mais importante na base; toda barra contém os mesmos componentes (se uma barra tem um componente que a outra não tem, a comparação quebra).

DG10-d — SUPERSEDIDO pelo DG11. Ver §5.

DG10-e — legenda permitida na empilhada, exceção explícita ao DG7: com 4 segmentos o rótulo direto não cabe dentro da faixa. O fallback textual leva uma coluna por segmento mais coluna Total. Na agrupada, o total não é exibido — ela responde outra pergunta.

4.4 Fronteira, tinta e textura — as três regras que a medição criou#

As três nasceram durante a validação, não do consolidado. São o registro de que a camada automatizada e o gate humano acharam o que a pesquisa não anteciparia.

DG11 — SUPERSEDIDO pelo DG14 (§4.6) em 2026-08-10. Toda superfície de área opaca leva contorno de 1px em cinza-900. O contorno universal viveu um dia: aprovado no gate de 2026-08-09, foi reprovado pelo OLHO do Rafael no gate seguinte ("ar de relatório antigo", crítica de estética de produto sobre o preview v0.6+). O problema que o DG11 resolvia — fill que reprova 3:1 sozinho contra o fundo — foi re-resolvido pela raiz: a categórica estendida v1.5 tem todos os fills ≥3,22 contra o fundo (única exceção: dourado, com regra própria), o que dispensa a fronteira desenhada. O texto original permanece abaixo como registro do racional:

Racional medido (histórico): o fill categórico v1.0 reprovava 1.4.11 sozinho contra o fundo claro — cat-1 2,71 · cat-2 1,85 · cat-5 2,53. Alternativa descartada com número: contorno na variante -stroke da própria série — cat-2-stroke contra cat-1 media 1,28, não separava vizinho. O cinza-900 foi a única cor testada que atingia ≥3 contra todos os fills nos dois modos (mínimo 4,17). A cadeia completa de supersedes está no §6: DG10-d → DG11 → DG14.

DG12 — tinta sobre dado não segue o tema. Rótulo interno e contorno usa o primitivo cinza-900 em light e em dark. É exceção declarada à regra "componente consome semântico". (Emenda da v0.5: "e contorno" morreu junto com o DG11/DG14 — sobrou o rótulo interno como único consumidor da regra nos gráficos core. A regra em si permanece viva e testada na suite.)

Racional: a regra existe para que o tema funcione — mas o objeto contrastado aqui é o fill categórico, que é claro nos dois modos (cat-2 é literalmente o mesmo hex). Uma tinta que inverte com o tema erra em um dos lados por construção.

Exceção declarada ao DG12, nascida no DM (2026-08-10): no medidor, a tinta da marca de meta ACOMPANHA a superfície (cinza-900 no light, cinza-100 no dark). Motivo medido: as bandas do medidor invertem com o tema (DM3 — cinza claro no light, cinza escuro no dark), então o objeto contrastado não é claro nos dois modos como o fill categórico; a tinta fixa erraria no dark por construção. Pior caso medido: 7,07 (light) · 3,93 (dark), ambos ≥3. O DG12 vale onde o objeto é estável entre temas; onde o objeto inverte, a tinta inverte junto.

DG13 — textura por série. (Gatilho supersedido pelo DI2 — ver emenda da v0.9 ao fim desta seção. O vocabulário abaixo permanece vivo e foi ESTENDIDO na v0.10.)

Vocabulário — 6 posições, uma por série do teto:

Série Textura
1 sólida (ausência de textura é o próprio sinal)
2 pontilhada
3 quadriculada
4 linhas horizontais
5 linhas verticais (novo na v0.10)
6 diagonal a 135° (novo na v0.10)

A hachura diagonal a 45° não entra no vocabulário — fica reservada ao chart-no-data, estendendo a exclusividade que a §3c deu ao cinza de "sem medição". A legenda repete a textura sob o mesmo gatilho, senão os quadradinhos mentem sobre o gráfico. Gráfico de série única não leva textura.

Emenda da v0.10 — a lacuna das posições 5 e 6. O vocabulário nasceu com quatro texturas enquanto o teto de séries sempre foi seis. A lacuna era invisível porque o gatilho antigo (escuro ∩ grayscale) nunca foi exercido contra um gráfico de 5 ou 6 séries: o único que existe no preview — a pizza de 5 — estava sem textura nenhuma, o que é a errata E11. Com o DI2, gráficos de 4+ séries passam a texturizar também no claro, e a falta apareceu. Racional das duas escolhas, aprovadas no gate de 2026-08-11: linhas verticais para a 5, porque é a rotação de 90° da textura 4 e nenhuma das duas se confunde com as demais; diagonal a 135° para a 6, distinta da diagonal a 45° do chart-no-data por direção, o que preserva a exclusividade que faz "sem medição" nunca ser lido como categoria. Alternativas descartadas: diagonal a 45° com espaçamento diferente — a distinção viraria densidade, frágil no papel e pior ainda em fotocópia, exatamente onde o no-data mais precisa ser inconfundível; pontos maiores para a 5 — lê como a textura 2 vista de perto.

Origem — gate visual do Rafael: ele ligou grayscale no modo escuro e disse que "parece tudo igual". Estava certo.

Racional, com a correção de instrumento que o gate forçou: a primeira medição usou razão de contraste WCAG entre as séries convertidas para cinza e reprovava também o modo claro (cat-1 × cat-3 = 1,22) — o que teria levado a texturizar tudo. Razão de contraste é a métrica errada aqui: foi calibrada para texto sobre fundo, não para faixas grandes adjacentes separadas por contorno. A métrica que discrimina faixa é o espalhamento de claridade do cinza resultante:

Tabela histórica — três séries da categórica v1.0. O veredito "a cor basta no claro" vale somente até três séries; com a categórica v1.5 e seis posições ele é falso, e o gatilho foi supersedido pelo DI2 (§4c.2). A tabela permanece como registro do racional que criou o DG13.

Modo cat-1 cat-2 cat-3 menor distância veredito
Claro 62% 75% 55% 7 pontos a cor basta; textura seria ruído
Escuro 75% 75% 71% 0 pontos textura obrigatória

O colapso é da rampa escura, não do grayscale em si — por isso a textura é remédio local, e o gatilho é a interseção, não o "ou". O piso de 6 pontos está no contraste-dg.py declarado como calibrado pelo gate, não derivado de norma, para que ninguém o cite um dia como se fosse WCAG.

Emenda da v0.5 — o piso vale só onde foi medido. No gate do DM (2026-08-10), as bandas do medidor distavam 9/8/17 pontos de claridade — acima do piso de 6 — e o Rafael não as distinguia ("não consegui perceber a diferença de tonalidade"). O piso foi calibrado em UM contexto (barras altas adjacentes, modo claro) e não transfere para faixas finas empilhadas dentro de um medidor. Regra decorrente: o piso de 6 pontos decide apenas no contexto em que foi calibrado; fora dele, quem decide é o gate — e cada decisão do gate vira número novo, declarado no contexto novo (foi assim que nasceu o DM11). A remedição da categórica v1.5 (claridades dark 75/75/71/71/67, vizinhas a 0–4 pontos) confirma: o DG13 permanece obrigatório com a paleta nova.

Emenda da v0.9 — SUPERSEDE do gatilho pelo DI2 (§4c.2). A remedição da v0.5 acima conferiu apenas o modo escuro da paleta nova; o modo claro seguiu sendo citado pelos 7 pontos da tabela histórica, que são de três séries. Medido em 2026-08-11 no sub-bloco DI, com as seis posições da v1.5 em modo claro: cat-1 × cat-4 = 1 ponto e cat-3 × cat-5 = 1 ponto (claridades 56/75/49/55/50/27). O claro é seguro até três séries e colapsa a partir da quarta. O gatilho passa de "escuro ∩ grayscale" para grayscale ∩ (escuro OU ≥4 séries). O vocabulário de textura, a exclusividade da diagonal a 45° para o chart-no-data, a repetição na legenda sob o mesmo gatilho e a isenção do gráfico de série única permanecem intactos. Fato de método: o defeito sobreviveu porque o contraste-dg.py percorre só cat1/cat2/cat3 — o detector estava recortado exatamente onde o defeito não mora (correção no DI18).

4.5 Estados e forma (DG6, DG7, DG8)#

DG6 — os três estados herdam o Bloco 3 com moldura de gráfico. Skeleton: espelha a moldura real (eixos, base e o mesmo número de barras — S2), shimmer E→D 1,8 s desligado em prefers-reduced-motion (S3), aria-busy com o conteúdo visual em aria-hidden (S6), timeout de 15 s que vira erro (S5). Vazio: pelos 5 tipos do Z1 — zero-resultados não recebe CTA de criação, a ação oferecida mexe no filtro, que é a causa; título de até 5 palavras sem ponto final e uma ação só (Z2). Erro: alerta §15 em role="alert", no lugar do gráfico, com recuperação ("tentar novamente").

DG6-b — "sem dado" NÃO é estado vazio. Série ou célula sem medição usa chart-no-data sempre hachurado, com o item "sem medição" na legenda e na tabela; o gráfico continua existindo com as demais séries. A distinção "gerou pouco × não reportou" nunca depende de cor.

DG7 — rótulo direto vence legenda até três séries em linha e área; legenda é recurso, não default. Exceção declarada: DG10-e. Racional: a legenda obriga ida-e-volta do olho e — pela auditoria citada no DG1 — sequer tem relação codificada com o gráfico; é elo fraco perceptual e programático. (Inferência declarada, não medida.)

DG8 — mobile 360 px. Barra vertical com mais de 5 categorias vira barra horizontal; rótulo de eixo rotacionado é proibido (só o título do eixo pode girar). O container exige altura mínima declarada — o Chart do shadcn não é responsivo sem ela.

DG9 — fronteiras. Gauge e sparkline = DM · mapas = DP · impresso = DI · painel = F6. Fora da v1 do DG, registrados: empilhada 100%, waterfall, boxplot, combo de eixo duplo.

4.6 Redesenho "gráfico de produto" — DG14–DG17 + duas leis transversais (gate de 2026-08-10)#

Origem. Sobre o DG recém-promovido, o Rafael abriu um segundo ciclo com uma crítica de ESTÉTICA, não de conformidade: o resultado estava tecnicamente correto e visualmente datado — "gráfico de relatório", não "gráfico de produto" (referência apresentada: dashboards no padrão do site Viver de IA — cantos suaves, zero contorno, curvas orgânicas, cor limpa). O ciclo levou o preview seed-dataviz-graficos-preview.html da v0.6 à v1.2, com gate visual completo (matriz tema × grayscale × viewport cruzada) e "aprovo" em 2026-08-10. Nenhuma decisão de CONFORMIDADE do DG1–DG10 mudou; o que mudou foi a camada de desenho — e uma decisão de conformidade (DG11) caiu porque a causa raiz dela foi removida.

DG14 — zero contorno em superfície de dado; fronteira por espaço negativo (SUPERSEDE do DG11). Barra, segmento de pilha, fatia e área não levam contorno. Na empilhada e na pizza, segmentos adjacentes separam-se por vão de 2px — tecnicamente um stroke na cor do cartão (surface-raised), que funciona como espaço negativo: a fronteira é geometria, não contraste, então funciona idêntica em light, dark, grayscale e impresso. Condição estrutural que tornou isso possível: todos os fills da categórica estendida v1.5 passam 3:1 sozinhos contra o fundo (mínimo 3,22; exceção declarada do dourado com regra própria na §3c) — o cat-1 mudou de stop exatamente para isso. Alternativas descartadas: manter o contorno só no light (dois desenhos por tema, deriva garantida) · contorno em cor mais suave (resolve a estética, devolve o problema de contraste que criou o DG11).

DG15 — geometria orgânica. Todo retângulo de dado nasce com canto arredondado rx=3 ("nenhum retângulo de dado sai de fábrica com canto vivo"); barra fina de ranking usa pílula completa (rx = metade da altura). Linha de tendência usa curva monótona (interpolação Fritsch–Carlson) a 2px — nunca spline genérica (Catmull-Rom/natural), que inventa picos acima dos dados reais e mente sobre máximos; a curva monótona nunca ultrapassa os valores medidos. Área sob a linha usa gradiente vertical 22% → 0 da cor da série. Racional: é a gramática visual consolidada de produto (shadcn charts, Tremor, dashboards modernos); a restrição monótona é o que a torna compatível com a honestidade de eixo do DG4.

DG15b — guarda do raio consistente (defeito achado pelo OLHO, não pela regex). Dentro do mesmo SVG, retângulos da mesma altura usam o mesmo raio. A primeira verificação automatizada das pílulas casou só 3 de 7 barras (regex fraca); o Rafael apontou a inconsistência no preview. A suite ganhou o teste DG15b (raio ↔ altura por classe de elemento), permanente.

DG16 — palco mínimo. Máximo 3 gridlines hairline por gráfico; sem linha de eixo desenhada (os rótulos flutuam); o número é o protagonista do cartão-KPI (fs-h2, peso 800) com rótulo em micro-caps mono; variação em badge-pílula suave (fundo feedback-*-bg, texto feedback-*-text); ponto de status sempre com rótulo textual ao lado (cor nunca sozinha — 1.4.1, mesma lei de sempre).

DG17 — destaque × contexto. Gráfico de série única pode realçar 1 categoria em cor com as demais em cinza-200 — o cinza aqui é "contexto", não "sem dado" (o no-data continua exclusivo do hachurado; a distinção é a hachura, testada na suite). Uso canônico: ranking de usinas com a usina em foco destacada.

Lei transversal 1 — hierarquia de traço (3 pesos + non-scaling-stroke). DADO = 2px (linha de tendência, sparkline) · ESTRUTURA = 1px (gridline, trilha; a marca de meta do medidor usa 1,5px como exceção registrada — precisa vencer a banda atrás dela) · APOIO = 0,5px (linha-guia de rótulo, tick). E todo SVG de gráfico usa vector-effect: non-scaling-stroke nos traços. Racional medido: os viewBox da suíte de previews escalam de 0,66× a 12,4× na tela real — o mesmo stroke-width="1" renderizava entre meio pixel e doze; sem o atributo, a hierarquia de peso é destruída pelo layout responsivo.

Lei transversal 2 — consumo da categórica estendida (os VALORES estão na §3c; as leis são estas). (a) Sequência de entrada fixa: turquesa → dourado → magenta → azul → violeta → azul-800. (b) Até 5 séries, as famílias de matiz são todas distintas — nenhum gráfico multi-série pareia dois tons da mesma família. (c) A 6ª posição é a única exceção (azul-800: mesma família da cat-4, a 28 pontos de claridade no light), e 6 séries é o teto absoluto da categórica — acima disso, o gráfico se reestrutura (agrupamento "Outros", facetas, destaque×contexto DG17). (d) Dourado (cat-2): permitido em área grande com rótulo direto; vetado como fill solitário sem rótulo — gráfico de série única nunca nasce em cat-2. (e) Magenta e violeta são exclusivos de dado: aparecerem em UI é defeito, e a suite não os aceita fora de contexto chart-*.

Ordem 2↔3 — decisão de gate com racional registrado: a sequência proposta era turquesa → magenta → dourado; o Rafael inverteu para turquesa → dourado → magenta porque turquesa e magenta são ambos tons médios saturados (56 e 49% de claridade) e liam parecidos como vizinhos de pilha — o dourado (75%) entre eles separa por PESO, não só por matiz. É a mesma lógica do espalhamento de claridade do DG13, aplicada na ordenação.


Esc