この記事では積み上げ棒グラフの開発について見ていきます。カスタムビジュアル開発の基本については カスタムビジュアル開発入門 を参照してください。
今回は積み上げ棒グラフに必要なデータ構造の検討と実装を行います。
ソリューションの作成
1. pbiviz を使ってソリューションを作成。
pbiviz new MyStackedBarChart
cd MyStackedBarChart
2. Visual Studio Code で開き、カスタムビジュアルを実行。
code .
pbiviz start
積み上げ棒グラフの作り方を検討
Y 座標
上記のデータを積み上げにしたい場合、例えばとあるグラフの高さを 300 とすると以下のようになります。
一見一番上の 76 が分かれば計算できるように見えますが、実際は下からの合計値が必要です。これは棒が 2 つ以上になった場合、必ずしもすべての棒が Y 座標 0 から始まらないためです。
よって下からの積み上げ合計をもって Y 座標を計算します。上図の?の計算は 3 月の合計が 218 であった場合、
300-218/364*300≒120 となります。もし 4 月より合計値が高いデータがある場合、計算に利用する 364 が変わります。
X 座標
次に X 座標を考えます。これは集計するデータの分類数に依存します。
1 つの要素が持つべき値
X,Y それぞれを決めて各四角を描写するためには、それぞれの要素に以下の情報が必要です。
自身の数値とそれまでに積まれた箱の合計: 自身の Y 座標を決めるために必要
自身の数値: 数表示するために必要
商品名: 自身の分類を認識し、色付けするために必要
日付: X 座標を決めるのに必要
またグラフ全体としては以下のデータが必要です。
各月合計の最大値: 棒グラフ自体の Y 座標を決めるために必要
すべての要素: 上記要素をデータ数分
これを踏まえ、以下インターフェースを visual.ts に追加します。
interface StackedBarChartViewModel {
dataPoints: StackedBarChartDataPoint[];
maxValue: number; // 各月合計の最大値
}
interface StackedBarChartDataPoint {
axis: string; // 日付
legend: string; // 商品名
value: number; // 自分の数
value2: number; // 積み上げた数
}
必要な項目と受け取るデータの形式
ユーザーに指定してほしい項目は「軸」、「凡例」、「値」の 3 つです。
また Power BI から受け取るデータの形式ですが、最終的にデータを成型できればいいため、今回は matrix を使ってみます。
Capabilities.json の中身を書き換え。
- conditions で受け入れる数を制限
{
"dataRoles": [
{
"displayName": "軸",
"name": "axis",
"kind": "Grouping"
},
{
"displayName": "凡例",
"name": "legend",
"kind": "Grouping"
},
{
"displayName": "値",
"name": "measure",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"conditions": [
{
"axis": {
"max": 1
},
"legend": {
"max": 1
},
"measure": {
"max": 1
}
}
],
"matrix": {
"rows": {
"for": {
"in": "axis"
}
},
"columns": {
"for": {
"in": "legend"
}
},
"values": {
"select": [
{
"for": {
"in": "measure"
}
}
]
}
}
}
]
}
デバッグでデータを確認
最後にどのようにデータが返ってくるか確認します。
1. visual.ts の update 関数に debugger を追加。
2. カスタムビジュアルが引き続き動くこととフィールドが指定できることを確認。
3. F12 キーを押下して開発者ツールを起動。ビジュアルを更新したらブレークポイントがヒットすることを確認。
4. コンソールで options.dataView[0] の中身を確認。
matrix.columns.root.children に凡例の情報が格納
matrix.rows.root.children に月ごとの集計が格納
データの変換
最後に Power BI より受け取ったデータを定義した型に変換する関数を追加します。
1. Visual クラスに以下関数を追加。
private converData(options: VisualUpdateOptions): StackedBarChartViewModel {
let dataViews = options.dataViews;
let dataModel: StackedBarChartViewModel = {
dataPoints: [],
maxValue: 0
}
if (!this.checkDataset(dataViews)) return dataModel;
let columns = dataViews[0].matrix.columns.root.children;
let rows = dataViews[0].matrix.rows.root.children;
let maxValue = 0;
let dataPoints: StackedBarChartDataPoint[] = [];
rows.forEach(row => {
let maxInAxis = 0;
let axisName = <string> row.value;
for (let key of Object.keys(row.values)) {
let value = <number> row.values[key].value;
maxInAxis += value;
let dataPoint: StackedBarChartDataPoint = {
axis: axisName,
legend: <string> columns[key].value,
value: value,
value2: maxInAxis,
};
dataPoints.push(dataPoint);
}
maxValue = Math.max(maxValue, maxInAxis);
});
dataModel.dataPoints = dataPoints;
dataModel.maxValue = maxValue;
return dataModel;
}
private checkDataset(dataViews: powerbi.DataView[]): boolean {
if (!dataViews
|| !dataViews[0]
|| !dataViews[0].matrix
|| !dataViews[0].matrix.columns
|| !dataViews[0].matrix.columns.root
|| !dataViews[0].matrix.columns.root.children
|| !dataViews[0].matrix.rows
|| !dataViews[0].matrix.rows.root
|| !dataViews[0].matrix.rows.root.children
) {
return false;
}
return true;
}
2. update 関数の debugger; 直後に以下コードを追加。
let viewModel = this.converData(options);
まとめ
今回はどのようなデータ構造が必要かを検討して実装しました。次回はグラフを描画します。