3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI/BIダッシュボードのカスタムビジュアライゼーション入門 - Vega-Liteの各チャートを動かすサンプルデータの作り方

3
Last updated at Posted at 2026-06-15

以前ガントチャートの記事を書きましたが、同じタイミングカスタム可視化もサポートされていました。

カスタムビジュアライゼーション (Public Preview): 組み込みのビジュアライゼーションタイプを超えたカスタマイズを行うために、Vega-Lite ライブラリでカスタムチャートを作成します。AI/BI ダッシュボードでのカスタムビジュアライゼーションを参照してください。

はじめに

AI/BIダッシュボードのカスタムビジュアライゼーションを使うと、組み込みのチャート種別では表現できないグラフを自分で定義できます。レンダリングには Vega-Lite ライブラリが使われており、JSON仕様を書くだけでゲージ、レーダー、ブレット、サンバースト、放射状チャートなどを描画できます。

本記事は以下の公式ドキュメントをベースにした解説です。

なお、この機能は記事執筆時点でパブリックプレビュー段階です。

公式ドキュメントには各チャートのJSON仕様は掲載されているものの、「どんなデータセットを用意すればその仕様が動くのか」がわかりにくい例がいくつかあります。そこで本記事では、各仕様の transform と参照フィールドを読み解き、そのまま貼り付けて動かせるサンプルデータの作り方まで導出しました。掲載しているサンプルデータとJSON仕様の組み合わせは、Vega-Lite (vega-lite 6 / vega 6) で実際にレンダリングできることを確認済みです。

Screenshot 2026-06-15 at 17.23.40.png

Vega-Liteとは

Vega-Lite は、可視化を宣言的なJSONで記述するための高水準なグラフィクス文法 (grammar of graphics) です。低レベルな描画ライブラリである Vega の上に構築されており、より簡潔な記法で対話的なグラフを生成できます。

1つのチャートは、おおむね次の要素を組み合わせて定義します。

  • data: 描画対象のデータ。Databricksのカスタムビジュアライゼーションでは、ダッシュボードのデータセットが databricks_query という名前で渡されます
  • transform: 集計、ウィンドウ関数、計算列の追加など、描画前のデータ変換
  • mark: 点 (point)、線 (line)、棒 (bar)、円弧 (arc) といった描画図形の種類
  • encoding: 列を xycolortheta などの視覚属性に割り当てるマッピング
  • layer: 複数のチャートを重ね合わせるための仕組み

基本的な棒グラフや折れ線グラフから、layer で複数のマークを重ねた複合チャートまで表現できる点が特徴です。Databricksのカスタムビジュアライゼーションは、この記法をほぼそのまま利用できます。

カスタムビジュアライゼーションの作成手順

基本的な流れは次の通りです。

  1. データセットを選択します
  2. 視覚化構成ペインで、詳細な視覚化セクションの下にある「カスタム可視化」を選択します
    Screenshot 2026-06-15 at 16.42.37.png
  3. 「フィールド」セクションで、使用するフィールドを追加します。各フィールドには一意の「名前」を付けます
  4. Vega-Lite JSON仕様を「Vega-Lite 仕様」エディターに入力します

ここで最も重要なのが、フィールドの「名前」とJSON仕様の対応関係です。

フィールドの「名前」が仕様とデータの橋渡しになる

カスタムビジュアライゼーションでつまずきやすいのが「JSON仕様が参照しているフィールド名と、SQLの列名がどう結びつくのか」という点です。両者を結びつけるのは「フィールド」セクションで付ける「名前」です。

  • JSON仕様の中の "field": "categoryField"datum['$valueField'] は、すべて「フィールドの名前」を参照しています
  • Databricksは、この名前の文字列が仕様JSONの中に登場するかどうかで使用・未使用を判定します。名前が1文字でも違うと「未使用のフィールド」という警告が出ます

