Communitygithub.com

2016judea/ascii-charts

Crie gráficos como texto simples com blocos Unicode — barras, faixas, marcadores, colchetes, histogramas de estrelas, mapas de calor, linhas, diagramas de Venn, pizza, rosca e dispersão — com um script Python sem dependências, para qualquer lugar onde apenas texto monoespaçado sobreviva (blocos de código em newsletters, Markdown, terminais, e-mails de texto simples, chat). Use quando um gráfico precisa ser incorporado como texto literal em vez de uma imagem ou serviço de terceiros, ou quando você deseja um visual artesanal de terminal sem rodapé de marca.

O que é ascii-charts?

O ascii-charts é uma ferramenta Python sem dependências que gera gráficos usando caracteres Unicode em texto monoespaçado, ideal para ambientes onde imagens não podem ser usadas, como newsletters por e-mail, Markdown, terminais ou chats. Ela oferece uma ampla variedade de tipos de gráficos, incluindo barras, faixas, gráficos de marcadores, histogramas de estrelas, mapas de calor, linhas, diagramas de Venn, pizza, rosca e dispersão — todos renderizados como texto literal, sem branding externo. A ferramenta é útil para situações onde um gráfico precisa ser embutido diretamente no texto, mantendo a consistência visual em qualquer plataforma que suporte monoespaço. O script é simples de usar: cada tipo de gráfico tem uma função dedicada em `scripts/ascii_chart.py`, e o usuário pode gerar exemplos executando `python3 scripts/ascii_chart.py`. A documentação enfatiza o "teste de 2 segundos" — o gráfico deve ser compreendido instantaneamente por um leitor cansado, sem necessidade de legendas complexas. A ferramenta suporta recursos avançados como correção de proporção para círculos (fator de 2.49) e largura máxima de 44 caracteres para visibilidade em dispositivos móveis. O foco está em clareza e simplicidade, evitando gráficos desnecessários que apenas adicionam custo de decodificação sem agregar informação.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/2016judea/brick-mortar-skills/tree/HEAD/skills/ascii-charts

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Gráficos ASCII

Gráficos em estilo terminal construídos a partir de caracteres Unicode de bloco simples e incorporados como texto literal: um bloco de código cercado em Markdown, uma tag <pre> em HTML. Sem serviço de gráfico, sem rodapé "feito com", sem conta externa, e eles renderizam de forma idêntica onde quer que monoespaço renderize.

scripts/ascii_chart.py tem uma função por tipo de gráfico. Execute python3 scripts/ascii_chart.py para imprimir um exemplo de cada tipo como verificação de sanidade.

Duas coisas aqui foram medidas em vez de assumidas, e ambas estavam erradas inicialmente: em uma viewport de telefone de 390px, linhas com mais de ~44 caracteres cortam a borda direita, e um círculo "redondo" em monoespaço precisa de uma correção de aspecto horizontal de cerca de 2.49 (não 2.0). Consulte Dimensionamento e a seção Pizza/rosca.

As plataformas de newsletter diferem em como colam blocos de código. Antes de confiar em uma, cole um gráfico de teste em um rascunho real e verifique as renderizações na web, aplicativo e e-mail.

Conjunto de caracteres

  • █ ▓ ▒ ░ (U+2588, U+2593, U+2592, U+2591 — sombreamento cheio/escuro/médio/claro) — densidade de preenchimento, de "mais" a "menos." Barras usam apenas █/░ (preenchido vs. trilha); pizza/rosca usam todos os quatro (mais ▚/▞/▤/▥ se houver mais de 4 fatias) como preenchimentos distintos por fatia; o mapa de calor usa todos os quatro mais · (ponto médio, não um espaço em branco) para o nível mais baixo, para que uma célula "silenciosa" ainda seja lida como parte intencional da grade, não uma lacuna.
  • dígitos 1–7 — códigos de região de Venn (uma máscara de bits de qual(is) conjunto(s) uma região pertence — veja Venn abaixo)
  • + — marcador de extremidade aberta em uma barra de faixa que pode ser maior que o teto mostrado (não estique a barra em si para fingir um número que você não tem)
  • ┃ — tick de destino do gráfico de marcador, desenhado sobre qualquer preenchimento/sombreamento que esteja por baixo, para que esteja sempre visível
  • └─┘ — colchete de lacuna, abrangendo entre duas extremidades de barra
  • ★/☆ — estrela preenchida/vazia, funcionando como rótulo de linha do histograma de estrelas
  • desenho de caixa (─│╭╮╰╯) — conectores de gráfico de linha e linha de tendência
  • ● — marcador de ponto de dispersão

