top of page

Tableau実践問題集 #TableauChallenge を作りました。

Gauge ChartをTableauで作る


公開日: 2024/04/12
最終更新: 2024/04/12

参考資料
- マップの地理的レイヤーを作成する
- Data Densificationを理解する

Workout Wednesday 2024/Week 14ではGauge Chart(ゲージチャート)に関するお題が出題されました。

本記事はこのお題から着想を得て作成しています。


Gauge ChartをTableauで作る方法については、既にいくつかの記事にまとめられています。例えば以下の記事などです。


ただし、Map Layers機能のリリース前に公開されたものである、またはテンプレートを用意して簡単に利用できることを目的としている、などの理由によりデータの形式が指定されている場合が多い印象です。


Gauge Chartはそれ単体で使用するというよりは、ダッシュボードや可視化の一部として使用されることが多い印象のため、使用するデータの事前加工を極力必要としない方法を用意できればと思いました。

この目的のために、Data DensificationとMap Layers機能を使用したGauge Chartの作り方を紹介します。


この記事の内容から、以下のようなGauge Chartを作成することができます。



本記事で使用したワークブックはこちらからダウンロードできます。

Sample Superstoreのデータおよびダミーデータを使用します。

Data Densificationに使用したダミーデータはこちらからダウンロードできます。


 

Gauge Chartについて


簡単にですが、Gauge Chartとは何か、どのような場合に使用するか、そもそも使用するべきかについて記載します。


Gauge Chartとは、その見た目の通りスピードメーターのようなゲージ(目盛)を用いて、進捗管理や割合の可視化などに使用されるグラフです。

デザインの柔軟性が高いグラフですが、多くは半円形または円形の形状をしており、主には以下が構成要素に含まれるように思います。

  • 対象とする指標が取る値の範囲を表すゲージ

  • 対象とする指標の値を示すゲージまたは針

  • 目盛などのラベル


可視化例については、例えば以下の記事が参考になります。


ところで、結局のところ目的は詳細なデータを可視化することではなく、重要指標および比較対象の可視化です。

したがって、例えば以下のような棒グラフでも目的は十分達成でき、かつ実装もGauge Chartに比べて大変シンプルかつ簡単です。



この点については以下の記事の「So What’s Best?」以降で、Gauge Chartを使うべきか、代替案を模索するべきかについてを具体例と共に記載されています。


Gauge Chartが持つ親和性、その形状が想起させるメタファー、目を引きやすい形状を取るか、実装しやすくビジュアルベストプラクティスに沿ったグラフの利点を取るかは、対象とするユーザーなど、可視化が使用される文脈や状況に合わせて選択する必要があります。

Gauge Chartは棒グラフなどのシンプルなグラフ形式よりは実装が複雑になるので、その複雑性に対する見返りについての検討をした上での使用が望ましいと思います。


以降で具体的な作り方について詳細に解説しますが、もし上記までの内容で「代替案を検討した方が良い」気がした方は、おそらくその予想は正しいです。 ここまでの内容や挙げている参考資料を代替案検討にお使いいただければ幸いです。


Gauge Chartの作り方の一例を知りたい方、Gauge Chartを使う必要性がある方は、以降の内容にぜひお付き合いください。



 

Gauge Chart作成の基本方針


まず初めに、本記事で扱うGauge Chartを構成する部品および使用する機能について説明します。


Map Layers機能を使うので構成要素は簡単に増減できますが、ここでは以下の4要素からGauge Chartを作成します。


作成するGauge Chartは上図のように、大きく以下の部品から作成します。

  • 背景のゲージ

  • 対象とする指標を示すゲージまたは針

  • 基準線とラベル

  • 基準線からなるゲージ領域

このGauge Chartの部品を作成しまとめて一つのグラフにするために、特に以下の事項を扱います。

  • Map Layers機能

    • 部品を一つのシート上で重ねて表示するため。

  • 多角形マーク(ポリゴンマーク)

    • 円弧を描画するため。

  • Data Densification

    • 円弧を描画するためのデータ点を用意するため。

  • 三角関数

    • 円弧を描画するための位置を与えるため。


またData Densificationを行うため、以下のようにSuperstoreのデータとダミーデータの間にRelationを設定します。

Data Densificationについては以下の記事を参照ください。




 

背景のゲージを作る


まずは背景部分を作成します。これは円周上に0度から180度までの点を作成し、それをつないで描画します。

そのため、各点の角度の計算に使用する計算フィールドを作成していきます。

INDEX
[ID] - 1