「フィールド」セクションでは名前を手で書き換えることもできますが、列を追加するたびに付け替えるのは漏れやすく、警告の原因になりがちです。そこで本記事では、最初からSQLの列エイリアスを仕様が参照する名前に一致させておく方針を採ります。こうすると、フィールドを追加した時点で名前が自動的に正しい値になり、手作業の付け替えが不要になります。

なお公式の仕様には $valueField のように名前の先頭に $ が付くものがあります。これは特別な構文ではなく、単に名前として $valueField という文字列を使っているだけです。SQLの列エイリアスでこの名前を使う場合は、`$valueField` のようにバッククォートで囲みます。

以降の各例では、この方針に沿ってそのまま実行できるSQLを示します。

移動平均付き階層化チャートの例

公式ドキュメントでも紹介されている、生の温度データに移動平均線を重ねるレイヤーチャートです。Databricksのサンプルデータセットの気象データをそのまま使えます。

データセットは以下のクエリーで作成します。

SELECT date, temperature AS temp_max
FROM samples.accuweather.historical_hourly_imperial
WHERE city_name = 'singapore'
ORDER BY date

この例では、列エイリアス (datetemp_max) が仕様の参照名とそのまま一致しています。そのため、フィールドを追加するだけで名前が一致し、付け替えは不要です。

JSON仕様は次の通りです。transformwindow で前後15ポイントの移動平均 (rolling_mean) を計算し、layer で散布点 (point) と赤い移動平均線 (line) を重ねています。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "width": "container",
  "height": "container",
  "config": {
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "data": { "name": "databricks_query" },
  "transform": [
    {
      "window": [{ "field": "temp_max", "op": "mean", "as": "rolling_mean" }],
      "frame": [-15, 15]
    }
  ],
  "encoding": {
    "x": { "field": "date", "type": "temporal", "title": "Date" },
    "y": {
      "type": "quantitative",
      "scale": { "zero": false },
      "axis": { "title": "Max temperature and rolling mean" }
    }
  },
  "layer": [
    {
      "mark": { "type": "point", "opacity": 0.3 },
      "encoding": { "y": { "field": "temp_max", "title": "Max temperature" } }
    },
    {
      "mark": { "type": "line", "color": "red", "size": 3 },
      "encoding": { "y": { "field": "rolling_mean", "title": "Rolling mean of max temperature" } }
    }
  ]
}

実際に設定すると、次のようなチャートが得られます。

Screenshot 2026-06-15 at 16.44.03.png

X軸が見切れる場合は、後述の「グラフのサイズを自動的に変更する」を参照してください。

データセット列の参照方法

Vega-Lite仕様の中で列を参照する方法は2通りあります。

1つ目は encoding などで "field": "{列名}" を使う方法です。

"encoding": {
  "x": { "field": "xField", "type": "quantitative" }
}

2つ目は式 (expression) の中で datum["{列名}"] または datum.{列名} を使う方法です。次の例では、rangle の列から新しい x を計算しています。

{ "calculate": "datum.r * cos(datum.angle)", "as": "x" }

式の詳細は、Vega expressionsドキュメントの datum を参照してください。

グラフのサイズを自動的に変更する

グラフをコンテナのサイズに合わせるには、仕様の最上位レベルに次の設定を追加します。X軸の見切れなどが起きる場合に有効です。

"width": "container",
"height": "container",
"config": {
  "autosize": {
    "type": "fit",
    "contains": "padding"
  }
}

チャート仕様の例とサンプルデータの作り方

ここからは、組み込みの視覚化では作れないチャートの仕様と、それを動かすためのサンプルデータを示します。各SQLは VALUES 句で直接データを生成しているため、テーブルを用意しなくてもそのまま実行できます。より多くの例は Vega-Lite の例のギャラリー も参考になります。

各チャートには、設定後のスクリーンショットを貼り付けるためのプレースホルダーを入れてあります。サンプルデータで動作を確認したら、実際の画面に差し替えてください。

ブレットチャート (Bullet chart)

目標値 (target) に対する現在値 (current) と進捗ペース (pace) を、カテゴリーごとに横棒で示すチャートです。targetFieldpaceFieldcurrentFieldfold で縦持ちに変換し、それぞれ別のマークで描画しています。