Sem cor, em lugar nenhum. Esse é o meio, não uma limitação a ser contornada — um bloco de código colado do Substack são caracteres literais, nada mais sobrevive (sem CSS inline, sem spans estilizados). Qualquer distinção que um gráfico precise fazer reside no caractere/dígito/legenda, não em um canal de cor indisponível.

Menu de tipos de gráfico

TarefaFunçãoUse para
Comparação de magnitude, várias categorias, todas começam em 0bar(valor, valor_máx, largura) + renderizar()Abastecimento de gasolina (5 min) vs. carga rápida DC (45 min)
Uma faixa min–max, uma categoriabarra_faixa(início, fim, escala_máx, largura, extremidade_aberta=) + renderizar()"$100k–$300k+ instalado"
Dois valores, antes/depoisTexto simples: f"{início} → {fim}""Atacado $220 → bar $650" — uma barra não adiciona nada; a seta é o gráfico
Uma medida vs. uma faixa de referência + um alvomarcador(valor, escala_máx, alvo=, referência=) + renderizar()"Sua classificação: 4.2, faixa normal 3.8–4.5, alvo 4.7"
Destacar explicitamente a lacuna entre duas barrascolchete_lacuna(a, b, escala_máx, largura, rótulo=) via renderizar(colchete=)"Você vs. mediana do mercado" — o movimento característico do relatório
Uma distribuição de classificação de 1 a 5 (ou similar)histograma_estrelas(contagens)Detalhamento de estrelas do Google/Yelp, uma linha por contagem de estrelas
Dois eixos categóricos, sombreados por intensidademapa_calor(matriz, rótulos_linha, marcas_coluna=)Tráfego de pedestres por dia × hora — "quando você está ocupado/morto"
Tendência ao longo do tempo, uma sériegráfico_linha(valores, altura, rótulos_x=)Receita mensal, contagem de avaliações ao longo de um ano
Tendência, inline em uma fraseminigráfico(valores)"Avaliações por mês: ▂▃▅▆█▇▅▃, aumento de 3x desde março"
2 ou 3 conjuntos nomeados, onde o grau de sobreposição é a própria descobertavenn(rótulos)"38% de suas avaliações de uma estrela também mencionam tempo de espera" — o tamanho da sobreposição é o ponto
Partes de um todo, um instantâneopizza(fatias, raio)Mix de receita: café / comida quente / bebidas / loteria
Partes de um todo, com um total do títulorosca(fatias, raio, texto_centro=)O mesmo, com "247 avaliações" sentado no centro oco
Duas variáveis numéricas, existe uma relaçãodispersão(pontos, largura, altura)Preço vs. classificação entre concorrentes
O mesmo, mais "e aqui está a tendência"dispersão_com_tendência(pontos, largura, altura)O mesmo, com uma linha ajustada provando a correlação

Se nada nesta tabela se encaixar, pare e pense bem em vez de forçar uma forma que não se encaixa — um gráfico tecnicamente renderizável, mas confuso, é pior do que recorrer ao pipeline PNG headless do Chrome.

O teste de 2 segundos para gráficos

Um gráfico responde ao mesmo padrão que uma boa frase faz: ser compreendido por um leitor cansado em seu telefone, na primeira olhada, sem reler, sem decodificar. Aplique o teste antes de escolher um tipo de gráfico, não depois de construir um.

O teste de 2 segundos: o leitor pretendido — um proprietário de pequena empresa, não um analista de dados — poderia dizer o que este gráfico significa em até 2 segundos, sem ler uma legenda primeiro? Se entender até mesmo uma região ou fatia requer decodificar uma legenda primeiro, isso é o equivalente visual do jargão: tecnicamente preciso, mas faz o leitor trabalhar em vez de atraí-lo.

Pego em uma questão real, pelo editor lendo o post renderizado a frio:

  • O diagrama de máscara de bits de dígitos de Venn de 3 conjuntos exigia a leitura de uma legenda de 7 linhas antes que qualquer região significasse algo. O editor: eles não entenderam, então um empresário comum também não entenderia. O fato subjacente — "você precisa de todos esses três, não apenas um" — é uma frase, e a lista numerada logo após o diagrama já dizia isso em inglês simples. O diagrama adicionou custo de decodificação sem adicionar informação que a prosa já não carregava mais claramente. Correção: remova -o, deixe a frase + lista fazerem o trabalho.
  • A barra de faixa de custo do carregador DC rápido (uma única barra, sem eixo, sem ponto de comparação) não tinha nada para comparar. O valor de uma barra vem de mostrar uma magnitude relativa a algo — uma escala, outra barra, uma referência. Uma barra solitária sem ponto de referência é decorativa, não informativa. O número que ilustrava ($100k–$300k+) já estava declarado claramente uma frase antes. Correção: remova-a também.

