04:28. 昨日は YT でぼんやり時間を溶かさず就寝できた。

Codeforces

04:55. 耳垢掃除薬の適用に時間がかかってしまった・・・

Kattis に挫けたので今日からは Codeforces. なお Topcoder も見たけどまったく使い方がわからなかった。10 年前くらいにいちど使ったことあるはずなのだが・・・。Codeforces は解答 (Tutorial) もあるし新しい Kotlin もサポートしてるしで、そこそこ期待している。Scala は 2.x はあるけど 3 はなくて、ほんと流行ってねーな Scala 3. まあ自分は Kotlin でいいです。

Judge Error

Hacker News でカルマを稼ぐ

一年少し前くらいから、気晴らしで Hacker News でカルマを稼ごうと思い立ち活動を始め、昨日めでたくカルマが 1000 になった。

これはインターネットで時間を溶かしている証左でしかないが、ではどのくらい溶かしているのかというと、活動は主にコメントで、270 コメントくらいしたらしい。二日に一回よりちょっと多いくらいのペース。例のごとく HN の公開データセットで計算してみると、これはコメントをしたユーザ全体の上位 2.5% のコメント数らしい。つまり、かなりヒマをつぶしている。しかも HN とか 2011 年くらいからあって自分は 2021 参加の新参者なわけだから、それにしてはコメントしすぎである。なお 20k / 800k みたいな規模感です。

コメント一つあたりの平均カルマはだいたい 3-4 くらい。つまり特にウィットの効いたコメントができているわけではない。じっさい単一コメントだと 20-30 くらいが限度。これはコメントが数十個程度のマイナーなスレッドだと一番上にくるようなイメージ。Mediocre ですね。はい。気の利いたコメントができる人なら同コメント数で 10x くらいカルマを稼げそうだが、まあいいです。当初は HN でカルマを稼ぐコツについて書きたいと思っていたが、こんな mediocre じゃ書くこともないね。コメント以外だと Ask HN も一回やったことがある。リンクの投稿は数回。

書いたコメントに返信がついたりするとインターネットしてる感じがして割とうれしい。こういう感じ、久しく味わってなかったなと思う。言語バリアのおかげで emotional burden が若干低めなので、それもよいです。時間のムダであることに変わりはないけれど。

Kattis

LeetCode に金を払い続けるのも癪に思えてきたので他を探したら Kattis というのがあったので冷やかす。

ただテストデータは見えないので、間違えたときに何が間違ってるかはわからないのだね。これだとバグがあるときに詰んでしまう。むかし Topcoder 試したときはそれがフラストレーションで続かったなかったのだよなあ。(スコアを競い合う)競技プログラミングの性質と答えの開示は相反するので仕方ないけど、テストケースが見えないの直しようがなくね?まあ甘えなのだろうけど、こういうスタイルだと無限に時間が解けてしまうか、ギブアップして何もわからないまま終了にするしかなくて、一日 30 分くらいだけパズル脳を訓練したい自分とは相性が悪い。ヒマな人向けで残念。

もう一問くらいやるか。

Greatest common divisor

04:38. さて Leet をやって、今日は家の用事を片付けなくてはなりません。

  • Mirror Reflection – LeetCode
    • 日替わり問題くらい解答用意しとけや・・・と、gray out された solution タブを見て思う。まあやります。
    • 本質的には GCD を計算しなさいねという問題だったので、Wikipedia をみて Euclidean algorithm を復習したのち解答。そういやそんなアルゴリズムだったねー GCD くらい標準ライブラリでできてもバチは当たらないとおもうけど(パズル脳)・・・。それにしてもこのアルゴリズムが必ず停止するのって直感的には不思議。
    • gcd はともかく解との関係を整理するのにやたら時間がかかってしまった。Arithmetic の苦手さよ。でも幾何的な雰囲気ある問題ってパズルぽくていいよね。
  • あとはおうちの調べものがあるのでここまで。

読譜活動 – ZetaSQL – ResolveQuery

