Posit выпустили ggsql — грамматику графики прямо в SQL-запросе

Posit, авторы ggplot2 и tidyverse, выпустили SQL-расширение для грамматики графики. Разбираем синтаксис, полный пример и зачем это нужно в мире, где уже есть ggplot2.

Обложка: Posit выпустили ggsql — грамматику графики прямо в SQL-запросе

Если вы визуализируете данные из SQL-запроса и каждый раз упираетесь в «экспортировать таблицу — открыть Python — подключить matplotlib», у вас есть повод попробовать другое. ggsql — расширение SQL от Posit, которое позволяет описывать график прямо в запросе: ключевые слова VISUALIZE и DRAW превращают таблицу в scatter, гистограмму или boxplot без промежуточного материализованного датафрейма.

20 апреля 2026 года Posit (бывшая RStudio; компания поддерживает ggplot2 и tidyverse — набор R-пакетов для анализа данных, созданный Хэдли Уикхемом) анонсировала альфа-релиз ggsql. Внутри — почему SQL и «грамматика графики» хорошо сочетаются, разбор синтаксиса на примерах с пингвинами и астронавтами и планы на Rust-рендерер, интерактивность и LSP (Language Server Protocol — стандарт автодополнения и подсказок для IDE).

Грамматика графики (grammar of graphics) — теоретическая система, в которой любой график собирается из модульных частей: данные, аэстетические маппинги (что и на какую ось), геометрические слои (scatter, bar, line), шкалы и подписи. Подход описан в книге Лиланда Уилкинсона и доведён до практики в пакете ggplot2 Хэдли Уикхема.

Ключевые выводы
Ключевые выводы
ggsql за минуту
  • ggsql — SQL-расширение для визуализации: VISUALIZE + DRAW вместо отдельного пакета графики. Альфа-релиз, бэкенд — DuckDB.
  • Полный пайплайн от данных до слоя графика выполняется одним SQL-запросом на бэкенде: для bar-чарта из 10 миллиардов транзакций клиент получает только количество точек для каждого бара, а не сами 10 миллиардов строк.
  • Синтаксис — декларативный и композиционный: весь накопленный опыт ggplot2 перенесён в SQL-совместимую форму. Заменяете слой или маппинг — меняется график, без переписывания кода.
  • Не требует R или Python-рантайма: отдельный исполняемый файл проще встраивать в BI-инструменты и ИИ-агенты, проще изолировать от недоверенного кода.
  • Работает в Quarto, Jupyter-ноутбуках, Positron и VS Code. Документация и туториал — на ggsql.org.

Знакомство с ggsql

Начнём с «hello world» визуализаций — обычной диаграммы рассеяния (scatterplot) на встроенном датасете penguins:

			VISUALIZE bill_len AS x, bill_dep AS y FROM ggsql:penguins
DRAW point
		
Scatterplot зависимости глубины клюва от его длины у пингвинов
Первая визуализация на ggsql: scatter-чарт bill_len × bill_dep на встроенном датасете penguins (источник — Posit)

Запрос можно прочитать вслух и понять, что он делает. Маппинг — это связь столбца с визуальным свойством (в грамматике графики такие свойства называют эстетиками): x-координата, цвет, размер. Построчно:

  • VISUALIZE открывает визуальный запрос и задаёт маппинги: x берётся из столбца bill_len, y — из bill_dep, данные — из встроенного датасета ggsql:penguins.
  • DRAW point добавляет слой с точками, который по умолчанию использует маппинг, заданный выше.

Теперь начнём наращивать график. Добавим цвет по виду пингвина:

			VISUALIZE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins
DRAW point
		
Scatterplot пингвинов с цветовой разбивкой по виду
Один дополнительный маппинг — и точки окрашены по категории species

Одно изменение в маппингах добавило цветовую категоризацию. Эта постепенная эволюция кода графика — одна из главных сильных сторон грамматики графики: нет предопределённых типов графиков, есть модульные части, которые можно комбинировать, добавлять и убирать. Добавим сглаженную линию регрессии поверх точек:

			VISUALIZE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins
DRAW point
DRAW smooth
		

Новый слой поверх точек наследует тот же маппинг. Так как цвет разбит по видам, сглаживание тоже посчитается отдельно для каждого вида.

Можно продолжать дальше — добавлять маппинги, менять слои местами, управлять шкалами, пока не получится нужный график. Например, если нас интересует распределение видов по трём островам, с которых собирали данные, код меняется минимально:

			VISUALIZE island AS x, species AS color FROM ggsql:penguins
DRAW bar
		

Совсем другой график — а большая часть кода осталась прежней.

Полный пример