Regras que se seguem:

  • Um gráfico que precisa de sua própria legenda para ser lido é um sinal de alerta — não apenas para Venn. Um mapa de calor com eixos não rotulados, ou uma pizza com mais fatias do que um leitor pode manter na cabeça, falha da mesma forma.
  • Se uma frase simples afirma o fato tão claramente quanto o gráfico faria, pule o gráfico. Mesmo instinto de trocar "vários/muitos/vários" por a contagem real na prosa: recorra a um visual porque uma comparação ou tendência é o ponto, não apenas porque os dados têm uma forma.
  • Cada barra precisa de um eixo (renderizar(..., eixo=)) ou de uma segunda barra na mesma escala para comparar. Uma única barra sem nenhum dos dois não transmite nada — a mesma falha de uma frase na voz passiva sem sujeito real. Mas uma vez que isso for satisfeito, remova o eixo se ele apenas reiterar um número já presente em um rótulo de valor por linha — uma barra de gasolina vs. carregamento removeu sua linha de eixo 0 ... 45 min exatamente por este motivo: ambas as linhas já carregam seu próprio valor ("5 min", "45 min"), então o eixo apenas repetia "45 min" uma segunda vez. Mesmo princípio de cortar uma cláusula redundante de uma frase.
  • Não crie gráfico para um número que já é uma frase limpa. "$100k–$300k+ instalado" é maximamente claro como texto; criar um gráfico para isso não revela uma comparação, tendência ou sobreposição, apenas adiciona uma etapa de decodificação sem retorno.
  • Leia o gráfico finalizado a frio, da forma que o leitor real o lerá — um proprietário de posto de gasolina em seu telefone, não a pessoa que acabou de construí-lo e já sabe o que ele deve dizer.

Fluxo de trabalho

Use scripts/ascii_chart.py em vez de alinhar caracteres manualmente ou rasterizar geometria você mesmo — matemática de colunas e matemática de círculo/ângulo são exatamente o tipo de coisa que é fácil de errar sutilmente a olho e só aparece como um desalinhamento de um caractere ou um círculo desequilibrado depois do fato. Execute python3 scripts/ascii_chart.py a qualquer momento para imprimir um exemplo de cada tipo de gráfico como verificação de sanidade.

Barra / barra de faixa

from ascii_chart import bar, barra_faixa, renderizar

linhas = [
    ("Abastecimento de gasolina", bar(5, 45, 24), "5 min"),
    ("Carga rápida DC", bar(45, 45, 24), "45 min"),
]
print(renderizar(linhas, eixo=("0", "45 min")))

linha = ("Carregador DC rápido", barra_faixa(100, 300, 300, 24, extremidade_aberta=True), "$100k–$300k+")
print(renderizar([linha]))

renderizar() recebe tuplas (rótulo, string_barra, string_valor) e lida com todo o alinhamento de colunas — passe seu próprio string_valor pré-formatado (moeda, unidades, o que a cópia precisar); a função apenas lida com geometria.

Gráfico de marcador

from ascii_chart import marcador, renderizar

linhas = [("Classificação média", marcador(4.2, 5.0, alvo=4.7, referência=(3.8, 4.5), largura=24), "4.2 (alvo 4.7)")]
print(renderizar(linhas, eixo=("0", "5.0")))

Uma barra sólida para o valor medido, desenhada sobre uma faixa de referência sombreada opcional (a faixa "normal", ▒) com um tick de alvo opcional (┃, sempre desenhado por último para que permaneça visível sobre qualquer preenchimento/sombreamento abaixo dele). Responde "estou dentro do normal e quão longe do alvo" em um relance — ainda há apenas uma barra real (a medida); a faixa é contexto.

Colchete de lacuna

from ascii_chart import bar, colchete_lacuna, renderizar

linhas = [("Você", bar(42000, 60000, 24), "$42,000"), ("Mediana do mercado", bar(58000, 60000, 24), "$58,000")]
print(renderizar(linhas, colchete=colchete_lacuna(42000, 58000, 60000, 24)))

Um colchete └─┘ abrangendo entre duas extremidades de barra, com o tamanho da lacuna centralizado dentro dele (auto-formatado a partir dos dois valores, ou passe rótulo= para seu próprio texto). Use o mesmo escala_máx/largura para as barras e o colchete, ou o intervalo não se alinhará. Isso é "você vs. o mercado", tornado explícito em vez de deixado para o leitor estimar.