子が日本語補習校なので土曜は謎の時間があります。土曜まで学校とか気の毒だが、それはさておき読んでくぞ。

  • resolver_stmt.cc: Zeta, Create XXX が異常にたくさんあり、エンタープライズ製品感強し。CREATE MODEL ってなんやねん・・・。(BQ の機能らしい)
  • そういうのは置いといて SELECT 見てくべし。というわけで resolver_query.cc … ギャー 8000 行! きびしい。
  • なお ResolveQuery() の出力は ResolvedScan。こうした resolved AST は スクリプトで生成しているらしい。こいつがまた 8000 行。もうちょっとなんとかならんのかロジックとデータを分離するとかさ (GYP につながる道)。superclass は ResolvedNode. 直列化をサポートしている。データベースは分散システムだからねえ。AST をどっかに送りたいこともあるのでしょう。Catalog とかも分散しないといけないので AST だけ直列化できても不十分だが、そういう usecase は興味深い。AST という木構造をどうやって proto に書いているのかは興味があるが、あとで。
  • ところでドキュメンテーションが割と充実してるね。ただユーザ向けのリファレンスと開発者向けのガイドが混ざってるのが厳しい。分けてもらえんもんかのう・・・。
  • コードを見ていて気付いたが、SELECT はネストできるのか。つまり・・・
$ bazel-bin/zetasql/tools/execute_query/execute_query "select (select 1 + 1) + 1"
+---+
|   |
+---+
| 3 |
+---+

Resolved AST をダンプしてみよう。