С первыми графиками разобрались — переходим к полному примеру. Там будут новые элементы синтаксиса, но с ними тоже разберёмся. Пример адаптирован из визуализации Jack Davison для TidyTuesday.

			WITH astronauts AS (
  SELECT * FROM 'astronauts.parquet'
  QUALIFY ROW_NUMBER() OVER (
    PARTITION BY name
    ORDER BY mission_number DESC
  ) = 1
)
SELECT
  *,
  year_of_selection - year_of_birth AS age,
  'Age at selection' AS category
FROM astronauts
UNION ALL
SELECT
  *,
  year_of_mission - year_of_birth AS age,
  'Age at mission' AS category
FROM astronauts

VISUALIZE age AS x, category AS fill
DRAW histogram
  SETTING binwidth => 1, position => 'identity'
PLACE rule
  SETTING x => (34, 44), linetype => 'dotted'
PLACE text
  SETTING
    x => (34, 44, 60),
    y => (66, 49, 20),
    label => (
      'Mean age at selection = 34',
      'Mean age at mission = 44',
      'John Glenn was 77\non his last mission -\nthe oldest person to\ntravel in space!'
    ),
    hjust => 'left',
    vjust => 'top',
    offset => (10, 0)
SCALE fill TO accent
LABEL
  title => 'How old are astronauts on their most recent mission?',
  subtitle => 'Age of astronauts when they were selected and when they were sent on their mission',
  x => 'Age of astronaut (years)',
  fill => null
		
Гистограмма возраста астронавтов при отборе и в момент миссии с аннотациями
Полный пример: гистограмма возраста астронавтов + пунктирные линии средних + текстовые аннотации. Источник — блог Posit

Кода много, но он покрывает почти весь ключевой синтаксис сразу.

На верхнем уровне у запроса две части: SQL-запрос и визуальный запрос. SQL-запрос — всё, что идёт до ключевого слова VISUALIZE. Это обычный SQL (в примере есть CTE — общее табличное выражение в секции WITH, и DuckDB-специфичное QUALIFY, которое фильтрует оконные функции): ggsql принимает всё, что принимает ваш бэкенд. Результирующая таблица не возвращается как обычно, а уходит прямо в визуализацию. Любая CTE, созданная здесь, доступна в визуальном запросе.

SQL-часть необязательна. Если данные уже в нужной форме, можно указать источник прямо в VISUALIZE:

			VISUALIZE year_of_selection AS x, year_of_mission AS y FROM 'astronauts.parquet'
		

Теперь по визуальному запросу — всё, что идёт после VISUALIZE. Ключевое слово VISUALIZE отделяет SQL от визуального запроса (или VISUALISE для тех, кто предпочитает британское написание). Оно может стоять само по себе или задавать маппинги по умолчанию для всех последующих слоёв. Маппинг — это как SELECT, где вы привязываете столбцы к абстрактным визуальным свойствам (в грамматике графики они называются аэстетики).

В примере выше мы указали: столбец age хранит значения, которые пойдут в x (позиция по оси), а столбец category — значения, которые пойдут в fill (цвет заливки). Ничего про то, как это отрисовать, ещё не сказано.

DRAW и PLACE: слои графика

После VISUALIZE идёт DRAW — способ добавить слой. Типов слоёв в ggsql много. Одни простые — point для scatter. Другие сложнее — histogram (как в примере) требует посчитать производные статистики: биннинг и подсчёт количества в бинах. У визуализации может быть сколько угодно слоёв, они рендерятся в порядке объявления.

У DRAW есть родственная конструкция — PLACE. Работает так же, но данные берёт не из таблицы, а из заданных буквально значений. Это нужно для аннотаций. В примере выше три слоя: гистограмма с данными из таблицы, rule-аннотация с заранее рассчитанными средними для каждой категории и text-аннотация с поясняющими подписями.

Слой — это не обязательно одна графическая сущность. В text-слое выше рендерятся три отдельные подписи. То есть не нужно класть три отдельных line-слоя, чтобы нарисовать три линии разных категорий.

SCALE: преобразование данных в визуальные значения

После DRAW и PLACE идёт SCALE. Эта конструкция управляет тем, как значения данных переводятся в значения, осмысленные для аэстетики. В примере столбец category хранит строки Age at selection и Age at mission, которые сами по себе не являются цветом. Запись SCALE fill TO accent говорит ggsql взять палитру accent и сопоставить значения fill с цветами.

SCALE умеет больше: применять преобразования к непрерывным данным, задавать точки разбиения, выставлять тип шкалы (например, ординальную или бинную).

LABEL: подписи осей и легенд

Последняя конструкция визуального запроса — LABEL. Она добавляет или меняет текстовые подписи: заголовок, подзаголовок, подписи осей и легенд.

Шаг назад: короткий синтаксис