必要なフィールドは categoryFieldcurrentFieldpaceFieldtargetField です。各行が1つのカテゴリーに対応します。

サンプルデータは次のように作成します。

SELECT * FROM VALUES
  ('営業',           270, 250, 300),
  ('マーケティング', 180, 200, 250),
  ('サポート',       310, 280, 300),
  ('エンジニアリング', 220, 230, 280)
AS sample(categoryField, currentField, paceField, targetField)

列のエイリアスを仕様が参照する名前に合わせてあるため、「フィールド」セクションで各列を追加すれば、名前は自動的に categoryField / currentField / paceField / targetField になります。名前を手で付け替える必要はありません。

visualization.png

JSON仕様は次の通りです。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "width": "container",
  "height": "container",
  "data": { "name": "databricks_query" },
  "config": {
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "transform": [
    {
      "fold": ["targetField", "paceField", "currentField"],
      "as": ["measure_name", "measure_value"]
    },
    {
      "calculate": "toNumber(datum.measure_value)",
      "as": "measure_value"
    },
    {
      "calculate": "{ \"targetField\": \"Target\", \"paceField\": \"Pace\", \"currentField\": \"Current\" }[datum.measure_name]",
      "as": "measure_label"
    },
    {
      "calculate": "indexof([\"Target\", \"Pace\", \"Current\"], datum.measure_label)",
      "as": "measure_order"
    }
  ],
  "layer": [
    {
      "mark": "bar",
      "params": [
        {
          "name": "legend_click",
          "select": { "type": "point", "fields": ["measure_label"] },
          "bind": "legend"
        }
      ],
      "encoding": {
        "color": { "field": "measure_label" },
        "opacity": { "value": 0 }
      }
    },
    {
      "transform": [{ "filter": { "param": "legend_click" } }],
      "layer": [
        {
          "layer": [
            {
              "mark": { "type": "bar", "tooltip": true },
              "encoding": { "color": { "field": "measure_label", "legend": null } },
              "transform": [{ "filter": { "field": "measure_label", "oneOf": ["Pace"] } }]
            },
            {
              "mark": { "type": "bar", "height": 7, "tooltip": true },
              "encoding": { "color": { "field": "measure_label", "legend": null } },
              "transform": [{ "filter": { "field": "measure_label", "oneOf": ["Current"] } }]
            },
            {
              "mark": { "type": "tick", "tooltip": true, "thickness": 3 },
              "encoding": { "color": { "field": "measure_label", "legend": null } },
              "transform": [{ "filter": { "field": "measure_label", "oneOf": ["Target"] } }]
            }
          ],
          "encoding": {
            "x": {
              "field": "measure_value",
              "type": "quantitative",
              "stack": null,
              "title": "Value",
              "axis": { "orient": "bottom" }
            },
            "color": {
              "scale": {
                "domain": ["Target", "Pace", "Current"],
                "range": ["#000000", "#bcbcbc", "#A66BBF"]
              }
            },
            "order": {
              "field": "measure_order",
              "type": "quantitative",
              "sort": "descending"
            }
          }
        }
      ],
      "encoding": {
        "y": {
          "field": "categoryField",
          "type": "ordinal",
          "title": "Category",
          "axis": { "labelOverlap": true }
        },
        "tooltip": [
          { "field": "categoryField", "type": "nominal", "title": "Category" },
          { "field": "currentField", "type": "quantitative", "title": "Current" },
          { "field": "paceField", "type": "quantitative", "title": "Pace" },
          { "field": "targetField", "type": "quantitative", "title": "Target" }
        ]
      }
    }
  ]
}

ゲージ

1つの値を全体に対する割合として円弧で表現するチャートです。ratio (= $valueField / $totalField) を計算し、割合に応じて色が変わります。0.33未満で赤、0.66未満で橙、それ以上で緑です。

必要なフィールドは $valueField$totalField です。ゲージは単一の値を表示するため、データは1行で十分です。