ダミーデータのID列は1から100の値を持ちますが、今後の計算では0から始まる値がある方が都合がいいため、上記のINDEX計算フィールドを用意します。


この0~99の100個のINDEXを、最終的には下図のように円弧上に並べます。


円弧上に並べるためには、各マークにおける角度を定義する必要があります。

ただし最終的にポリゴンを描画するために、最初の半分と残りの半分とで、角度の増減の方向を逆転させる必要があります。

そのため、INDEXが0~49までの場合は左から右に向かう=180度から角度が減るようにし、50~99の範囲では右から左に向かう=0度から角度が増えるようにします。


以下は角度を与える計算式です。

INNER/OUTER Label
IIF(MIN([INDEX]) <= 49, 'INNER', 'OUTER')
Radian (Background)
IF [INNER/OUTER Label] = 'INNER' THEN
    (49 - MIN([INDEX])) * PI()/49
ELSE
    (MIN([INDEX]) -1 - 49) * PI()/49
END

ところで、ゲージ描画のためには角度だけではなく円の半径も必要になります。

円の半径を与える計算フィールドも用意しましょう。

ここで[Inner Radius]と[Outer Radius]は小数型パラメータで、ここではそれぞれ値を0.5および0.6としています。

Radius (Actual/Background)
IIF([INNER/OUTER Label] = 'INNER', [Inner Radius], [Outer Radius])

半径と角度が与えられたので、実際にゲージを描画してみます。

まずは地図上の点を与える計算フィールドを作成します。

POINT (Background)
MAKEPOINT(
    [Radius (Actual/Background)] * SIN([Radian (Background)])
    , [Radius (Actual/Background)] * COS([Radian (Background)])
)

作成したPOINT (Background)を配置し、以下のようにポリゴンマークを選択し、IDをパスに入れます(INDEXでも可)。



ちなみにMAKEPOINT関数を使用しているので地図を使用した描画になっているため、デフォルトでは左下にMapboxのコピーライトが表示されます。

表示させない方法はいくつかありますが、一番簡単な方法はバックグラウンドレイヤーを全て非表示にすることかなと思います。



背景のゲージを作成することができました。

このように角度と半径を作成し、それを用いたMAKEPOINT関数を使用することが、今回の作成方法の基本方針です。


背景が出来たので、次は実際の指標について描画していきましょう。



 

指標を追加する


次に実際の指標を描画します。

今回はSuperstore全体の利益率を使用します。ただし以降の計算式で使いやすいように、Measureという計算フィールドを作成します。

Measure
SUM([Profit]) / SUM([Sales])

今回作成するGauge Chartは半円の範囲に収めたいので、この指標が半円で示される範囲を超えないようにします。

Measure (in [Lower Limit, Upper Limit])
MAX(
    MIN([Measure], [Threshold - Upper Limit])
    , [Threshold - Lower Limit]
)

この計算フィールドでは、2つのパラメータ[Threshold - Upper Limit]および[Threshold - Lower Limit]を使用しています。 それぞれゲージの上限と下限の数字を入れており、今回は上限が30%、下限が-10%とします。


上記の計算式によって「今回使用する0~180度の半円は-10%から30%の範囲を示す」と定義されました。

つまり-10%が180度、30%が0度に対応します。


例えばSuperstore全体の利益率は約12.6%ですが、この12.6%は角度に換算して何度になるのかを計算する必要があります。

いくつか方法があるとは思いますが、ここでは(0度, 30%)と(180度, -10%)を通る直線の式を求めることにより計算します。



求めた直線の式から、以下の計算フィールドを作成してMeasureを角度(Radian)に変換します。 ちなみに上記の上限と下限の数値下で、約1.37(Rad) ≒ 78度くらいでした。

Measure (in Radian)
PI()/([Threshold - Upper Limit]-[Threshold - Lower Limit]) 
* (-[Measure (in [Lower Limit, Upper Limit]])]+[Threshold - Upper Limit])

Measureの値に対応する角度が求められたので、この角度から180度までのポリゴンを作るための、各点の角度を計算します。

上記と同様に、2点を通る直線から求めます。ただしINDEXの値によって直線の向きが変わるので、以下のように2直線分を求めます。



求められた2直線の式から、以下の計算フィールドでポリゴン描画用の角度を与えます。

Radian (Actual)
IF [INNER/OUTER Label] = 'INNER' THEN
    ([Measure (in Radian)] - PI()) / 49 * MIN([INDEX])
    + PI()
ELSE
    ((PI() - [Measure (in Radian)]) * MIN([INDEX]) 
    + 99 * [Measure (in Radian)] - 50 * PI()) / 49