$ bazel-bin/zetasql/tools/execute_query/execute_query --mode=resolve "select (select 1 + 1) + 1"
QueryStmt
+-output_column_list=
| +-$query.$col1#2 AS `$col1` [INT64]
+-query=
  +-ProjectScan
    +-column_list=[$query.$col1#2]
    +-expr_list=
    | +-$col1#2 :=
    |   +-FunctionCall(ZetaSQL:$add(INT64, INT64) -> INT64)
    |     +-SubqueryExpr
    |     | +-type=INT64
    |     | +-subquery_type=SCALAR
    |     | +-subquery=
    |     |   +-ProjectScan
    |     |     +-column_list=[$expr_subquery.$col1#1]
    |     |     +-expr_list=
    |     |     | +-$col1#1 :=
    |     |     |   +-FunctionCall(ZetaSQL:$add(INT64, INT64) -> INT64)
    |     |     |     +-Literal(type=INT64, value=1)
    |     |     |     +-Literal(type=INT64, value=1)
    |     |     +-input_scan=
    |     |       +-SingleRowScan
    |     +-Literal(type=INT64, value=1)
    +-input_scan=
      +-SingleRowScan

Subquery が “SCALAR” であるという事実は静的に判定されている。複数の row を返すようなケースではどう resolve されるのだろうか・・・。なんとかテーブルをつっこむ必要があるな。この BUILD ファイル に CSV を食わせる方法がひっそり書いてあるので試すと動いた(が、コピペでは動かなかった。あとで bug をファイルすべし。)

$ bazel-bin/zetasql/tools/execute_query/execute_query  --table_spec="data=csv:$(pwd)/sample.csv" "select * from data"
+---+-----+----+
| a | b   | c  |
+---+-----+----+
| 5 | 1.2 | r1 |
| 6 | 1.5 | r2 |
| 7 | 3.3 | r3 |
+---+-----+----+

さて query のネストをしてみましょう。

$ bazel-bin/zetasql/tools/execute_query/execute_query  --table_spec="data=csv:$(pwd)/sample.csv" "select (select CAST(a AS INT64) from data) + 1"
ERROR: OUT_OF_RANGE: More than one element [type.googleapis.com/zetasql.execute_query.ParserErrorContext='\n.select (select CAST(a AS INT64) from data) + 1']

EXPLAIN すると…

morrita@noisia:~/src/zetasql$ bazel-bin/zetasql/tools/execute_query/execute_query  --table_spec="data=csv:$(pwd)/sample.csv" --mode=explain "select (select CAST(a AS INT64) from data) + 1"
RootOp(
+-input: ComputeOp(
  +-map: {
  | +-$col1.2 := Add(SingleValueExpr(
  |   +-value: $col1,
  |   +-input: ComputeOp(
  |     +-map: {
  |     | +-$col1 := Cast($a, ConstExpr(false))},
  |     +-input: EvaluatorTableScanOp(
  |       +-a#0
  |       +-b#1
  |       +-c#2
  |       +-table: data))), ConstExpr(1))},
  +-input: EnumerateOp(ConstExpr(1))))

“ParserErrorContext” といっていたが、EXPLAIN はできている。つまり実行時エラーである。実際 subquery を LIMIT 1 すると成功する。というわけで実行結果が vector か scalar かというのは型の一部ではない、と言えそう。

一方 string と int を + しようとすると・・・

$ bazel-bin/zetasql/tools/execute_query/execute_query  --mode=resolve --table_spec="data=csv:$(pwd)/sample.csv" "select (select a from data LIMIT 1) + 1"
ERROR: INVALID_ARGUMENT: No matching signature for operator + for argument types: STRING, INT64. Supported signatures: INT64 + INT64; UINT64 + UINT64; DOUBLE + DOUBLE; NUMERIC + NUMERIC; BIGNUMERIC + BIGNUMERIC; DATE + INT64; INT64 + DATE; TIMESTAMP + INTERVAL; INTERVAL + TIMESTAMP; DATE + INTERVAL; INTERVAL + DATE; DATETIME + INTERVAL; INTERVAL + DATETIME; INTERVAL + INTERVAL [at 1:8] [type.googleapis.com/zetasql.execute_query.ParserErrorContext='\n\'select (select a from data LIMIT 1) + 1']

Resolve に失敗する。というわけで + の評価には型が存在する as expected. なお parse には成功する。

$ bazel-bin/zetasql/tools/execute_query/execute_query  --mode=parse --table_spec="data=csv:$(pwd)/sample.csv" "select (select a from data LIMIT 1) + 1"
QueryStatement [0-39]
  Query [0-39]
    Select [0-39]
      SelectList [7-39]
        SelectColumn [7-39]
          BinaryExpression(+) [7-39]
            ExpressionSubquery [7-35]
              Query [8-34]
                Select [8-26]
                  SelectList [15-16]
                    SelectColumn [15-16]
                      PathExpression [15-16]
                        Identifier(a) [15-16]
                  FromClause [17-26]
                    TablePathExpression [22-26]
                      PathExpression [22-26]
                        Identifier(data) [22-26]
                LimitOffset [27-34]
                  IntLiteral(1) [33-34]
            IntLiteral(1) [38-39]
  • さて本題に戻り、末端の SELECT を評価するのは ResolveSelect(). これは・・・複雑。だがコメントが丁寧に書いてあって大企業えらいですね。こういうコメント見ると、コードで表現するのが常に正しいのか疑問になってしまうよな。理想的に正しいのはわかるが、現実として。
  • なお Duck も select の resolve はなかなかカオスだったので、そういうものなのでしょう。

読譜活動 – ZetaSQL – Resolver

昨晩遅かったので朝は走るだけ、と思ったら雨。コード読むかな。

  • execute_query 全体的に大げさなコードでいまいちである。
  • execute_query_tool.cc : ExecuteQuery() – が本題だと思われる。
  • まず ParseExpession で ASTNode を作ります
  • … と思ったが AnalyzeStatement()ResolvedNode を作ります、だな。なおこれを呼ぶには Catalog と type factory が必要。AnalyzeStatement() は free function で、謎のコンテクストとかは必要ない。クリーンでえらいね。AnalyzerOptions には arena (!) やら string id pool (interned string?) やら、それなりに context 的なオブジェクトも突っ込まれているらしいが。
  • で内部では結局 ParseExpression なり ParseStatement なりを呼んで、その AST を analyze するらしい。Parser はあとで詳しく見るとして、この AST の段階では catalog とかいらない。つまり型の解決とかは analyze の仕事らしい。ZetaSQL, SQL を statically typed ぽく扱っている節があるのでそれをどうやってるのがが気になるところ。
  • で、Analaysis は Resolver クラスがエントリポイントです。resolver.h は 4000 行くらいあって一瞬ギョっとするが、Android で鍛えた我々は 1 万行以下のファイルではビビらないのである。というかこのての parser とか analyzer とか、だいたいデカくなりがち。型単位で再帰的に解決したりするので。これを visitor とかで小さいクラスに分ければ読みやすくなるというものでもない。なお .cc ファイルは resolver_*.cc に分割されている。これ duck も似たような構成だったな。
  • 複雑さという意味で Resolver の private fields (状態) を眺めると、全然ない。つまりクラスにはなっているが概ね side-effect-free ぽく書かれていることが期待できる。
  • ResolveStatement の signature はこんなかんじ。(この改行をなんとか殺さねばならぬ・・・)
  // Resolve a parsed ASTStatement to a ResolvedStatement.
  // This fails if the statement is not of a type accepted by
  // LanguageOptions.SupportsStatementKind().
  // <sql> contains the text at which the ASTStatement points.
  absl::Status ResolveStatement(
      absl::string_view sql, const ASTStatement* statement,
      std::unique_ptr<const ResolvedStatement>* output);
  • つまり ASTStatement を ResolvedStatement に map している。他もまあ似たような構成になっていることが予想される。常識的な作りでよい。なお Duck もこんなんだったな。彼らの “resolve” は割と雑だったが、Zeta はどうでしょうか。
  • ところで Zeta には LanguageOptions というのがあって、これで言語機能をかなり細かく制御できる。statement の種類を絞ったりとか。これが世界(社内)を統べる SQL の力だが、同時に実装は複雑になるね。

といったところで時間ぎれ。execute_query がいまいちだったので心配していたが、ライブラリ本体はなかなかクリーンぽくて安心。

次回以降への疑問:

  • Query の解決。
  • Parser の実装はどうなってるのか。
  • Catalog はどうやって作るのか。Catalog への副作用は発行できるのか。つまりDDL はどうハンドルされるのか。

読譜活動 – ZetaSQL

ちょっとばかし ZetaSQL のコードを読んでみるターン。DuckDB しか知らないと Duck 活動してもいまいち自分の SQL 力が高まらないなということで、ガチ勢の SQL パーサを読んでみる。ZetaSQL は Google 社内の SQL 方言をすべて駆逐した本気の二周目 SQL 実装である。これを読めば SQL への理解も高まるというものでしょう。オープンソースへのコードダンプがどのくらいちゃんとしているのかは怪しいが、それは見ればわかるでしょうということで。

  • まずビルドしてみるべく Bazel のインストールからスタート。
  • JDK もいるらしいので apt-get install openjdk-17-jdk
  • ビルドはじまった。WSL2 がんばってくれ・・・
  • ビルドをまちつつコードサイズを調べると・・・
$ find zetasql/ -type f | xargs wc
  ...
  852658  2684718 30878589 total

$ find zetasql/ -type f -name "*.test" | xargs wc
  ...
  408165  1213844 13169468 total

$ find zetasql/ -type f -name "*_test.cc" | xargs wc
 ...
  100019  276858 4024329 total

  • というわけでテストなしで 300k-400k くらい。パーサだけなのに DuckDB よりでかいんじゃないか大企業・・・。なお Java binding があるが、それは数えていない。
  • Python がないといってビルドが失敗している。そして pyenv が入っていない。やれやれ・・・そして Python 3.8+ がサポートされていない!(こんな感じの問題っぽい)ここで breaking change をつっこんでくる Python もどうかと思うが、一体社内の Python バージョンいくつなんだろうな気にしたこともなかったが・・・。
  • ビルドを待ちつつコードで読むか。
  • サンプルを見ると zetasql/public/analyzer.h が入口なのかな。他にもいっぱいファイルあるけど、”Analyzer Famework” を名乗っているので、この AnalyzerOutput に必要なものは全部入っているのかもしれない。しかしもうちょっと E2E なサンプルないかな。
  • と README を読むと execute_query というのがあるらしい。こいつを理解するのがちょうどよい starting point かもしれない。
  • Google C++ はなんか特殊だよな良くも悪くも。新卒とかで入ってきて C++ の、よりによってこんな特殊な dialect をやらされる若者とかちょっと気の毒な気もするが、クラウドとかだと G style の C++ も一定程度は知名度あるのだろうか。たとえば Envoy は Bazel でビルドされる C++ だが、いまちらっと見た感じここまでのヤバさは感じない。ABSL が厳しいのかもしれない。
  • さて Evaluator というのがあって、実際に式や文を評価でいるらしい。しかしこんな実行のコアの部分をフレームワークに握られるとイヤそうだが、どうなのかね。商用製品では別のレイヤでインテグレートしており、これはカジュアルユーザ(とは?)向けなのかもしれないけれど。
  • などといいつつビルドがまったく終わらないこのヤバさ。Duck よりでかいのは間違いない。時間切れにつき今日はここまで。

入門活動 – D3 #2

04:32. 目が覚めてダラダラインターネットして、コーヒーは今日はやめといて、そろそろやってくかな。

  • Learn D3: Scales / D3 / Observable
  • Observable notebook, すべての cell が reactive… というか “observable” なのか。Linear に読んでいくのに向いてない・・・。
  • observablehq/htl: Hypertext Literal
  • 突然 JS の Literal を使って生の SVG を書き始めた・・・D3 って jQuery みたいに SVG 作るものじゃなかったの・・・。しかもリテラルと式展開がネストしまくりで認知負荷高すぎの可読性ゼロ。正気とは思えない・・・。
htl.html`<svg viewBox="0 0 ${width} ${height}" style="max-width: ${width}px; font: 10px sans-serif;">
  <g fill="steelblue">
    ${fruits.map(d => htl.svg`<rect y="${y(d.name)}" x="${x(0)}" width="${x(d.count) - x(0)}" height="${y.bandwidth()}"></rect>`)}
  </g>
  <g fill="white" text-anchor="end" transform="translate(-6,${y.bandwidth() / 2})">
    ${fruits.map(d => htl.svg`<text y="${y(d.name)}" x="${x(d.count)}" dy="0.35em">${d.count}</text>`)}
  </g>
  ${d3.select(htl.svg`<g transform="translate(0,${margin.top})">`)
    .call(d3.axisTop(x))
    .call(g => g.select(".domain").remove())
    .node()}
  ${d3.select(htl.svg`<g transform="translate(${margin.left},0)">`)
    .call(d3.axisLeft(y))
    .call(g => g.select(".domain").remove())
    .node()}
</svg>`

はー・・・。感想:

  • 自分の JS 力が低いのでこまごまとしたところで戸惑いがある。
  • Observable はねーわ。これなしのプレインな D3 を触れるようにしないといけない。つまりフロントエンド基礎知識が必要。
  • D3 やたらたくさん機能があるので、ぜんぜん把握できない。サンプルを写経するなり、なんらかのデータを実際に可視化するなりが必要。

Python や R で EDA するとは違って D3 の可視化はウェブフロントエンドのニッチなのだろうな。たとえばデータサイエンティスト連れてきてほらこれで可視化しろよ、とかいってもできるとは思えない。

D3 の可視化は誰かが何らかの発見をして結論を出した後、その発見・結論を示せる JSON とかを事前に用意しておいて、そいつをかっこよく表示してあげるというもの。インタラクティビティも作者の意図を読者に伝えるためのギミック。

仮に D3 を EDA に使おうと思ったらデータソースをつなぎこむ必要があるので、そういうシステムを作る必要がある。大仕事。(Observable はそういうのを一定程度やってくれるっぽいが。)

自分には Colab で EDA しているときに Altair に足りない機能を D3 で補いたい期待があったが、それは難しそうに見える。できなくはないだろうけど・・・。もう一つの期待は社内 dashboard のしょぼさをドメイン固有なフロントエンドを用意して補う路線で、そっちのほうが(自分のフロントエンド力の無さを差し引けば)現実的かな。


いずれにせよ次にやるべきことは D3 をつかって E2E でなんらかのウェブアプリなりサイトなりを作ることだろうね。あまりアイデアがないなあ。保留しつつそのうち考えます。

誤読活動 – A layered grammar of graphics

A layered grammar of graphics

というわけで ggplot2 論文。これは…素晴らしいね。本家 GOG で曖昧だった部分をすべて明らかにしたのみならず(たとえば transformation のよくわからなかった部分は丁寧に解説されている)、整理しなおし拡張している。そして可視化の best practice のようなものにも言及している (ex. “In practice, many plots have (at least) three layers: the data, context for the data, and a statistical summary of the data.”)。コードもある。

一方、当然なら本家 GOG を参照しているのであれを読んでいないと割と意味不明ではある。そういう意味で GOG は Hadley のこの論文を読むための税金だったのだと思えば許せる。

そして読んでいて気付いたが、ggplot2 にあるのに Altair にない機能が普通にあるね。Contour とかないじゃん。これ超欲しいんですけど。

これに限らず、Hadley の可視化に関する知見を学ぶためにこの人の書いた本を読むのは意味がある気がする。

心の積読にしておこう。

さて、これで星空日記から始まった可視化入門の旅は終わった。次にやることを考えないとな。まあ dashboard の本は読むとして、あれだけだと若干退屈なのでもうちょっと他にないか考えようではないか。イメージとしては dashboard の本は私用 laptop にアクセスできない会社の昼休みとかで読み、家ではもうちょっと手を動かす感じにできないかなあ。まあ無理に手を動かさなくてもいいんだけど、画面でないとできない活動、同じ読むでもコード読みとか、そういうかんじの何かをやりたい。Notion にでも書き出して考えるべし。

執筆活動 – m.g.i

Message Passing 書き終わり。そのほかお手紙に返事など。


Windows には最近は scoop という便利インストーラがあると教わり入れてみる。(参考: MacOS ユーザが WSL では無い Windows のコンソール環境を整える – A Day in the Life)

お、いいじゃんと勢い余って duckdb を Windows native でビルドしようとしてみるが、なんかいろいろ足りず挫折。また今度・・・。そして Windows ネイティブ開発しようとするとダウンロードサイズがでかい。つぎ laptop 買うときはでかめの SSD が欲しいかもしれないなあ。

参考リンク

文章活動、家庭活動

さて家賃を払わねばならぬ・・・そういえば引っ越して一年たったけど家賃更新なかったな。COVID の影響で禁止されているのだろうか。軽く探した感じ何も見つからなかったが。そういえば東京で一人暮らししていた 10 年間くらい、一度も家賃を引き上げられたことなかったな。今思えばすごい話だね。

銀行ついでに総資産を冷やかすと・・・減ってるね。そういえば株価下がってるというニュースを見た気がする。自国で百万人死んでも株価は上がり続けるのに、遠いユーラシアで戦争になると下がるの、資本主義のろくでもなさを突き付けられる感。

家計簿振り分け。ためなければ一瞬であります。

お手紙返事活動。

さて Message Passing のターンが来たので書くぞ。

昼間コーヒー飲んだせいか気が付いたら 23 時。今日はここまで。

雑用活動

お手紙活動に返事がきて、M1 Mac は Docker 動くしいいですよ、とのこと。ふーんとおもって適当にぐぐると、Docker Mac は仮想化のデフォルトが QEMU だという Reddit の発言を見かける。SO も。マイクロサービシズ!みたいな仕事は開発環境含め全部 Docker に入れてしまえば Mac だろうがなんだろうが好きなのを使えばよいということなのかねえ。

しかしこの話を書いていて WSL2 は Android Studio を使えない(限りなく無理) なことに気がついてしまった。うっかり Bazel とかを使おうとした日には積んでしまうな。Mac でも同程度にダメな予感もするが・・・。

IntelliJ なら最近は JetBrain Gateway というのがあって VSCode Remote 的に JetBrain 製品を使えるようになるっぽいが、Android Studio は当然のように未対応。これが動くとハッピーなのだけどねえ。そのうち対応してくんないかな。


来週の grocery 注文作業。子が生まれる前は一週間のメニューを考えてそれに合わせて買うとかやってたなあ。今は適当に買ってあるものを作るようになったが、適当に作るスキルの高まりにより割と困っていない。Imperfect Foods はイマイチなところもあるが、全体としては納得のできるサービスといえる。

家計簿。しかし前回から transaction が一件しかない。インポートが遅れてるな。

珍しく弟から電話。雑談。長男が中学受験だよ、など。自分の日本の友達でも子が中学受験とか言ってたし、昔と比べ一般化してるのだろうか。自分の卒業した都立高校も少しまえから中高一貫校になったという。そこには知らない日本がある。

少し前、自分の子に見せようと昔の日本の様子の動画(映画の切り貼り)を見たら不思議な気分になった。人々の恰好は古いが、街並みは案外変わっていない、というと誇張だけれど、多くが共通している気がする。しかし自分の脳内日本映像の解像度もだいぶ荒く、ただしく比較できない。

明日は朝から水族館にいくのでさっさと起きて弁当を作らねばならぬ。寝るべし。

誤読活動 – Polaris: a system for query, analysis, and visualization of multidimensional relational databases

Stolte: Polaris: A system for query, analysis, and… – Google Scholar

久々に出社し、タダで使えるプリンタがあるのを思い出したので星空日記で積み残していた Tableau の元となった論文を読む。

  • RDB に入っているデータを引っこ抜いてチャートを描く GUI を作りましたよ。Grammar of Graphics にインスパイヤされた可視化を GUI でチョイチョイと作れますよ。指定された可視化仕様に基づき SQL をつくって RDB から引っこ抜いてきますよ。
  • という内容で、完成されている。Tableau… はさわったことないけど社内のダッシュボードツール(Data Studio を武骨にしたようなもの)はこれをしょぼくしたものという風情。2002 年でこの完成度。そりゃ Tableau 流行るわけだわ。
  • データや代数のモデルを RDB/SQL に寄せてあるのが GoG との違いだと書いてあるが、20 年後に振り返ると成功している。もちろん ggplot2 路線にはそっちなりの良さもあるんだけど、GUI で画面を作るに際して UI の操作を通じて結果の可視化を軸に SQL を組み立てるアイデアがエレガントかつ正しいバランスをヒットしていて見事。
  • このあと WU とかから出てきた研究でここまで「やるな!」感がある論文は星空日記では発見できなかった。つまり一族の親分たる Patrick Hanrahan はすごかったね。

しかしその後の Tableau の発展はアカデミアに還元されることはなかったのだった・・・と書こうと思ったら Tableau Research というのがあり、論文わりと面白そうじゃないですか。タイトルで選んで記録:

可視化は自分の関心が高まってるせいもあってどの論文も面白そうでよい。

あと Polaris の被引用リストを見ていたら The Grammar Of Graphics の論文バージョン 2012 を発見したので、書籍 Grammar Of Graphics じゃなくてこっちを読もうかな。

はじめに

長いことブログというものを表立って書いていなかった。なにもインターネットに存在感がないのは寂しいのでまた書いてみる。

人々に言いたいことは今のところ特にないので、かわりにしばらくは自分が余暇の時間にやっている読んだり書いたりの活動を記録していこうと思う。森田が報告・連絡・相談するので法蓮草の森。連絡と相談はたぶんしないけど、語呂優先です。