1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Power BI カスタムビジュアル開発 : 積み上げ棒グラフの開発 : プロジェクト作成とデータの定義

Last updated at Posted at 2020-03-17

この記事では積み上げ棒グラフの開発について見ていきます。カスタムビジュアル開発の基本については カスタムビジュアル開発入門 を参照してください。

尚、積み上げ棒グラフとは以下のようなグラフです
image.png

今回は積み上げ棒グラフに必要なデータ構造の検討と実装を行います。

ソリューションの作成

1. pbiviz を使ってソリューションを作成。

pbiviz new MyStackedBarChart
cd MyStackedBarChart

2. Visual Studio Code で開き、カスタムビジュアルを実行。

code .
pbiviz start

3. カスタムビジュアルが動作することを確認。
image.png

積み上げ棒グラフの作り方を検討

まずデータは以下のように日付、商品、数列があるとします。
image.png

Y 座標

上記のデータを積み上げにしたい場合、例えばとあるグラフの高さを 300 とすると以下のようになります。

一見一番上の 76 が分かれば計算できるように見えますが、実際は下からの合計値が必要です。これは棒が 2 つ以上になった場合、必ずしもすべての棒が Y 座標 0 から始まらないためです。

よって下からの積み上げ合計をもって Y 座標を計算します。上図の?の計算は 3 月の合計が 218 であった場合、
300-218/364*300≒120 となります。もし 4 月より合計値が高いデータがある場合、計算に利用する 364 が変わります。

X 座標

次に X 座標を考えます。これは集計するデータの分類数に依存します。
image.png
image.png

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 つです。
image.png

また Power BI から受け取るデータの形式ですが、最終的にデータを成型できればいいため、今回は matrix を使ってみます。
Capabilities.json の中身を書き換え。

  • conditions で受け入れる数を制限
capabilities.json
{
    "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 を追加。
image.png

2. カスタムビジュアルが引き続き動くこととフィールドが指定できることを確認。
image.png

3. F12 キーを押下して開発者ツールを起動。ビジュアルを更新したらブレークポイントがヒットすることを確認。
image.png

4. コンソールで options.dataView[0] の中身を確認。
matrix.columns.root.children に凡例の情報が格納
image.png
matrix.rows.root.children に月ごとの集計が格納
image.png

データの変換

最後に 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);

3. 再度デバッグを実行してデータを確認。
image.png
image.png

まとめ

今回はどのようなデータ構造が必要かを検討して実装しました。次回はグラフを描画します。

次の記事へ
目次へ戻る

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?