Два хороших известия. Во-первых, вы уже знаете основные элементы синтаксиса (есть ещё нюансы, но в них легко вырасти). Во-вторых, многие визуальные запросы будут гораздо короче полного примера. Например, boxplot (диаграмма-ящик с усами: показывает медиану, квартили и выбросы) года рождения астронавтов, разбитый по полу:

			VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet'
DRAW boxplot
		

Коротко, но если вы приходите из другой системы построения графиков, может показаться, что это многословно. Скажем, по сравнению с условным boxplot(x, y) в других библиотеках. Да, длиннее — но также структурированнее, композиционнее и самодокументируемее. Эти свойства — прямое следствие грамматики графики, и они означают, что и вам, и вашему ИИ-ассистенту по коду будет проще понимать, как строятся графики любого типа. 18 лет доминирования ggplot2 в R-экосистеме — это свидетельство в пользу такого подхода.

Например, тот же график можно переделать в jitter-scatter (scatter со случайным смещением точек, чтобы они не слипались в одну категорию):

			VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet'
DRAW point
  SETTING position => 'jitter'
		

Или так, чтобы jitter следовал распределению данных и работал как violin-плот:

			VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet'
DRAW point
  SETTING position => 'jitter', distribution => 'density'
		

Синтаксис и композиционная природа делают итерации над визуализацией очень эргономичными — это важно и в разведочном анализе, и в дизайне графиков.

Зачем ещё один инструмент визуализации

Писать библиотеку визуализации с нуля — большая задача. Причин, почему Posit взялись за это снова, несколько:

  • Хочется работать с аналитиками и data-сайентистами, которые живут в SQL.
  • SQL и грамматика графики хорошо подходят друг другу.
  • Хочется мощный code-based инструмент визуализации, который не требует целого языка программирования (R или Python).
  • LLM хорошо говорят на SQL — значит, и на ggsql заговорят.
  • 18 лет разработки ggplot2 дали много опыта, который приятно применить к чистому листу.

Привет, SQL-пользователь!

Пока R и потом Python забирали внимание в data-science-революции, SQL шёл своим ходом как надёжный рабочий инструмент. Есть много людей, которые работают с данными преимущественно или только через SQL. Варианты визуализации для них, по мнению Posit, субоптимальны:

  • Экспортировать данные и перейти в R или Python, что может быть за пределами зоны комфорта.
  • Использовать GUI-ориентированный BI-инструмент, у которого плохо с воспроизводимостью.
  • Полагаться на немногочисленные инструменты для графики прямо в запросе — но они недостаточно мощные или эргономичные.

Цель ggsql — чтобы синтаксис сразу был понятен SQL-пользователю, опирался на ожидания композиционных, декларативных конструкций.

Декларативная обработка, декларативная визуализация

Если читаете без знания SQL, краткое резюме: SQL — язык для манипуляции реляционными данными, хранящимися в одной или нескольких таблицах. Синтаксис опирается на концепцию реляционной алгебры — структурированного подхода к операциям над данными. Семантика описывает набор модульных операций, декларативных, а не функциональных, что даёт собирать мощные манипуляции из небольшого набора операций.

Если читаете без знания грамматики графики, краткое резюме: грамматика графики — теоретическая декомпозиция концепций визуализации на модульные части. Теория реализована в таких инструментах, как ggplot2. Семантика описывает набор модульных операций, декларативных, а не функциональных, что даёт собирать мощные и кастомные визуализации из хорошо определённого набора операций.

Из сравнения понятно: SQL и грамматика графики похожи в подходе к своим предметным областям. Вместе они дают естественное и мощное решение для полного конвейера от сырых данных до финальной визуализации.

Без рантайма — не беда

Почему важно, что ggplot2 требует R, а plotnine — Python? Отдельный исполняемый файл для визуализации удобнее:

  • Встраивать небольшой бинарник в другие инструменты проще, чем таскать с собой R или Python.
  • Меньший scope проще изолировать и защищать от запуска вредоносного кода — случайного или намеренного.

Оба пункта делают ggsql хорошим кандидатом на интеграцию с ИИ-ассистентами и code-based инструментами для отчётов, которые выполняют код в разных окружениях.

Отказ от интерпретируемого языка звучит как ограничение, но даёт выигрыш. Самое главное — жёсткая структура даёт выполнять весь пайплайн данных как один SQL-запрос на слой на бэкенде. То есть для bar-чарта на 10 миллиардов транзакций вы получаете с хранилища только количество для каждого бара, а не все 10 миллиардов строк. То же для boxplot и density-плотов. Это отличает ggsql от большинства инструментов, которые сначала материализуют все данные, потом считают на них, потом рисуют.

LLM и ggsql: код без R и Python-рантайма