END

ポリゴン描画用の角度が求まり、また半径は背景のものと共用なので、Measure用の地図上の点を作成できるようになりました。

POINT (Actual)
MAKEPOINT(
    [Radius (Actual/Background)] * SIN([Radian (Actual)])
    , [Radius (Actual/Background)] * COS([Radian (Actual)])
)

背景を作成したシート上で、下図のようにMap Layerを重ねる形で描画します。



ちなみに、もしゲージではなく針で可視化したい場合には、以下の計算フィールドを使用します。 要は2点を結んで線を描画しているだけです。

Radius (Actual/Tick)
WHEN 0 THEN 0
WHEN 1 THEN ([Outer Radius] + [Inner Radius])/2
END
POINT (Actual/Tick)
MAKEPOINT(
    [Radius (Actual/Tick)] * SIN([Measure (in Radian)])
    , [Radius (Actual/Tick)] * COS([Measure (in Radian)])
)
Tick Size
MIN(IIF([INDEX] IN (0,1), -[INDEX], NULL))


ということで、Gauge Chartの重要な部品を作成できました。

ただし現状の可視化では比較対象などが可視化されておらず、可視化から読み取れる情報が特にない状態になっています。


可視化に文脈を追加するため、比較対象を描画しましょう。



 

比較対象を描画する


比較対象をどのように可視化するかは色々なデザインがあると思いますが、ここではシンプルに線を引きましょう。

ここでは以下の4本の線を引きます。

  • Gauge Chartの下限 (-10%)

  • Gauge Chartの上限 (30%)

  • 基準線(0%)

  • 目標値(15% - パラメータ[Threshold - Target]で制御する)


今までと同様に、それぞれの値における角度を考える必要があります。

Gauge Chartの下限と上限はそれぞれ180度および0度で与えるとして、基準線と目標値については、Measure (in Radian)と同様の式から計算します。

Radian (Baseline)
PI()/([Threshold - Upper Limit]-[Threshold - Lower Limit]) 
* (-[Threshold - Baseline] + [Threshold - Upper Limit])
Radian (Target)
PI()/([Threshold - Upper Limit]-[Threshold - Lower Limit]) * (-[Threshold - Target]+[Threshold - Upper Limit])

ところで4本の線を描き、線の種類によって角度を出しわける必要があるので、以下に線の出し分けのためにラベル付けをする計算フィールドを用意します。

Threshold Name
CASE INT([INDEX]/2)
WHEN 0 THEN 'Lower Limit'
WHEN 1 THEN 'Baseline'
WHEN 2 THEN 'Target'
WHEN 3 THEN 'Upper Limit'
END

4本の線を引くので、それぞれに始点と終点の2点が必要なので、合計で8点が必要になります。

上記の計算式は、感覚的にはINDEXの値が0~7のデータ点についてのみラベル付けをしています。


このラベルの値に合わせた角度の出し分けを、以下の計算フィールドにより実現します。

Radian (Thresholds)
CASE MIN([Threshold Name])
WHEN 'Lower Limit' THEN PI()
WHEN 'Baseline' THEN [Radian (Baseline)]
WHEN 'Target' THEN [Radian (Target)]
WHEN 'Upper Limit' THEN 0
END

また、半径を以下の計算フィールドで与えます。

Radius (Thresholds)
IF MIN([INDEX])%2 = 0 
THEN 
    [Inner Radius]*0.95 
ELSEIF MIN([INDEX])%2 = 1 
THEN 
    [Outer Radius]*1.05
END

この計算フィールドは、INDEXの値が偶数なら[Inner Radius]の0.95倍を、奇数なら[Outer Radius]の1.05倍を返しています。


実際に見てみた方が早いと思いますので、同様にMAKEPOINT関数を使った計算フィールドを作成し、Map Layerを足してみましょう。

POINT (Thresholds)
MAKEPOINT(
    [Radius (Thresholds)] * SIN([Radian (Thresholds)])
    , [Radius (Thresholds)] * COS([Radian (Thresholds)])
)


(線が見やすいよう、ゲージの色を調整しています) 上記では線の名前をラベルで表示していますが、数字を表示したい場合には、以下のような計算フィールドを作成し使用することもできます。

Threshold Label
WHEN 'Lower Limit' THEN [Threshold - Lower Limit]
WHEN 'Baseline' THEN [Threshold - Baseline]
WHEN 'Target' THEN [Threshold - Target]
WHEN 'Upper Limit' THEN [Threshold - Upper Limit]
END

