Аккуратные графики из таблиц
Строит графики и диаграммы из табличных данных в едином аккуратном стиле и выдаёт PNG, SVG или самодостаточную интерактивную HTML-страницу.
- Что делает
- Строит графики и диаграммы из табличных данных в едином аккуратном стиле и выдаёт PNG, SVG или самодостаточную интерактивную HTML-страницу.
- Когда брать
- Когда нужно построить график или визуализировать данные и результат должен выглядеть лучше стандартных настроек matplotlib.
- Когда не брать
- Если не нужен график, а достаточно таблицы или числа; без Python и matplotlib скрипты не запустятся.
- Пример запроса
- Построй график продаж по неделям из этой таблицы с подписью источника и пометкой на пике.
- Нужно подключить
- Python, matplotlib, терминал
Входит в плагин claude-tag-data-viz. В Cowork и Claude Code можно поставить плагин целиком.
Как включить
- Скачайте архив и распакуйте его.
- Положите папку
graphingв~/.claude/skills/. - Откройте Claude Code и опишите задачу своими словами: Claude подхватит скилл по описанию.
Текст
---
name: graphing
description: Составляет аккуратные графики (временные ряды, столбчатые, линейные, с областями, круговые, точечные и любые другие, какие требуют данные) из табличных данных на примитивах chartkit и выдаёт PNG, SVG или самодостаточный интерактивный HTML. Используй, когда пользователь просит построить график, диаграмму или визуализировать данные и хочет результат лучше стандартных настроек matplotlib.
---
Построение графиков
Код для построения графика пишешь ты. Набор инструментов даёт то, что должно быть единым в каждом графике: типографику, вывод цветов из фона, рамку с заголовком и подписью, упаковку HTML для работы офлайн. Всё, что касается самого графика, — твоё суждение, применённое к данным, которые перед тобой.
Примитивы
Импортируй chartkit, добавив каталог scripts/ этого скилла в sys.path. Используй абсолютный путь, а не относительный, так как твой рабочий каталог — проект пользователя. В примерах ниже путь записан как /path/to/graphing/scripts; подставь настоящий.
Нужные примитивы:
theme(bg, font): задаёт rcParams matplotlib и возвращает вычисленные цвета. Цвета переднего плана выводятся из яркости фона, так что тёмныйbgдаёт правильный тёмный график. Поля:bgdarktextmutedgridspineaccentsecondaryseriesfont_css.palette(n, base): n цветов. Без base перебирает ряд цветов по умолчанию, hex-цвет в base строит из него градиент, список — перебирает цвета из списка.finish(ax, title, subtitle, source): типографическая рамка. Жирный заголовок по левому краю, приглушённый подзаголовок, мелкая подпись об источнике.save(fig, stem, formats, dpi): записываетstem.png,stem.svgили оба. Возвращает пути.write_html(out, data, component_js, title, bg, font): самодостаточная интерактивная страница. Встраивает React, ReactDOM, react-is и Recharts изthird_party/, чтобы файл открывался офлайн. Твой компонент читаетwindow.__CHART_DATA__и отрисовывается в#root.zero_fill_days(pairs)rolling_mean(values, w)log_floor(values): небольшие помощники для подводных камней, перечисленных ниже. Используй их, только когда они подходят.
Шаги
- Посмотри на данные и реши, чего они заслуживают. Выбор определяют форма, количество и смысл: тренды во времени просят линии или столбцы по дням, ранжированные категории — горизонтальные столбцы, части целого с малым числом долей могут быть круговой диаграммой, корреляция просит точечный график. Ничто не ограничивает тебя этим: диаграммы с накоплением, двойные оси, серия малых графиков (small multiples), подписанные пороги — это просто код, который ты пишешь.
- Выведи цвета из контекста. Проверь разговор и память на признаки дизайна: конфиг tailwind, CSS-переменные или фирменные правила, и учти смысл данных (красный или янтарный для ошибок, зелёный для успеха). Передай фон места назначения в
theme(bg=...), а фирменные цвета — вpalette(base=...)или напрямую. К значениям по умолчанию возвращайся, только когда ничего вывести нельзя. Шрифт по умолчанию — Inter, и он меняется, только если пользователь назвал гарнитуру или у места назначения есть задокументированный фирменный шрифт.
- Напиши короткий скрипт в своей черновой папке (scratchpad), который импортирует chartkit, строит фигуру обычным matplotlib (или компонентом Recharts для интерактивного результата), вызывает
finishи сохраняет.
- Отрисуй и посмотри на результат. Прочитай PNG обратно и проверь собственными глазами, прежде чем отдавать: подписи читаемы, ничего не накладывается, цвета различимы, история данных действительно видна. Исправляй и перерисовывай, пока не получится как надо.
Устройство скрипта графика
PNG или SVG через matplotlib:
import sys
sys.path.insert(0, "/path/to/graphing/scripts")
import chartkit as ck
import matplotlib.pyplot as plt
c = ck.theme() # or theme(bg="#0f1419") for a dark surface
fig, ax = plt.subplots(figsize=(10, 5))
# ...plain matplotlib against the data, using c.accent, c.secondary, ck.palette(...)
ck.finish(ax, title="What the chart shows", subtitle="scope or time range",
source="source: where the data came from, date")
print(ck.save(fig, "out/report", formats=("png", "svg")))
Интерактивный HTML через Recharts, написанный простым React.createElement, без JSX и без этапа сборки:
component = """
(function () {
var e = React.createElement
var R = window.Recharts
var DATA = window.__CHART_DATA__
function App() {
return e(R.ResponsiveContainer, { width: "100%", height: 420 },
e(R.LineChart, { data: DATA },
e(R.CartesianGrid, { stroke: "GRID", vertical: false }),
e(R.XAxis, { dataKey: "x" }), e(R.YAxis, null),
e(R.Tooltip, null),
e(R.Line, { dataKey: "y", stroke: "ACCENT", strokeWidth: 2.4,
dot: false, isAnimationActive: false })))
}
ReactDOM.createRoot(document.getElementById("root")).render(e(App))
})()
"""
ck.write_html("out/report.html", data, component, title="What the chart shows")
Подставь в компонент настоящие цвета из темы и оставь isAnimationActive: false, чтобы график был полностью готов в момент открытия файла.
Суждение, а не флаги
Это настройки по умолчанию хороших графиков. Отступай от них, когда этого требуют данные.
- Поворачивай подписи по оси x, только если иначе они столкнутся. Короткие подписи оставляй горизонтальными.
- Ограничивай ширину столбца, когда категорий мало. Два столбца не должны заполнять холст от края до края.
- Подписывай столбцы значениями, когда их примерно дюжина или меньше. Оси и линии сетки нужны, чтобы читать тренды, а не точные значения.
- Упорядочивай столбцы категорий по значению, если у категорий нет естественного порядка.
- Длинные названия категорий лучше читаются на горизонтальной столбчатой диаграмме.
- Заголовок говорит, что показывает график. Подзаголовок несёт временной диапазон или охват. Подпись об источнике говорит, откуда и когда взяты данные. Пропускай любое из этого только намеренно.
- Легенда нужна, только когда рядов больше одного. Единственный ряд называет заголовок.
- Отмечай на графике то, что важно: линию выкладки, порог, пик, аномалию, о которой спрашивал пользователь. Пометка, которая читателю не нужна, — это мусор.
Подводные камни, ради которых есть помощники
- Календарные пропуски: временной ряд с пропущенными днями вводит в заблуждение на непрерывной оси.
zero_fill_daysзаполняет их нулями. Не используй, когда нули были бы ложью (редкая выборка, а не отсутствие событий). - Скользящие средние:
rolling_meanсчитается по предыдущим значениям (trailing), ранние точки усредняют то, что есть на данный момент. Не центрируй его на данных, которые заканчиваются сегодня. - Логарифмические шкалы: столбцы, значение которых равно минимуму оси, получают нулевую высоту.
log_floorдаёт нижнюю границу на порядок ниже. - Отрицательные значения: matplotlib с ними справляется, но проверь, что пределы по y их включают, и добавь нулевую линию, когда столбцы идут в обе стороны. Области значений по y в Recharts по умолчанию начинаются с нуля, поэтому передай явный
domainдля YAxis, когда данные отрицательные или шкала логарифмическая.
Проверка
Сделай минимальную отрисовку и посмотри на неё.
python3 -c "
import sys
sys.path.insert(0, '/path/to/graphing/scripts')
import chartkit as ck
import matplotlib.pyplot as plt
c = ck.theme()
fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(['A', 'B', 'C'], [10, 30, 20], color=c.accent, width=0.5)
ck.finish(ax, title='chartkit smoke test')
print(ck.save(fig, '/tmp/ck_smoke'))
"
Убедись, что записан непустой PNG, затем прочитай его обратно и проверь, что он отображается правильно.
Перевод: iiuniversitet. Оригинал: https://github.com/anthropics/claude-tag-plugins/tree/main/claude-tag-data-viz/skills/graphing, лицензия Apache-2.0. Изменения: перевод на русский язык.
Оригинал на английском
---
name: graphing
description: Compose polished charts (timeseries, bar, line, area, pie, scatter, or anything else the data calls for) from tabular data using the chartkit primitives, producing PNG, SVG, or self-contained interactive HTML. Use when the user asks to chart, graph, plot, or visualize data and wants something better than raw matplotlib defaults.
---
# Graphing
You write the plotting code. The kit provides the parts that should stay consistent across every chart: typography, color derivation from the background, the title and caption frame, and offline HTML packaging. Everything about the chart itself is your judgement applied to the data in front of you.
## The primitives
Import `chartkit` by putting this skill's `scripts/` directory on `sys.path`. Use its absolute path, not a relative path, since your working directory is the user's project. The examples below write it as `/path/to/graphing/scripts`; substitute the real path.
Relevant primitives:
- `theme(bg, font)`: sets matplotlib rcParams and returns resolved colors. Foreground colors derive from background luminance, so a dark `bg` produces a correct dark chart. Fields: `bg` `dark` `text` `muted` `grid` `spine` `accent` `secondary` `series` `font_css`.
- `palette(n, base)`: n colors. No base cycles the default series, a hex base builds a ramp from it, a list cycles the list.
- `finish(ax, title, subtitle, source)`: The typographic frame. Left-aligned bold title, muted subtitle, small provenance caption.
- `save(fig, stem, formats, dpi)`: Writes `stem.png`, `stem.svg`, or both. Returns the paths.
- `write_html(out, data, component_js, title, bg, font)`: Self-contained interactive page. Inlines React, ReactDOM, react-is, and Recharts from `third_party/` so the file opens offline. Your component reads `window.__CHART_DATA__` and renders into `#root`.
- `zero_fill_days(pairs)` `rolling_mean(values, w)` `log_floor(values)`: Small data helpers for the gotchas listed below. Use them only when they fit.
## Steps
1. **Look at the data and decide what it deserves.** Shape, count, and meaning drive the choice: trends over time want lines or day bars, ranked categories want horizontal bars, parts of a whole with few slices can be a pie, correlation wants a scatter. Nothing limits you to those: stacked areas, dual axes, small multiples, annotated thresholds are all just code you write.
2. **Infer colors from context.** Check your conversation and memory for design indicators: a tailwind config, CSS variables, or brand guidelines, and consider the semantic meaning of the data (red or amber for errors, green for success). Pass the destination background to `theme(bg=...)` and brand colors to `palette(base=...)` or directly. Fall back to the defaults only when nothing is inferable. The font defaults to Inter and only changes when the user names a typeface or the destination has a documented brand font.
3. **Write a short script** in your scratchpad that imports chartkit, builds the figure with plain matplotlib (or a Recharts component for interactive output), calls `finish`, and saves.
4. **Render and look at the result.** Read the PNG back and check it with your own eyes before handing it over: labels legible, nothing overlapping, colors distinguishable, the story of the data actually visible. Fix and re-render until it is right.
## The shape of a chart script
PNG or SVG via matplotlib:
```python
import sys
sys.path.insert(0, "/path/to/graphing/scripts")
import chartkit as ck
import matplotlib.pyplot as plt
c = ck.theme() # or theme(bg="#0f1419") for a dark surface
fig, ax = plt.subplots(figsize=(10, 5))
# ...plain matplotlib against the data, using c.accent, c.secondary, ck.palette(...)
ck.finish(ax, title="What the chart shows", subtitle="scope or time range",
source="source: where the data came from, date")
print(ck.save(fig, "out/report", formats=("png", "svg")))
```
Interactive HTML via Recharts, written as plain `React.createElement` with no JSX and no build step:
```python
component = """
(function () {
var e = React.createElement
var R = window.Recharts
var DATA = window.__CHART_DATA__
function App() {
return e(R.ResponsiveContainer, { width: "100%", height: 420 },
e(R.LineChart, { data: DATA },
e(R.CartesianGrid, { stroke: "GRID", vertical: false }),
e(R.XAxis, { dataKey: "x" }), e(R.YAxis, null),
e(R.Tooltip, null),
e(R.Line, { dataKey: "y", stroke: "ACCENT", strokeWidth: 2.4,
dot: false, isAnimationActive: false })))
}
ReactDOM.createRoot(document.getElementById("root")).render(e(App))
})()
"""
ck.write_html("out/report.html", data, component, title="What the chart shows")
```
Substitute real colors from the theme into the component and keep `isAnimationActive: false` so the chart is complete the moment the file opens.
## Judgement, not flags
These are the defaults of good charts. Deviate when the data argues for it.
- Rotate x labels only when they would otherwise collide. Short labels stay horizontal.
- Cap bar width when there are few categories. Two bars should not fill the canvas edge to edge.
- Label bars with their values when there are roughly a dozen or fewer. Axes and gridlines are for reading trends, not exact values.
- Rank categorical bars by value unless the categories have a natural order.
- Long category names read better on a horizontal bar chart.
- A title states what the chart shows. A subtitle carries the time range or scope. The source caption says where the data came from and when. Skip any of them only deliberately.
- Legends only when there is more than one series. A single series is named by the title.
- Annotate the chart with what matters: a deploy line, a threshold, the peak, the anomaly the user asked about. An annotation the reader did not need is clutter.
## Gotchas the helpers exist for
- Calendar gaps: a timeseries with missing days misleads on a continuous axis. `zero_fill_days` fills them with zero. Skip it when zeros would be the lie (sparse sampling rather than absence of events).
- Rolling averages: `rolling_mean` is trailing, early points average what exists so far. Do not center it on data that ends today.
- Log scales: bars whose value equals the axis minimum get zero height. `log_floor` gives a lower bound one decade down.
- Negative values: matplotlib handles them, but check the y limits include them and add a zero line when bars go both ways. Recharts y domains default to starting at zero, so pass an explicit `domain` on the YAxis when data is negative or log scaled.
## Verification
Run a minimal render and look at it.
```bash
python3 -c "
import sys
sys.path.insert(0, '/path/to/graphing/scripts')
import chartkit as ck
import matplotlib.pyplot as plt
c = ck.theme()
fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(['A', 'B', 'C'], [10, 30, 20], color=c.accent, width=0.5)
ck.finish(ax, title='chartkit smoke test')
print(ck.save(fig, '/tmp/ck_smoke'))
"
```
Confirm a non-empty PNG is written, then read it back and check it renders correctly.
Источник: anthropics/claude-tag-plugins / claude-tag-data-viz / graphing ↗. Ссылка проверена 2026-10-10.