サンプルデータは次のように作成します。下記は72%相当 (緑色) になります。

SELECT 72 AS `$valueField`, 100 AS `$totalField`

名前に $ が含まれるため、SQLの列エイリアスはバッククォートで囲みます。こうしておくと、フィールド追加時の名前がそのまま $valueField / $totalField になります。

visualization (1).png

JSON仕様は次の通りです。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
  "width": "container",
  "height": "container",
  "data": { "name": "databricks_query" },
  "config": {
    "concat": { "spacing": 0 },
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "params": [
    { "name": "ring_max", "expr": "min(width, height) / 2 - 16" },
    { "name": "ring_width", "expr": "max(12, (min(width, height) / 2) * 0.12)" },
    { "name": "ring_gap", "expr": "max(4, (min(width, height) / 2) * 0.03)" },
    { "name": "label_color", "value": "#000000" },
    { "name": "ring_background_opacity", "value": 0.3 },
    { "name": "ring0_percent", "value": 100 },
    { "name": "ring0_outer", "expr": "ring_max + 2" },
    { "name": "ring0_inner", "expr": "ring_max + 1" },
    { "name": "ring1_outer", "expr": "ring0_inner - ring_gap" },
    { "name": "ring1_inner", "expr": "ring1_outer - ring_width" },
    { "name": "ring1_middle", "expr": "(ring1_outer + ring1_inner) / 2" },
    { "name": "arc_size", "expr": "220" }
  ],
  "transform": [
    { "as": "ratio", "calculate": "datum['$valueField'] / datum['$totalField']" },
    { "as": "_arc_start_degrees", "calculate": "360 - ( arc_size / 2 )" },
    { "as": "_arc_end_degrees", "calculate": "0 + ( arc_size / 2 )" },
    { "as": "_arc_start_radians", "calculate": "2 * 3.14 * ( datum['_arc_start_degrees'] - 360 ) / 360" },
    { "as": "_arc_end_radians", "calculate": "2 * 3.14 * datum['_arc_end_degrees'] / 360" },
    { "as": "_arc_total_radians", "calculate": "datum['_arc_end_radians'] - datum['_arc_start_radians']" },
    { "as": "_ring_start_radians", "calculate": "datum['_arc_start_radians']" },
    {
      "as": "_ring_end_radians",
      "calculate": "datum['_arc_start_radians'] + ( datum['_arc_total_radians'] * datum['ratio'] )"
    }
  ],
  "layer": [
    {
      "mark": {
        "type": "arc",
        "color": "lightgrey",
        "theta": { "expr": "datum['_arc_start_radians']" },
        "radius": { "expr": "ring1_outer" },
        "theta2": { "expr": "datum['_arc_end_radians']" },
        "radius2": { "expr": "ring1_inner" },
        "cornerRadius": 10
      }
    },
    {
      "name": "RING",
      "mark": {
        "type": "arc",
        "theta": { "expr": "datum['_ring_start_radians']" },
        "radius": { "expr": "ring1_outer" },
        "theta2": { "expr": "datum['_ring_end_radians']" },
        "radius2": { "expr": "ring1_inner" },
        "cornerRadius": 10
      },
      "encoding": {
        "color": {
          "value": "#307E31",
          "condition": [
            { "test": "datum['ratio'] < 0.33", "value": "#880808" },
            { "test": "datum['ratio'] < 0.66", "value": "#E49B0F" }
          ]
        }
      }
    },
    {
      "mark": { "type": "text", "fontSize": 40 },
      "encoding": {
        "text": { "field": "$valueField" },
        "color": {
          "value": "#307E31",
          "condition": [
            { "test": "datum['ratio'] < 0.33", "value": "#880808" },
            { "test": "datum['ratio'] < 0.66", "value": "#E49B0F" }
          ]
        }
      }
    }
  ]
}

レーダーチャート

複数の評価軸のスコアを多角形で表現するチャートです。windowrow_number で各行に通し番号を振り、その順序を角度に変換して円周上に配置します。スコアは最大値を100として正規化されます。