Histograma de estrelas

from ascii_chart import histograma_estrelas

print(histograma_estrelas([(5, 61), (4, 22), (3, 9), (2, 4), (1, 4)]))

contagens é [(estrelas, contagem), ...] em qualquer ordem que você deseja imprimir (geralmente 5 até 1). Os glifos de estrela preenchida/vazia (★/☆) funcionam como o rótulo da linha — não há necessidade de também soletrar "5 estrelas" em texto. Construído inteiramente em bar() + renderizar().

Mapa de calor

from ascii_chart import mapa_calor

print(mapa_calor(matriz, ["Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"],
              marcas_coluna=[(0, "0h"), (6, "6h"), (12, "12h"), (18, "18h")]))

matriz é linhas × colunas de intensidade numérica (por exemplo, 7 dias × 24 horas), normalizada em toda a matriz (não por linha) para que o sombreamento seja comparável entre linhas. marcas_coluna é [(índice_coluna, rótulo), ...] — sem espaçamento automático, escolha posições que não colidirão para os rótulos que você passar.

Gráfico de linha / minigráfico

from ascii_chart import gráfico_linha, minigráfico

print(gráfico_linha([120, 135, 128, 150, 175, 190, 205, 198, 220],
                  altura=10, rótulos_x=("Jan", "Set")))

print(minigráfico([3, 5, 4, 8, 12, 10, 15, 14, 18]))

gráfico_linha desenha uma linha conectada com cantos de desenho de caixa (╭╮╰╯│─) — não há caractere para uma inclinação intermediária arbitrária, então a largura é fixa em len(valores) - 1 colunas (uma por segmento). rótulos_x, se fornecido, é apenas (primeiro, último) impresso na linha do eixo — diga os pontos intermediários na prosa ao redor, não tente rotular cada marca. minigráfico é uma tendência de 8 níveis de linha única (▁▂▃▄▅▆▇█) para uma cláusula dentro de uma frase, não um gráfico independente.

Venn (2 ou 3 conjuntos)

from ascii_chart import venn

diagrama, legenda = venn(["Saída de rodovia", "Grande loja", "Capacidade da rede"])
print(diagrama)
print(legenda)

Rasteriza círculos sobrepostos e preenche cada região com um dígito (uma máscara de bits de qual(is) conjunto(s) ela pertence: 1, 2, 4 para os conjuntos simples, 3/5/6 para sobreposições aos pares, 7 para todos os três) em vez de tentar encaixar texto de rótulo dentro de um limite curvo, o que não sobrevive à renderização monoespaçada. A legenda (retornada separadamente, imprima ambas) mapeia cada dígito de volta à combinação de rótulo real, por exemplo, 7 = Saída de rodovia + Grande loja + Capacidade da rede <- todos eles. Isso foi originalmente acreditado impossível em ASCII (um post inicial recorreu a um PNG headless do Chrome para seu Venn) — a técnica de região de dígito resolve isso de forma limpa; não há mais um caso onde Venn precise da alternativa PNG.

Mas execute-o através do teste de 2 segundos acima antes de recorrer a ele — a própria legenda de dígitos é a coisa que tornou um Venn real confuso para um leitor leigo. Um Venn ganha seu lugar quando o grau de sobreposição é a descoberta (por exemplo, "38% de suas avaliações de uma estrela também mencionam tempo de espera"). Quando a mensagem real é "você precisa de todos os três juntos, sem crédito parcial," um Venn é a ferramenta errada mesmo quando renderiza corretamente — texto simples faz esse trabalho sem legenda necessária, por exemplo:

Saída de rodovia  +  Grande loja  +  Capacidade da rede
        perca um desses, pule o site

Pizza / rosca

from ascii_chart import pizza, rosca

diagrama, legenda = pizza([("Café", 40), ("Comida quente", 25), ("Bebidas", 20), ("Loteria", 15)], raio=9)
print(diagrama); print(legenda)

diagrama, legenda = rosca([("Café", 40), ("Comida quente", 25), ("Bebidas", 20), ("Loteria", 15)],
                         raio=9, texto_centro="247")
print(diagrama); print(legenda)

