
2026/04/20 21:51
ggsql:SQL のためのグラフィックス・グラマー
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
ggsql は、構造化された可視化機能をアナリストやデータサイエンティストに提供する目的で、SQL 構文内に「グラフィックの文法」を直接実装したアルファバージョンを発表しました。別途 R や Python 環境を必要としないよう設計されたこの単一の実行可能ファイルアプリケーションは、ユーザーが特定の SQL クエリ節を用いてプロフェッショナルなチャートを作成することを可能にします。「VISUALIZE」節がクエリの開始を担当し(このキーワード以前には CTE や UNION をサポート)、「DRAW」節が可視化レイヤー(例:点、滑らか化する線、ヒストグラムなど)を構築し、ジッターなどの設定で微調整できます。「SCALE」節はデータ値を審美的な表現にマッピングし、「PLACE」と「LABEL」節は注釈およびテキストを担当します。標準的な SQL クエリが結果をテーブルとして実体化するのに対し、ggsql はデータを可視化エンジンに直接供給することでパイプライン効率を高めています。18 に及ぶ ggplot2 の経験を基盤としつつ R のレガシー制約を回避しており、Quarto、Jupyter ノートブック、Positron、VS Code などのプラットフォームへの埋め込みに最適化されています。今後のアップデートでは、高パフォーマンスな Rust バックエンドの採用、テーマリング、インタラクティブ機能、空間データのサポート、セキュアなサンドボックス環境内での強化された AI 統合が含まれる予定としています。
本文
本日、私たちは超大きな興奮を込めて、ggsql のアルファリリース(初期公開版)の発表を行います。名称からわかるように、ggsql は SQL の構文に基づいた「図像の文法」(grammar of graphics)の実装であり、SQL へのリッチで構造化された可視化サポートをもたらします。このツールは、Quarto、Jupyter ノートブック、Positron、Visual Studio Code などの環境ですぐに利用可能です。
本投稿では、われわれがこのツールの開発に至った背景にある動機について触れ、ご使用方法の豊富な例示を通じて、読者の方にも我々のような興奮をお感じいただけるよう努めます。
ggsql とお会いしましょう
なぜという議論に入る前に、いくつかの実例を用いて、ggsql が何であるかをまずご紹介します。
最初のプロット
可視化の「Hello World」となる散布図を作成するために、組み込みデータセット『penguins(ペンギン)』を使用してみましょう。
VISUALIZE bill_len AS x, bill_dep AS y FROM ggsql:penguins DRAW point
これでいかがでしょうか。確かに SQL という言語特有の冗長さはありますが、それは同時に「プロットコードを口頭でも発話し、その動作を理解できる」という利点でもあります。ここで起こっていることを行ごとに分解してみましょう:
指令で視覚的クエリを開始し、組み込みデータセット『penguins』から x と y のマッピングを提供します(x はVISUALIZE
カラムのデータに対応し、y はbill_len
カラムのデータに対応)。bill_dep- 上に定義したマッピングをデフォルトとして使用する「点レイヤ」を描画します。
これを基盤として、可視化を進めていくことができます:
VISUALIZE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins DRAW point
マッピングへの単一の変更によって、プロットに色分けされたカテゴリが追加されました。このようにプロットコードを段階的に進化させる能力は、「図像の文法」のもっとも大きな強みの一つです。ここではプリ定義されたプロットタイプはありません;結合可能(composable)なモジュール的なパーツを組み合わせて、追加し、削除するだけです。これをさらに強調するために、散布図に滑らかな回帰線を加えてみましょう:
VISUALIZE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins DRAW point DRAW smooth
点レイヤの上に新しい層(レイヤー)が追加されました。この層もまた、点レイヤーと同じマッピングを借用します。種(species)による色分けのため、滑らかな線は各々別に描かれ、3 種類ずつ表示されます。
これと同様の作業を続け、さらにマッピングを追加したり、レイヤを追加・切り替えたり、スケールの適用方法などを制御することで、無論単純なものであっても複雑なものであっても、最終的に必要なプロットに到達できます。上記の例では、データの収集が行われた 3 つの島における種の分布を見ることに興味を持つかもしれません:
VISUALIZE island AS x, species AS color FROM ggsql:penguins DRAW bar
全く異なる種類のプロットですが、前回のプロットのコードのうちどれだけ残されているかが確認できるでしょう。
完全な例
最初の数個のプロットをマスターした後では、次は完全な実例に移りましょう。これにはこれまで見なかった部分も含まれていますが、ご心配なく。以下に詳しく解説します(すでに紹介済みの部分も含みます)。この例は、TidyTuesday の Jack Davison 氏が作成した可視化の改変版です。
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
非常に多くのコードに見えますが、一方で一つの例を通じて最も重要な構文の側面を多くカバーできていることも事実です。
最上位レベルでは、このクエリには SQL クエリ部分と視覚化クエリという 2 つの部分があります。SQL クエリとは
VISUALIZE 句から先までのコードのことです。これは通常の SQL であり、バックエンドが受け入れるものは何でも使用できます(本ブログ記事では DuckDB バックエンドを使用しています)。クエリの結果は、通常想定されるようなテーブルとして返されるのではなく、可視化に直接入力されます。
本記事の目的が SQL を教えることではないため、SQL クエリ部分についてはさらに詳しく議論することはありません。ここでの主な要点は、「
VISUALIZE 句よりも前のすべては純粋な SQL であり、生成されたテーブルは自動的に可視化によって使用され、そこに作成されたテーブルや CTE(Common Table Expression)は後続の視覚化クエリで参照可能である」ということです。
最初の例でも見たように、SQL クエリ部分は必須ではありません。すでにプロット用に適切な形状になっているデータがある場合は、それをスキップして
VISUALIZE 句内で直接ソースを指定することもできます:
VISUALIZE year_of_selection AS x, year_of_mission AS y FROM 'astronauts.parquet'
さて、次に視覚化クエリ(
VISUALIZE から先までの部分)を見てみましょう。「VISUALIZE は SQL クエリの終了と、視覚化クエリの開始を示します(英国式の綴りを好む方々は VISUALISE を使用してください)。これらは単独でも機能し、ここでは後続のすべてのレイヤーをデフォルトにする 1 つ以上のマッピングも持っています。マッピングとは、データを抽象的な視覚特性に関連付けるために用いるものです。マッピングは、図像の文法における「美学(aesthetics)」と呼ばれる視覚的特性へカラムをエイリアス付与する SELECT のようなものです。上記の可視化では、「age カラムには x 軸に沿った値(位置)を使用し」、「category カラムには実体(entity)の色付けに使用する値を使用する」と定義しました。しかし、それをどのように描画するかについてはまだ何も指定していません。
VISUALIZE クエリの後には DRAW 句が続きます。「DRAW は視覚化にレイヤーを追加する方法です」ggsql には多数の異なるレイヤertype が用意されています。一部は直感的で、例えば散布図を描くための point です。一部はより複雑で、ここでは使用されているヒストグラムのように、ビンごとのカウントなどの導出統計量を計算する必要があるものもあります。可視化は何個かのレイヤーを持つことができ、定義された順序でレンダリングされます。「DRAW」には姉妹句である「PLACE」があります。これは注釈(annotation)に使用され、「DRAW」のように動作しますが、テーブルからデータを得るのではなく、代わりに文字列などのリテラル値を受け取ります。
したがって、上記の可視化には 3 つのレイヤーが含まれています:
- テーブルからのデータを表すヒストグラム層
- カテゴリごとの事前に計算された平均値を表示するルール(rule)注釈層
- 可視化に文脈を追加するテキスト注釈層
ここで留意すべき点は、レイヤが単一のグラフィカルエンティティに対応するわけではないということです。上記のテキストレイヤーのように、各レイヤーはその種類の複数の独立したエンティティを描画できます。したがって、例えば 3 つのカテゴリ用のラインプロットを描画するために「3 つのラインレイヤ」を用意する必要はありません。
DRAW と PLACE 句の後に SCALE 句が続きます。この句は、データ値を実際の美学(視覚特性)に意味を持つ値に変換する方法を制御します。われわれの場合、category カラムには"Age at mission"や"Age at selection"という文字列が含まれており、これ自体が色値に直結しません。「SCALE fill TO accent」という句は、マッピングされた「fill」の値を実際の色の値に変換する際に、「accent」というカラーパレットを使用することを指示します。スケールはさらに多くのことに使用でき、例えば連続データのトランスフォーメーションの適用、ブーケポイント(割れ目)の定義、特定のスケールタイプ(順序尺度やビンされたものなど)の設定などに使用できます。
視覚化クエリの最後の句は
LABEL です。これにより、タイトル、サブタイトル、軸、凡例などのテキストレーベルを追加または修飾することができます。
らしい戻ってみる
さっぱり理解できず複雑な内容でした。しかし、この一連全体には 2 つの非常に銀色(silvery)の縁取りがあります:
- これで構文の最も重要な側面を理解しました(もちろん他にもありますが、それらは成長の中で学べます)。
- 多くの視覚化クエリは上記よりもずっとシンプルになります。
すでに紹介した短い視覚化クエリの例もありますが、引き続き性別によって整理された宇宙飛行士の誕生年の箱ひげ図の例を見てみましょう:
VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet' DRAW boxplot
これは最後のプロットコードよりもはるかに短いです。しかし、異なる可視化システムから来た方は「過度に冗長」とすら感じるかもしれません(例えば、
boxplot(astronauts.sex, astronauts.year_of_birth) のようなものと比較した場合)。確かにコード量は多いですが、それがより構造化され、結合可能で、自己記述的であるという利点があります。これらの特性はすべて「図像の文法」の流れを汲むものであり、これによりあなた自身だけでなく、将来の大規模言語モデル(LLM)コーディングパートナーも、作成可能なすべての種類のプロットの動作を理解しやすくします。R エコシステムで 18 ュ年間支配的な ggplot2(これらの機能を共有しています)がその証です。
例として、上記のプロットを代わりにジッターされた散布図として同じ関係を示すように変更してみましょう:
VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet' DRAW point SETTING position => 'jitter'
あるいは、ジッターがデータの分布に従うため、バイオリンプロットとしても機能するかもしれません:
VISUALIZE sex AS x, year_of_birth AS y FROM 'astronauts.parquet' DRAW point SETTING position => 'jitter', distribution => 'density'
ご覧の通り、構文と結合可能な性質により、可視化のイテレーション(反復的な改善や変異)が非常にエルゴノミカル(使い勝手が良い)となり、探索的分析および可視化設計において極めて貴重な機能となります。
なぜ ggsql なのか?
可从零開始编写一个新的可视化库是一项艰巨的任务,你可能会问为什么我们要再次这样做。部分原因在于:
- 我们希望接触并帮助那些主要使用 SQL 的数据分析师和数据科学家
- SQL 和图像文法(Grammar of Graphics)的结合极其完美
- 我们希望创建一个强大的代码为基础的可视化工具,而无需整个编程语言(如 R 或 Python)
- LLM(大语言模型)非常擅长处理 SQL,并且这也提供了一种新的数据可视化创作界面
- 我们从 ggplot2 长达 18 年的开发中学到了很多,我们非常兴奋地将这些经验应用到全新的画布上
下面让我们逐一讨论。
嗨,SQL 用户!
虽然最初是 R,后来是 Python 捕获了所有数据科学革命的关注,但 SQL 作为可靠而强大的幕后工作马一直在运行。许多人处理数据时仅或主要使用 SQL。在我们看来,他们可视化数据的选项通常不是最优的:
- 导出数据并使用 R 或 Python(这可能不在他们的舒适区)
- 使用基于 GUI 的商业智能工具,但这些工具对可重复性的支持很差
- 依赖少数可以直接在查询中创建可视化的工具之一,这些工具我们认为还不够强大或不符合人体工学
我们在设计 ggsql 时的目标是让语法能立即被 SQL 用户理解,并利用他们对组合性、声明性子句的预期。
除了提供更好的数据可视化方式外,ggsql 也是邀请 SQL 用户进入我们丰富的基于代码的报告生成和共享生态系统的途径,该生态系统建立在 Quarto 之上。
声明式的整理,声明式的可视化
如果您阅读本文时没有 SQL 的先验知识,这里是一个非常简短的回顾:SQL 是一种用于操作存储在单一或多个表中的关系数据的领域特定语言。其语法基于关系代数的概念,这是一种思考数据操纵操作的结构化方式。语义定义了一组声明性而非函数性的模块操作,使用户能够使用一组定义良好的操作组合出非常强大且定制的操纵功能。
如果您阅读本文时没有图像文法的先验知识,这里也是一个非常简短的回顾:图像文法是将数据可视化的概念分解为模块部件的理论解构。虽然纯理论性质,但像 ggplot2 这样的工具已在实践中实现了这一理念。语义定义了一组声明性而非函数性的模块操作,使用户能够使用一组定义良好的操作组合出非常强大且定制的可视化效果。
综上所述,从这个略带夸张的概述中可以看出,SQL 和图像文法在其各自领域的方法论上有很多共同点。结合在一起,它们可以为从原始数据到最终可视化的完整管道提供非常强大且自然的解决方案。
无需运行时,没问题
为什么 ggplot2 和 plotnine 分别需要安装 R 和 Python?一个单一、专注的可执行文件来处理数据可视化有明显的优势:
- 将小型可执行文件嵌入到其他工具中,远比捆绑 R/Python(或要求它们已安装)容易得多
- 较小的作用域使得更容易进行沙箱隔离,防止恶意代码的执行(无论是故意还是错误)
上述两点都使得 ggsql 成为集成到 AI 代理(帮助您进行数据分析)或基于代码的报告工具中的更具吸引力的选择,这些工具可能在不同的环境中执行代码。
您可能认为我们已经不得不吞下一些苦药片,即放弃了解释型语言,但它也给了我们很多。最重要的是,这种严格的结构意味着我们可以将整个数据流水线作为每层一个 SQL 查询在后台执行。这意味着,如果您想创建 100 亿笔交易的条形图,您只需从数据仓库中获取每个条的计数值,而不是获取 100 亿行数据。对于更复杂的图层类型(如箱线图和密度图)也是如此。这与大多数可视化工具形成鲜明对比:它们必须首先将完整数据实例化,然后对其进行必要的计算,最后才能绘图。
SELECT pod_door FROM bay WHERE closed
LLM 在将自然语言转换为 SQL 方面已被证明非常有效
LLM 在将自然语言转换为 SQL 方面已被证明非常有效,我们相信它们也能同样有效地处理 ggsql。我们已经在 querychat 中看到了这种证据,现在您可以使用自然语言通过 ggsql 来可视地探索数据。而且,由于 ggsql 比 R 或 Python 更安全、轻量级,您可以更有信心地将代码代理部署到生产环境中。
我们早已超出我们的年龄而变得智慧
ggplot2 开发和维护长达 18 年,也意味着有 18 年时间思考数据可视化的语法、使用和设计。虽然我们无意自夸,但我们确实相信这使我们在该主题上获得了一些专业知识。然而,并非所有这些知识都可以全部回馈给 ggplot2。有许多多年前做出的决定和期望,我们必须遵守,或者至少只能非常缓慢地挑战(我们偶尔也会这样做)。
ggsql 是一张白纸。不仅因为我们是从头开始构建它,还因为它是为一个没有任何既定可视化工具期望的环境而构建的。我无法强调这一点带来的解放感和活力有多么强烈,并且我确信这一点在 ggsql 给用户的感觉中体现了出来。
未来
我们即将结束这次相当长的发布——感谢您的陪伴。在第一行我们就称这是一个 alpha 版本(初期公开版),这意味着我们还没有完成。为了让您对未来感到像您现在对 ggsql 的状态一样兴奋,这里有一个我们要添加的功能的非穷尽列表:
- 全新的基于 Rust 从头编写的高性能输出器
- 主题基础设施
- 交互性
- 从 Posit Workbench/Positron 到 Connect 的端到端部署流程
- 完整的 ggsql 语言服务器和代码格式化器
- 对空间数据的支持
这对 ggplot2 开发意味着什么
如果您是当前的 ggplot2 用户,您可能带着恐惧和兴奋(或者也许只是其中一种情绪)读完这篇文章。这是否意味着我们要在 Posit 放弃 ggplot2,专注于我们新的闪亮玩具?绝非如此!此时 ggplot2 已经非常成熟和稳定,但我们将继续支持和扩展它。我们也希望 ggsql 能够通过向 ggplot2 提供新功能来回报从 ggplot2 开发中积累的所有经验。
想了解更多吗?
如果您迫不及待想要了解更多关于 ggsql 的信息并开始使用它,可以前往 ggsql 网站上的“入门”部分获取安装说明和教程,或者直接跳转到文档以发现 ggsql 的所有功能。我们期待您尝试后与我们分享您的使用体验!