必要なフィールドは $key (軸のラベル) と $value (スコア) です。各行が1つの軸に対応します。行の並び順が角度の順序になるため、軸は3つ以上用意するとレーダーらしくなります。

サンプルデータは次のように作成します。

SELECT * FROM VALUES
  ('スピード', 80),
  ('パワー',   65),
  ('防御',     90),
  ('リーチ',   70),
  ('精度',     85),
  ('スタミナ', 60)
AS sample(`$key`, `$value`)

$ を含む名前はバッククォートで囲みます。フィールドを追加すれば名前がそのまま $key / $value になります。

visualization (2).png

JSON仕様は次の通りです。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "width": "container",
  "height": "container",
  "config": {
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "data": { "name": "databricks_query" },
  "transform": [
    { "window": [{ "op": "row_number", "as": "category" }] },
    { "calculate": "datum.category - 1", "as": "category" },
    {
      "joinaggregate": [
        { "op": "count", "as": "numCategories" },
        { "op": "max", "field": "$value", "as": "maxValue" }
      ]
    },
    { "calculate": "2 * PI * datum.category / datum.numCategories", "as": "angle" },
    { "calculate": "100 * datum['$value'] / datum.maxValue", "as": "r" },
    { "calculate": "datum.r * cos(datum.angle)", "as": "x" },
    { "calculate": "datum.r * sin(datum.angle)", "as": "y" },
    { "calculate": "110 * cos(datum.angle)", "as": "label_x" },
    { "calculate": "110 * sin(datum.angle)", "as": "label_y" }
  ],
  "layer": [
    {
      "transform": [
        { "joinaggregate": [{ "op": "count", "as": "numCategories" }] },
        { "aggregate": [{ "op": "max", "field": "numCategories", "as": "numCategories" }] },
        { "calculate": "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", "as": "cats" },
        { "flatten": ["cats"], "as": ["cat"] },
        { "filter": "datum.cat <= datum.numCategories" },
        { "calculate": "2 * PI * datum.cat / datum.numCategories", "as": "angle" },
        { "calculate": "100 * cos(datum.angle)", "as": "x" },
        { "calculate": "100 * sin(datum.angle)", "as": "y" }
      ],
      "mark": { "type": "line", "color": "#ddd", "strokeWidth": 1 },
      "encoding": {
        "x": { "field": "x", "type": "quantitative", "scale": { "domain": [-120, 120] }, "axis": null },
        "y": { "field": "y", "type": "quantitative", "scale": { "domain": [-120, 120] }, "axis": null },
        "order": { "field": "cat" }
      }
    },
    {
      "transform": [
        { "joinaggregate": [{ "op": "count", "as": "numCategories" }] },
        { "aggregate": [{ "op": "max", "field": "numCategories", "as": "numCategories" }] },
        { "calculate": "[20,40,60,80,100]", "as": "levels" },
        { "flatten": ["levels"], "as": ["level"] },
        { "calculate": "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", "as": "cats" },
        { "flatten": ["cats"], "as": ["cat"] },
        { "filter": "datum.cat <= datum.numCategories" },
        { "calculate": "2 * PI * datum.cat / datum.numCategories", "as": "angle" },
        { "calculate": "datum.level", "as": "r" },
        { "calculate": "datum.r * cos(datum.angle)", "as": "x" },
        { "calculate": "datum.r * sin(datum.angle)", "as": "y" }
      ],
      "mark": { "type": "line", "color": "#ddd", "strokeWidth": 1 },
      "encoding": {
        "x": { "field": "x", "type": "quantitative" },
        "y": { "field": "y", "type": "quantitative" },
        "detail": { "field": "level" },
        "order": { "field": "cat" }
      }
    },
    {
      "mark": { "type": "line", "color": "#9467bd", "strokeWidth": 2, "interpolate": "linear-closed" },
      "encoding": {
        "x": { "field": "x", "type": "quantitative" },
        "y": { "field": "y", "type": "quantitative" },
        "order": { "field": "category" }
      }
    },
    {
      "mark": { "type": "point", "filled": true, "size": 50, "color": "#9467bd" },
      "encoding": {
        "x": { "field": "x", "type": "quantitative" },
        "y": { "field": "y", "type": "quantitative" }
      }
    },
    {
      "mark": { "type": "text", "fontSize": 14, "fontWeight": "bold" },
      "encoding": {
        "x": { "field": "label_x", "type": "quantitative" },
        "y": { "field": "label_y", "type": "quantitative" },
        "text": { "field": "$key", "type": "nominal" }
      }
    }
  ],
  "view": { "stroke": null }
}