As fatias começam às 12 horas e vão no sentido horário (convenção padrão de pizza), cada uma recebe um caractere de preenchimento distinto (█▓▒░▚▞▤▥, nunca repetido em uma fatia adjacente para contagens típicas de 2–6 fatias) para que os limites permaneçam legíveis sem cor. rosca é pizza com um centro oco — texto_centro coloca um número/rótulo do título lá (por exemplo, uma contagem total), que é a única coisa que uma rosca ASCII pode fazer que uma real geralmente desperdiça em espaço vazio. raio está em unidades de linha; a função corrige internamente para a proporção do caractere monoespaçado (constante ASPECTO compartilhada, também usada por venn()) para que o resultado seja realmente redondo, não uma oval achatada — não ajuste manualmente largura/altura separadamente, apenas passe raio.

Correção: ASPECTO estava codificado para um assumido 2.0

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

2016judea/buffett-checklist

Apply Warren Buffett's investment framework as a discipline lens when weighing a buy, hold, or sell decision — circle of competence, economic moat, owner earnings & intrinsic value, margin of safety, management/capital-allocation quality, and market psychology (Mr. Market, fear vs greed, temperament). Use when asked to "run this through Buffett", "what would Buffett say", "does this pass the moat test", "is this cheap enough", or for a second, more skeptical read on a name being evaluated or already held. This is a discipline overlay, not a replacement for a strategy — it applies the Buffett lens to how someone actually invests, rather than issuing generic advice.

2016judea/image-riff

Turn one or more reference images into original art in that reference's own visual language, then cut it to whatever surface it's for. Use when you paste or point at art and say "use this as the base image", "generate art from this", "riff on this", "some creative ideation with these images", "make me a channel banner / avatar / cover / plate", "wilder version of this", or want a spread of options off one piece of reference. This is the TASK skill; the engine is the `make-art` tool skill.

2016judea/leonardo

Draw the way Leonardo da Vinci drew — a study sheet, a notebook folio, a red-chalk or silverpoint study, a machine cutaway, a storm of vortices — in his real materials and page-logic, generated with the make-art engine and anchored on fifteen of his actual (public-domain) sheets. Use when you say "Leonardo", "da Vinci", "like his notebooks", "a codex page of X", "draw this as one of his study sheets", "sanguine", "silverpoint", or wants a design, diagram, or illustration in that hand. Also a reading guide to his notebooks (Richter's 1883 public-domain translation) for "what did Leonardo say about shadow / trees / water". This is a TASK skill; the engine is `make-art`.

2016judea/mcp-stack

Which free MCP server or framework to reach for, and its traps — finance/gov data (SEC EDGAR, Yahoo, SAM.gov, USAspending), web research (Exa, Firecrawl, Crawl4AI, Jina reader), design/art/brand (Canva, Inkscape, Penpot, Figma, Orshot, Hugging Face image gen, vectorizing, charts), data/spatial (DuckDB spatial, live ArcGIS layers, OpenStreetMap/Overpass, Census, MapLibre), and ops (PostHog, iMessage, context7 docs). Use when making a social post, OG card, poster, logo/vector, chart, map, or brand asset; when querying parquet/geojson/duckdb or a city's open-data layer; when an MCP "needs authentication" or fails; or when asked "what tools do we have", "is there an MCP for X", "should we add X".

2016judea/records-request

Get a specific record out of a US government office by public-records request — "request the assessor's model", "file a data practices request", "FOIA this", "open records request", "can we just ask the county for it", "who do I write to at <county>", "chase that request", "did they ever answer". Covers checking the website first, finding the right office and statute, the carve-out paragraph that makes a request answerable instead of refused, web-form traps (hidden character caps, WAFs that reject apostrophes), chasing (there is usually no deadline), whether what comes back may be republished, and parsing multi-year tables without silent errors.

2016judea/sms-native-product

Build a product whose interface is text messages rather than an app or a website — "no app, no website", "they just text a number", "chat with our agent natively in Text Messages", "can we do this over text", "an SMS bot", "a Telegram bot", "make it a group chat", "minimum viable friction". Fires equally when it has already gone wrong — "my campaign got rejected", "our number is blocked", "the texts aren't arriving", "why do I need to register". Covers the gate that decides whether such a product can send at all (US A2P 10DLC registration, SHAFT content rules, permanent rejection codes), group MMS from code, what each channel can't do, an architecture that survives losing the channel, and guarding model-rewritten user content.

2016judea/vertical-market-agent

Build a chat agent that knows one industry in one metro better than any general model because it carries a precomputed digest of real public records (or a mined review corpus) and can pull live records mid-conversation — finding the moat, building a byte-stable substrate, enumerating what the records can't, the data traps that produce plausible wrong numbers, deterministic math in tools, measured prompt cost and cache TTL, shipping as an ad destination, an off-sector ending, and a precomputed spatial "what is this next to" layer. Use when building a vertical AI agent grounded in records rather than general knowledge.

Habilidades Relacionadas