Dataviz
4. Sub-bloco DG — gráficos core
seed-dataviz.md v0.22 · §04seção 6 de 1204-sub-bloco-dg-graficos-core-13-decisoes.md · MD5 cc8ee980Tí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.html— v1.2 (82.126 B, md58d1930598b9d124d3807fc80f70b0fbf) é 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.mjs— 163 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.py⚠ desatualizado (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-14,30 (reprova o piso 4,5 — na paleta antiga dava 5,11) ·cat-27,48 ✓ ·cat-33,40 ✗ ·cat-44,17 ✗ ·cat-53,43 ✗ ·cat-61,46 ✗, mas branco sobrecat-6mede 9,52 ✓. Resultado vigente: rótulo interno só emcat-2(tinta escura) ecat-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 sobrecat-1a 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 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:cinza-900.
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-900no light,cinza-100no 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-datapor 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 ecat-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" paragrayscale ∩ (escuro OU ≥4 séries). O vocabulário de textura, a exclusividade da diagonal a 45° para ochart-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 ocontraste-dg.pypercorre 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.htmlda 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.