| name | tableau-twbx |
| description | Использовать при разборе книги или экстракта Tableau — файлы .twbx / .twb / .hyper, «справка по продажам из Tableau», «что в этой книге», «посчитай метрики из дашборда», Goods Board Report, экстракты sqlproxy, Hyper API, а также когда передали файл Tableau и ждут цифры, сводку или отчёт. Работает без установленного Hyper API; ставит его только с явного согласия. |
| metadata | {"short-description":"Читать книги и экстракты Tableau, обходить их капканы, отчитываться честно"} |
Разбор Tableau .twbx / .hyper
Область применения
Пришёл файл Tableau, и от него хотят либо структуру («что это за книга»), либо
цифры («посчитай выручку за неделю»). Скилл покрывает оба случая и — что важнее —
не разваливается, когда Hyper API не установлен и установить его нельзя.
Работает с .twbx (упакованная книга), .twb (только XML) и голыми экстрактами .hyper.
Этот проект
Факты конкретного проекта — книга, утверждённый периметр, реальные имена колонок,
подтверждённые капканы, недоступные метрики и готовые команды — лежат в CLAUDE.md в
корне проекта и грузятся каждую сессию. Читать его до любой работы с данными и не
переписывать сюда. Здесь только переносимый метод.
Главное правило
Имена полей в .twb — это НЕ имена колонок в .hyper.
XML несёт подписи модели Tableau: вычисляемые поля, псевдонимы, переименованные
колонки. Экстракт несёт физическую схему исходного запроса. Реальный случай: книга,
чей XML рекламировал GMV, Bill_Cnt, AUP_Sales_RUR, All_Inv_RUR_RRP, стояла на
экстракте с колонками sales_rur, sales_u, inv_rur_rrp — пересечение нулевое.
Поля из XML могут вообще не существовать в данных.
Отсюда: никогда не писать запрос по именам из .twb. Сначала интроспекция схемы, всегда.
.twb говорит, что считает отчёт; что лежит в данных, говорит только экстракт.
Уровни доступа — сначала разведка, потом план
bash scripts/probe.sh <путь-к-файлу>
Сообщает, какой уровень достижим, и ничего не устанавливает.
| Уровень | Требует | Даёт |
|---|
| 0 — Структура | только stdlib python3 | Дашборды, листы, источники, инвентарь полей, параметры, манифест экстрактов. Доступен всегда. |
| 1 — CSV | выгрузка-кросстаб из Tableau | Полный расчёт метрик по тому, что выгрузили. Без установки. |
| 2 — Прямой запрос | tableauhyperapi (установка по согласию) | SQL по экстракту. Всё. |
Уровень 0 запускать безусловно — он быстрый, бесплатный и объясняет, для чего книга,
а это определяет все дальнейшие вопросы. Подниматься выше только когда нужны цифры.
Уровень 0 — структура
python3 scripts/twb_inspect.py "Goods Board Report.twbx"
Только stdlib. Достаёт .twb из zip не распаковывая экстракты — книга на 932 МБ
отдаёт структуру меньше чем за секунду. На выходе markdown: версия, сервер-источник,
источники данных с классами подключения, дашборды, листы, параметры, подписи полей и
манифест экстрактов с размерами.
Уровень 1 — CSV, без установки
Когда нужны цифры, а уровень 2 недоступен или нежелателен, попросить выгрузку:
В Tableau открыть нужный лист → Download → Crosstab (или Data) → CSV.
Положить файл рядом с книгой.
Затем:
python3 scripts/csv_summary.py export.csv
Только stdlib csv, без pandas. Определяет кодировку и разделитель (Tableau часто отдаёт
UTF-16 с табами), разбирает форматирование чисел (1 234,56, (123), проценты), делит
колонки на измерения и меры, по запросу строит группировку и двумерную сводку.
Считать можно только то, что выгрузили, — так и говорить, не намекая на полноту.
Уровень 2 — прямой запрос (нужно согласие)
Установка — это загрузка пакета. Спрашивать каждый раз. Сказать что, откуда, сколько:
tableauhyperapi с PyPI, ~250 МБ, внутри движок hyperd от Tableau — официальный SDK,
единственный поддерживаемый способ читать .hyper вне Tableau. Плюс ~N МБ на распаковку
экстрактов. Ставлю?
При согласии — venv в проекте, а не системный интерпретатор:
bash scripts/setup_hyper.sh /путь/к/проекту
Создаёт .venv рядом с книгой и ставит туда. Системный и homebrew-питон помечены как
externally-managed (PEP 668); venv снимает вопрос --break-system-packages и сносится
одним rm -rf. Сразу сказать пользователю, как его удалить после работы.
Дальше интроспекция — этот шаг не пропускать никогда:
.venv/bin/python scripts/hyper_introspect.py extracts/*.hyper
Выдаёт схемы, таблицы, число строк, колонки и запускает автоматический свип капканов
(описан ниже). Читать его предупреждения до первого агрегата.
Запросы:
.venv/bin/python scripts/hyper_sql.py extract.hyper "SELECT ... "
Флаг --tsv отдаёт сырые значения без разделителей и с пустотой вместо NULL — для
машинного чтения; без флага печатает выровненную таблицу для человека.
Капканы данных — проверять все до отчёта
hyper_introspect.py печатает секцию TRAPS из шести автоматических проверок
(~1.5 с на экстракте в 10 млн строк). Полный каталог с SQL для ручной проверки —
references/data-traps.md.
| Проверка | Что ловит |
|---|
| Колонка сравнения периодов | fy_period ∈ {TY, LY, LLY, 3LY} — прошлые годы, переложенные на текущий календарь |
| Скелет будущих периодов | Заранее созданные строки незакрытых периодов; сообщает настоящий последний закрытый |
| Дублирование строк за флагом | Колонка типа full_week, делящая строки, но не меры |
| Sentinel-значения | Абсурдные целые (12345678912345001) вместо «неизвестно» |
| Предрасчитанные отношения | *_wov, *_pc_*, *_index — то, что нельзя суммировать |
| Разрежённые меры | План или бюджет на грубой грануляции, NULL почти везде |
Порядок свипа несущий. Колонка периода определяется первой, потому что скелет и
дублирование не видны вне среза текущего года: на всей таблице прошлогодние строки
маскируют скелет, а флаг дублирования на самой свежей дате показывает единственное
значение.
Скелетные строки не обязательно пустые. Снимки остатков доживают до незакрытых
периодов, поэтому проверка «все меры NULL» их пропускает. Надёжный сигнал — обвал числа
строк относительно медианы периода: 1 850 против 66 000.
Если оба значения флага покрывают полный набор ключей, два набора строк — копии друг
друга, и любой фильтр даёт верные итоги; свип рекомендует более полный.
Два капкана свип увидеть не может, им нужен контекст бизнеса: партийные каналы и
сдвиг сезонных кодов, оба ниже в «Гигиене сравнений».
Гигиена сравнений
Помимо капканов схемы — четыре проверки, отделяющие находку от артефакта:
- Выравнивание периодов. В таблицах с
fy_period ∈ {TY, LY, LLY, 3LY} прошлые годы
лежат переложенными на текущий календарь. Сравнивать строки LY по той же дате;
вычитать год из даты самостоятельно — ошибка.
- Эффект базы. До публикации любого YoY за один период построить тот же показатель за
12–13 предыдущих. Неделя −9 % на фоне ряда около +1 % обычно означает, что аномалией был
прошлый период, а не текущий. Прямо сказать, какой именно.
- Партийные каналы. Опт, B2B, франшиза, дистрибуция отгружаются партиями. Недельный YoY
по такому каналу — шум: одна отгрузка составляет весь период. Смотреть собственную историю
канала до того, как приписывать ему падение; отчитываться по нему месяцем или кварталом.
- Сдвиг сезонных кодов. Коды коллекций сдвигаются год к году (
AW27 сейчас против
AW26 тогда), поэтому разрез YoY по коду сезона сравнивает разное. Нужен относительный
индекс сезона, а не сырой код.
Отчётность
Структура и тон — references/reporting.md.
Без исключений: сказать, что посчитать не удалось. В экстрактах регулярно нет маржи
(нет себестоимости), количества чеков (штуки ≠ чеки) и плана (разрежён или NULL на нужном
периметре). Назвать три отсутствующие метрики полезнее, чем молча выдать пять имеющихся и
позволить читателю додумать остальное.
Тоже без исключений: методику класть в сам документ. Какие фильтры задали периметр,
какой капкан обезврежен и как, какое сравнение искажено базой. Читатель правления, который
не может восстановить периметр, не может действовать по цифре.
Форма результата
| Форма | Когда |
|---|
| Markdown рядом с книгой | Базовый вариант, всегда |
| Страница-дашборд, 5 стилей | У отчёта есть аудитория: ссылка правлению, экранный показ |
| Дашборд + PDF | Нужна именно распечатка или файл в рассылку |
Страница-дашборд собирается из готовых стилей — ledger, terminal, editorial,
panel, blueprint — одним файлом данных на все пять:
python3 scripts/build_report.py --style ledger --data report-data.json --out dashboard.html
Контракт данных, характер каждого стиля и порядок — references/report-styles.md;
эталонный файл данных — assets/report/example-data.json. Стили экранные: собрать
несколько вариантов и дать выбрать глазами. В PDF их не гнать — печатного CSS там нет.
PDF-ветка остаётся на своём шаблоне (метод — references/board-dashboard.md):
cp assets/board-dashboard.html <проект>/dashboard.html
bash scripts/render_pdf.sh <проект>/dashboard.html "<проект>/Отчёт.pdf"
В обоих случаях оформлять только после того, как капканы обезврежены — иначе
получается красиво поданная ошибка.
PDF после сборки прочитать глазами — инструментом Read с параметром pages. Скрипт
проверяет число страниц и геометрию, но не видит раздутых графиков, схлопнувшихся колонок
и налезающих подписей. Главный капкан здесь: headless-браузер считает медиазапросы по окну,
а не по печатной странице, и без --window-size раскладка рассыпается только в PDF,
оставаясь верной на экране.
Ориентация задаётся третьим аргументом (landscape по умолчанию, portrait) и правилом
@page в самом HTML — менять оба, иначе окно и страница разойдутся.
Гигиена рабочей папки
- Экстракты
.hyper распаковывать во временную директорию, не рядом с книгой — они обычно
в 3–10 раз больше .twbx.
- Для уровня 0 достаточно
.twb; не распаковывать экстракты ради вопроса о структуре.
- Движок Hyper пишет
hyperd.log в рабочую папку, и тот разрастается до мегабайтов —
удалить после работы.
- По завершении предложить уборку:
rm -rf .venv и временные экстракты.
Файлы
| Путь | Уровень | Назначение |
|---|
scripts/probe.sh | — | Определить доступный уровень, ничего не ставить |
scripts/twb_inspect.py | 0 | Структура книги из XML, только stdlib |
scripts/csv_summary.py | 1 | Разбор CSV-выгрузки Tableau, только stdlib |
scripts/setup_hyper.sh | 2 | Создать venv и поставить Hyper API (нужно согласие) |
scripts/hyper_introspect.py | 2 | Дамп схемы и автоматический свип капканов |
scripts/hyper_sql.py | 2 | Выполнить SQL, напечатать результат |
scripts/build_report.py | 3 | Собрать страницу-дашборд: тема + тело + данные, только stdlib |
scripts/render_pdf.sh | 3 | HTML-дашборд в PDF через headless Chrome, с проверкой геометрии |
assets/report/ | 3 | Пять стилей страницы: styles/*.css, bodies/*.html, движок core.js, эталон example-data.json |
assets/board-dashboard.html | 3 | Шаблон PDF-ветки: темы, печатная вёрстка, шесть графиков |
references/data-traps.md | — | Полный каталог капканов с SQL для проверки |
references/reporting.md | — | Структура отчёта, правила честности, блок методики |
references/report-styles.md | 3 | Пять стилей: контракт данных, характер каждого, порядок сборки |
references/board-dashboard.md | 3 | PDF-ветка: сборка, правила печати, капкан headless-рендера |