放射状チャート (Radial chart)

カテゴリーごとの値を、角度と半径の両方で表現する円グラフの拡張版です。$colorField でグループ化して $valueField の合計を集計するため、同じカテゴリーが複数行に分かれていても合算されます。

必要なフィールドは $valueField (数値) と $colorField (カテゴリー) です。

サンプルデータは次のように作成します。

SELECT * FROM VALUES
  ('スマートフォン', 320),
  ('チェア',         280),
  ('テーブル',       210),
  ('バインダー',     170),
  ('ストレージ',     140)
AS sample(`$colorField`, `$valueField`)

$ を含む名前はバッククォートで囲みます。フィールドを追加すれば名前がそのまま $colorField / $valueField になります。

visualization (3).png

JSON仕様は次の通りです。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
  "width": "container",
  "height": "container",
  "config": {
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "data": { "name": "databricks_query" },
  "transform": [
    {
      "aggregate": [{ "op": "sum", "field": "$valueField", "as": "total" }],
      "groupby": ["$colorField"]
    },
    {
      "window": [{ "op": "rank", "as": "rank" }],
      "sort": [{ "field": "total", "order": "descending" }]
    }
  ],
  "layer": [
    {
      "mark": { "type": "arc", "innerRadius": 20, "stroke": "#fff" }
    }
  ],
  "encoding": {
    "theta": {
      "field": "total",
      "type": "quantitative",
      "scale": { "type": "sqrt" },
      "stack": true,
      "sort": "descending"
    },
    "radius": { "field": "total", "scale": { "type": "sqrt", "zero": true } },
    "color": {
      "field": "$colorField",
      "type": "nominal",
      "title": "Sub-Category",
      "sort": { "field": "total", "order": "descending" },
      "legend": { "orient": "right" }
    },
    "tooltip": [
      { "field": "$colorField", "type": "nominal", "title": "Sub-Category" },
      { "field": "total", "type": "quantitative", "title": "Sales" }
    ]
  },
  "view": { "stroke": null }
}

サンバーストチャート

2階層のグループを同心円のドーナツで表現するチャートです。内側のリングが外側グループ (outerGroupField)、外側のリングがそれぞれの外側グループに属する内側グループ (innerGroupField) を表します。

必要なフィールドは outerGroupFieldinnerGroupFieldsizeField です。各行が「外側グループ × 内側グループ」の1つの組み合わせに対応します。

仕様の色レンジは内側リングが10色、外側リングが2色になっています。そこでサンプルデータは「外側2グループ × 内側5項目 = 10通り」となるように作り、色の対応がきれいになるようにしています。

SELECT * FROM VALUES
  ('モバイル',     'iOS',        120),
  ('モバイル',     'Android',     90),
  ('モバイル',     'タブレット',   40),
  ('モバイル',     'ウェアラブル', 25),
  ('モバイル',     'その他',       15),
  ('デスクトップ', 'Windows',    110),
  ('デスクトップ', 'macOS',       70),
  ('デスクトップ', 'Linux',       30),
  ('デスクトップ', 'ChromeOS',    20),
  ('デスクトップ', 'その他',       10)
AS sample(outerGroupField, innerGroupField, sizeField)

$ は付かないため、列エイリアスをそのまま outerGroupField / innerGroupField / sizeField にすればOKです。フィールド追加時に名前が自動的に一致します。