また基準線も可視化できたので、基準に対する指標の大小で色付けをしてみましょう。

Color
IF [Measure] >= [Threshold - Target] THEN 'Good'
ELSEIF [Measure] <= [Threshold - Baseline] THEN 'Bad'
ELSE 'In-between'
END

ここまでの内容でGauge Chartに必要な要素はカバーできたと思います。

最後に色の凡例と数値のラベルのような、補完的な要素を作成します。



 

色の凡例とラベルを追加する


色の凡例は以下3つのポリゴンの重ね合わせで表現します。


必要な計算式の考え方は既に解説されているので、ここでは必要な計算フィールドを列挙します。

Radian (Indicator - Bad)
IF [INNER/OUTER Label] = 'INNER' THEN
    ([Radian (Baseline)] - PI()) / 49 * MIN([INDEX])
    + PI()
ELSE
    ((PI() - [Radian (Baseline)]) * MIN([INDEX]) 
    + 99 * [Radian (Baseline)] - 50 * PI()) / 49
END
Radian (Indicator - In-between)
IF [INNER/OUTER Label] = 'INNER' THEN
    ([Radian (Target)] - PI()) / 49 * MIN([INDEX])
    + PI()
ELSE
    ((PI() - [Radian (Target)]) * MIN([INDEX]) 
    + 99 * [Radian (Target)] - 50 * PI()) / 49
END
Radius (Indicator)
IIF(
    [INNER/OUTER Label] = 'INNER'
    , [Inner Radius] * 0.85
    , [Inner Radius] * 0.9
)
POINT (Indicator - Bad)
MAKEPOINT(
    [Radius (Indicator)] * SIN([Radian (Indicator - Bad)])
    , [Radius (Indicator)] * COS([Radian (Indicator - Bad)])
)
POINT (Indicator - In-between)
MAKEPOINT(
    [Radius (Indicator)] * SIN([Radian (Indicator - In-between)])
    , [Radius (Indicator)] * COS([Radian (Indicator - In-between)])
)
POINT (Indicator - Good)
MAKEPOINT(
    [Radius (Indicator)] * SIN([Radian (Background)])
    , [Radius (Indicator)] * COS([Radian (Background)])
)

下図のように配置します。Map Layerの順番に注意ください。 順番はドラッグ&ドロップで変更できます。

また必要に応じてズームアウトやラベル表示位置などを調整ください。



同様に、数字と指標名を表示するための計算フィールドを作成し、Map Layerに追加します。

Radian (Label)
IF MIN([INDEX]) IN (0,1) THEN PI()/2 END
Radius (Label)
CASE MIN([INDEX])
WHEN 0 THEN 0
WHEN 1 THEN [Outer Radius] * 1.25
END
Text Label
CASE MIN([INDEX])
WHEN 0 THEN STR(ROUND([Measure]*100, 1)) + '%'
WHEN 1 THEN 'Profit Ratio'
END
POINT (Label)
MAKEPOINT(
    [Radius (Label)] * SIN([Radian (Label)])
    ,[Radius (Label)] * COS([Radian (Label)])
)


ということで、目的のGauge ChartをData DensificationとMap Layers機能を使って作成することができました。

Map Layerは選択可否を設定できるので、クリック等を必要としない要素については選択を許可しない設定にしておくと良いと思います。



 

Relationが使えない場合


ところで、今回の方法ではRelationを使って100行のダミーデータを結合することで、一つのデータソースからGauge Chartを作成しました。

一方、例えばTableau Cloud/Server上のデータソースなど、Relation機能を使用できないデータソースに対しては、今回の方法をそのまま使うことができません。


そのような場合には、Map Layers機能は複数データソースからの作成をサポートしていることを利用して作成します。

ただしMAKEPOINT関数が表計算を引数にできない都合、針を使用したGauge Chartで作ることが現実的かなと思います。


以下が作成例です。詳細はワークブックの「Without Relation」シートを確認ください。

SuperstoreデータソースおよびDummyデータソースの2つの独立したデータソースから作成しています。




 

最後に


Data DensificationとMap Layers機能を使用したGauge Chartの作り方について解説しました。

本記事で扱った内容を元に、要件に合わせてアレンジください。Map Layers機能を使用しているので、要素の追加など柔軟性は高いと思います。


ちなみに本記事は先にワークブックを作成し、記事化するにあたって参考資料を探したのですが、以下のLuke Stankeさんの記事では本記事と近いこと記載されています。

こちらも合わせて一読いただくと理解が深まるかもしれません。


質問などありましたら、XかLinkedinまでお願いします。



コメント


bottom of page