Radial Chartの応用編として、Radial Gantt Chartの作り方を思いつきましたので書き起こします。
Radial Chartの基礎については以下のブログ記事をご参照下さい。
今回のテーマは「時間に関するデータの、最初と最後を結んだRadial Chartを作る」です。
以下の画像のようなRadial Chartを作成し、これをRadial Gantt Chartと呼称します。
今回の場合、睡眠ログを使用します。就寝時間と起床時間を線で結び、直近の睡眠ほど外側に配置されるようにしています。色の濃淡は「良く寝ている時刻」を示します。
使用したワークブックは以下からダウンロードできます。
使用データは以下に格納しました。
Radial Chartのおさらい
最初に、前回の記事のおさらいを簡単にします。
前回作成したRadial Chartはこちら。
このRadial Chartは、簡単に言えば
全てのLineで始点を固定し
終点の位置をパラメータと、最大長さに対する各Lineの長さの割合で制御
していたグラフでした。
したがってグラフのスタート時点は固定ですし、単にBar Chartを円周上に配置したのみです。
一方で、今回は「始点と終点を円周上にプロットさせ、その後2点を線で結ぶ」ので、同じRadial Chartですが設計方針が大きく異なります。
イメージ的にはGantt Chartを円周上に配置、かつ循環させる感じです。
Radial Gantt Chartのモチベーション
Ganttチャートとの対比でお話すれば、このRadial Gantt Chartは「循環する」ことに大きな意義があります。
試しにGanttチャートでこのデータを可視化したとき、以下のような「日付を跨いだ睡眠」で困ってしまうなと。Ganttのサイズは睡眠時間を示しています。
データ上、本来であれば日付を跨いだらそれは翌日の睡眠としてカウントされるべきで、上図のように「22時から40時まで寝てました!」みたいな見せ方をするべきでは無いかなと思います。
解決策としては睡眠が日付を跨いだレコードを2分割してしまう等の前処理も考えられますが、今回はRadial Gantt Chartを用いて、データを循環させてしまいましょう。
データを見ながら、全体感をまずは掴んでいきましょう。
使用データと作成物について
今回のデータは至極シンプルで、以下の2カラムのみです(というより始点と終点だけあればRadial Chartは作れます)。
このデータを、以下のように良い感じに円周上に載せて、線で結びたいよねというのが今回の目的です。
また、日付を跨いだレコードについても問題なく結べています。
ということで、早速つくっていきましょう。
Radial Gantt Chartの作り方
いつものようにSelf-UNIONです。
最初に、就寝時刻と起床時間を秒に変換します。
何に変換するかは正直なところ使用するデータと目的次第ですので、そこは適宜変更ください。この記事では秒を使用します。
End (seconds)
DATEPART('hour',[Sleep End])*3600
+ DATEPART('minute',[Sleep End]) * 60
+ DATEPART('second',[Sleep End])
Start (seconds)
DATEPART('hour',[Sleep Start])*3600
+ DATEPART('minute',[Sleep Start]) * 60
+ DATEPART('second',[Sleep Start])
次に、秒からRadianに変換します。Radianは要は角度です。
ここで[Rotation (Gantt)]は整数型パラメータで、90を与えています。
(90度の理由は、0°地点を時計12時の方向に合わせたいためです。このあたりも前回の記事をご参照下さい。)
End (Radians)
RADIANS([Rotation (Gantt)] + (360/(3600*24))*[End (seconds)])
Start (Radians)
RADIANS([Rotation (Gantt)] + (360/(3600*24))*[Start (seconds)])
この式をざっくり説明すると、以下のステップを踏んでいます。
回転用の[Rotation (Gantt)]パラメータにより、0°が12時方向になり
360/(3600*24)の補正項で、度数⇔1日の変換をする
[End (seconds)]または[Start (seconds)]を掛けることで、それぞれの1日における秒数が円周上にプロットされる
最後にRADIAN()関数で度数(degree)から弧度(radian)に変換
ちなみに、360/(3600*24)の補正項は秒をプロットする場合であり、分のプロットの場合は360/(60*24)になります。この辺りも適宜変更下さい。
一日は何秒or何分ですか?みたいな話です。
Start (Radians)を調整する
さて、ここで一つ問題が出てきます。
このRadiansをそのまま使用すると、ちょっと良くないことが起こります。
以下に、このまま進めた結果のRadial Gantt Chartをご用意しました。
例の、日付を跨ぐデータに関する問題です。
先程までの計算式では、1日の始まり(0時)に近いほどRadianは小さくなり、1日の終わり(24時)に近いほどRadianは大きくなります。
最終的にRadianのBinを使用するのですが、Radial ChartはBinの小さい方から大きい方に沿って作成されます。
したがって、Start (Radians) > End (Radians) の条件では、線の向きが反転します。
本来Start→Endの方向に沿ってBinが作られて欲しい一方、Start (Radians) > End (Radians) のため、End→Startの方向でBinが作成されます。
この問題を解決するために、以下の計算式を導入します。
Adjusted Start (Radians)
IF [Start (Radians)] < [End (Radians)]
THEN [Start (Radians)]
ELSE [Start (Radians)]- RADIANS(360)
END
要は Start (Radians) > End (Radians) の場合には、360°だけ引いておくことにより、必ずStart (Radians) < End (Radians) となるように調整しよう、と言う計算式です。
Data Densification用のBinを作る
このAdjusted Start (Radians)を使用して、描画用データ作成(Data Densification)用のBinを作成します。
ここでPATH(bin)を0.1刻みにするので、各Radiansを小数点1桁目に丸めておきます。
PATH
IIF([Table Name] = 'Sheet1'
, ROUND([Adjusted Start (Radians)], 1)
, ROUND([End (Radians)], 1)
)
PATH (bin) ここでBin Size (Gantt)は小数型パラメータ、一旦は0.1を設定
[Bin Size (Gantt)] パラメータについては後述します。
このPATHとBinの詳細については、こちらのSankey Diagramの記事をご参照ください。
Radial Gantt Chart用の計算フィールドを作る
やっとここまで来ました。
最初に、各Radial Ganttを指定するディメンションを作成します。
何毎に線を描きたいか、というためのディメンションです。今回の場合、各レコードについて線を描きます。
Dimension
STR([Sleep Start]) + '-' + STR([Sleep End])
そして先ほど使用したPATH(bin)を使用して角度を与えていくために、以下の計算フィールドを用意します。
RADIANS (PATH(bin)を使用して表計算)
IF NOT MIN(ISNULL([PATH]))
THEN MIN([PATH])
ELSE WINDOW_MIN(MAX([PATH])) + (INDEX()-1)*[Bin Size (Gantt)]
END
この式では以下の処理をしています。
もしDensificationで作成されていないマークであれば、普通にPATHを返す
Densificationによるマークであれば、各Dimensionにおける、PATHの最小値(要は[Adjusted Start (Radians)] )を返し、それにINDEX() - 1に [Bin Size (Gantt)]を掛けたものを返す
おそらく見た方が早いので、以下の図をご用意しました。
Start地点からEndに向かって、0.1刻みでRadianが追加されていく感じです。
円周上へプロットする準備が出来たので、座標を与えていきます。
X
-COS([RADIANS]) * INDEX()/SIZE()
Y
SIN([RADIANS])* INDEX()/SIZE()
XとYそれぞれの表計算設定は次のようになっています。
これらを組み合わせ、以下のように配置すればRadial Gantt Chartは完成です。
色については単にINDEXを入れていますが、おまけです。
最後に
今回はRadial Gantt Chartの作成方法について解説しました。
日付などを跨いで数値を循環させたい場合に強力なチャートではと思っています。
カレンダーや時間を使用した可視化で、どうにも両端が分断されてしまう問題に対しての良いアプローチになりそうですね。
ご質問等はTwitter、Linkedinへよろしくお願いします。