visualization (4).png

JSON仕様は次の通りです。

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "width": "container",
  "height": "container",
  "data": { "name": "databricks_query" },
  "config": {
    "autosize": { "type": "fit", "contains": "padding" }
  },
  "transform": [
    { "calculate": "datum['outerGroupField']", "as": "OUTSIDE" },
    { "calculate": "datum['innerGroupField']", "as": "INSIDE" },
    { "calculate": "datum.OUTSIDE + '-' + datum.INSIDE", "as": "OUT_IN" },
    { "calculate": "toNumber(datum['sizeField'])", "as": "SIZE" }
  ],
  "resolve": {
    "scale": { "color": "independent" },
    "legend": { "color": "independent" }
  },
  "layer": [
    {
      "mark": {
        "type": "arc",
        "tooltip": true,
        "innerRadius": { "expr": "min(width, height)/9" },
        "outerRadius": { "expr": "min(width, height)/3" }
      },
      "encoding": {
        "theta": { "field": "SIZE", "type": "quantitative", "stack": true },
        "color": {
          "field": "OUT_IN",
          "type": "ordinal",
          "sort": "ascending",
          "title": "Inner Grouping",
          "scale": {
            "range": [
              "#1DF9B9",
              "#1DE5B9",
              "#1DD1B9",
              "#1DBDB9",
              "#1DA9B9",
              "#3DF23B",
              "#3DDA3B",
              "#3DC23B",
              "#3DAA3B",
              "#3D923B"
            ]
          }
        },
        "order": { "field": "OUT_IN", "sort": "ascending" },
        "tooltip": [
          { "field": "OUTSIDE", "type": "nominal", "title": "Outer Grouping" },
          { "field": "INSIDE", "type": "nominal", "title": "Inner Grouping" },
          { "field": "SIZE", "type": "quantitative", "title": "Count" }
        ]
      }
    },
    {
      "transform": [
        {
          "aggregate": [{ "op": "sum", "field": "SIZE", "as": "total_users" }],
          "groupby": ["OUTSIDE"]
        }
      ],
      "mark": {
        "type": "arc",
        "tooltip": true,
        "innerRadius": { "expr": "min(width, height)/3" }
      },
      "encoding": {
        "theta": {
          "field": "total_users",
          "type": "quantitative",
          "stack": true,
          "sort": "ascending",
          "title": "Users Count"
        },
        "color": {
          "field": "OUTSIDE",
          "type": "ordinal",
          "sort": "ascending",
          "title": "Outer Grouping",
          "scale": { "range": ["#1DD1B9", "#3DC23B"] }
        },
        "order": { "field": "OUTSIDE", "sort": "ascending" },
        "tooltip": [
          { "field": "OUTSIDE", "type": "nominal", "title": "Outer Grouping" },
          { "field": "total_users", "type": "quantitative", "title": "Count" }
        ]
      }
    }
  ]
}

制限事項

カスタムビジュアライゼーションには次の制限があります。

  • ツリーマップチャートはサポートされていません。Vega-Lite自体がツリーマップに対応していないためです
  • 画像は、現在カスタムVegaビジュアライゼーションではサポートされていません

おわりに

カスタムビジュアライゼーションのつまずきどころは、JSON仕様の難しさそのものよりも「どんなデータセットを用意すれば仕様が動くのか」がわかりにくい点にあります。本記事では、各仕様が参照しているフィールドを読み解き、VALUES 句だけで完結するサンプルデータを用意しました。

ポイントは、JSON仕様が参照する field 名と「フィールド」セクションの名前が一致している必要があるということです。最初からSQLの列エイリアスを仕様の名前に揃えておけば、フィールド追加時に名前が自動的に一致し、「未使用のフィールド」警告も避けられます。この要領さえ押さえれば、ギャラリーにある他のVega-Lite作例も同じようにダッシュボードへ取り込めます。

はじめてのDatabricks

はじめてのDatabricks

Databricks無料トライアル

Databricks無料トライアル

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?