LLM хорошо переводят естественный язык в SQL, и Posit уверены, что с ggsql будет так же. Свидетельство этому уже есть в querychat, где данные можно исследовать визуально через естественный язык — как раз через ggsql. А так как ggsql — более лёгкий и безопасный рантайм, чем R или Python, с ним спокойнее отправлять код-агентов в продакшен.

18 лет знаний о визуализации

18 лет разработки и поддержки ggplot2 — это 18 лет размышлений про синтаксис визуализации, сценарии использования и дизайн. Posit считают, что это даёт им экспертизу в теме. При этом не весь накопленный опыт можно вернуть в ggplot2: там есть решения, принятые много лет назад, которые нужно поддерживать или менять очень постепенно.

ggsql — чистый лист. Не только в смысле «строим с нуля», но и в смысле «нет сложившихся ожиданий к инструменту визуализации». Для разработчиков это даёт свободу — и, как надеются в Posit, пользователю это тоже чувствуется.

Планы: что будет дальше

Альфа-релиз — значит, работа далеко не закончена. Вот короткий список того, что хотят добавить:

  • Новый высокопроизводительный рендерер, написанный с нуля на Rust.
  • Инфраструктура тем.
  • Интерактивность.
  • Сквозной деплой-флоу от Posit Workbench/Positron до Connect.
  • Полноценный language server и форматтер для ggsql.
  • Поддержка геоданных.

Что это значит для ggplot2

Если вы пользователь ggplot2, возможно, вы прочли всё это со смесью страха и радости. Значит ли это, что Posit бросают ggplot2 ради новой игрушки? Нет. ggplot2 сейчас зрелый и стабильный, его продолжат поддерживать и развивать. И надеются, что ggsql сможет вернуть часть накопленного опыта обратно в ggplot2, подсказывая новые возможности.

FAQ

FAQ
1
Это замена ggplot2?

Нет. ggplot2 остаётся основным инструментом визуализации Posit для пользователей R; его развитие продолжается. ggsql адресован тем, кто работает в SQL и не хочет экспортировать данные в R или Python ради графика.

2
Нужно ли знать ggplot2 или R, чтобы работать с ggsql?

Нет. ggsql спроектирован как самостоятельный синтаксис: если вы умеете писать SELECT и WITH, вам хватит этого старта. Идеи грамматики графики (слой, маппинг, шкала) объясняются по мере знакомства с примерами — их не нужно учить отдельно. Знание ggplot2 помогает быстрее освоиться, но не требуется.

3
Какой бэкенд использует ggsql?

В анонсе показаны примеры с DuckDB. Архитектурно ggsql принимает любой SQL-бэкенд, который принимает ваш SQL до VISUALIZE; сама визуализация сворачивается в SQL-запросы к этому бэкенду — по одному на слой графика.

4
Можно ли использовать ggsql без R и Python?

Да — это одна из ключевых целей. ggsql задуман как отдельный небольшой исполняемый файл, который не требует R или Python для работы. Поддерживаются Quarto, Jupyter, Positron и VS Code как среды запуска.

5
Чем ggsql отличается от встроенных чартов BI-инструментов?

BI-инструменты обычно дают фиксированные типы графиков и слабую воспроизводимость. ggsql — декларативный code-based подход: любой график собирается из модульных слоёв, SCALE и LABEL, запрос можно версионировать и переиспользовать.

6
Где попробовать?

На ggsql.org есть секция Getting started с инструкциями по установке и туториалом, а также полная документация по всем возможностям.

Выводы

ggsql — попытка перенести 18 лет опыта ggplot2 на SQL-территорию и при этом снять привязку к рантайму R или Python. Для аналитика, который живёт в SQL, это шанс строить сложные визуализации, не выходя из запроса и не материализуя миллиарды строк ради bar-чарта. Для разработчика ИИ-ассистентов — повод ожидать, что LLM будут генерировать не только SQL, но и готовые визуализации прямо в нём.

ggsql — чистый лист. Не только в смысле «строим с нуля», но и в смысле окружения, в котором нет сложившихся ожиданий к инструменту визуализации. Это даёт свободу, и, мы надеемся, это чувствуется в том, как ggsql работает в руках.
Thomas Lin PedersenSoftware Engineer, Posit — мейнтейнер ggplot2 и автор ggsql

Как попробовать. На ggsql.org есть Getting Started с инструкцией по установке и первыми примерами. В Quarto и Jupyter ggsql подключается как отдельное ядро; в Positron и VS Code есть интеграция через расширение. DuckDB ставится отдельно, если у вас его ещё нет. Ограничений по географии для Posit Open Source нет — пакеты доступны через открытые репозитории.

Оригинал статьи: opensource.posit.co/blog/2026-04-20_ggsql_alpha_release. Обсуждение на Hacker News — news.ycombinator.com/item?id=47833558. Попробовать и прочитать документацию — на ggsql.org.