ユースケース開発Workshop可視化ウィジェットXYチャート

注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。

グラフ XY

グラフ XY ウィジェットで必要な機能や書式設定を実現できない場合は、Vega Chart ウィジェットの使用を検討してください。

グラフ XY ウィジェットは、オブジェクトをインタラクティブなグラフとして可視化するために使用します。グラフ XY ウィジェットを設定するモジュール作成者は、次のことができます。

  • データを棒グラフ、折れ線グラフ、散布図として表示する。
  • 可視化するプロパティ、プロパティの集計方法(例:件数、合計、平均)、およびプロパティをセグメント化するかどうかとその方法を選択する。
  • 関数ベースのレイヤーを使用して、より高度な集計の種類やグラフを表示する。
  • グラフのタイトル、軸、凡例、数値の書式設定に関する表示オプションを設定する。
  • グラフ上での選択と下流のフィルタリングを有効にする。

以下のスクリーンショットは、Flight Alerts データを表示する、設定済みの3個のグラフ XY ウィジェットの例です。

chart_xy_empty_state.png

設定オプション

以下の画像では、青い矢印の左側に、新しく追加された(まだ設定されていない)グラフ XY ウィジェットと、その初期設定パネルが表示されています。青い矢印の右側には、元データとなる Flight Alerts のオブジェクトセットがすでに入力された、個別のレイヤー設定パネルが表示されています。

chart_xy_empty_state.png

レイヤーの設定オプション

グラフ XY ウィジェットにデータを追加するには、レイヤーの設定が必要です。レイヤーでは、次の設定オプションを利用できます。

  • タイトル
    • 設定パネル内で現在のレイヤーのタイトルを設定します。
    • 注:このタイトルはモジュールのユーザーには表示されませんが、作成者が複数のレイヤーを使用する複雑なグラフ XY の設定を整理、管理するために使用します。
  • データ入力
    • このレイヤーの入力データを制御します。
    • オブジェクトセットの選択肢では、Workshop のオブジェクトセット変数を入力として使用できます。
    • 関数集計の選択肢では、2D 集計または3D 集計を返す関数を入力として使用できます。
      • 注:関数集計レイヤーでは、以下のレイヤー設定オプションの一部のみを利用できます。
    • 時系列セットの選択肢では、Workshop の時系列セット変数を入力として使用できます。時系列セット変数の詳細については、変数を参照してください。これにより、X 軸に時間範囲、Y 軸に変数の時系列値を配置した時系列グラフが設定されます。
  • レイヤータイプ
    • 表示するグラフの種類を選択します。現在の選択肢には、棒グラフ、折れ線グラフ、散布図があります。データ入力が時系列セットの場合、折れ線グラフの選択肢のみがサポートされます。時系列セット変数の詳細については、変数を参照してください。
  • 面積のオプション
    • 折れ線グラフに対して、3つの可視化の選択肢があります。
      • 「折れ線」(単純な折れ線グラフを表示します)、
      • 「面積」(折れ線グラフを描画し、各折れ線の下の領域を塗りつぶします)、
      • 「積み上げ」(「面積」の選択肢に似ていますが、セグメント化されたグラフの値を積み重ねて表示します)。
    • 面積のオプションは、折れ線グラフでのみ利用できます。
  • ラベル
    • グラフ上の値ラベルの表示を切り替えます。
    • このオプションは、現在、棒グラフと折れ線グラフで利用できます。
  • X 軸のプロパティ
    • グラフにプロットするプロパティタイプを決定します。
  • 棒 / 折れ線 / グラフの系列
    • 単一 / 複数の系列を使用
      • 選択した X 軸のプロパティに対して、1個以上のグラフ系列をプロットできます。
      • たとえば、X 軸のプロパティとして「Alert Type」を選択した場合、複数の系列を使用すると、「Alert Type」ごとの件数と、「Alert Type」ごとの「# of Hours Delayed」の合計の両方をプロットできます。
    • 系列の集計
      • グラフにプロットする各値の集計方法を決定します。
      • デフォルトでは、「件数」に設定されています。
      • ほかの選択肢には、「平均」、「最小値」、「最大値」、「合計」、「近似一意件数」があります。
    • セグメント
      • 任意です。
      • プロットする各値を、2つ目のプロパティタイプでセグメント化できます。
      • たとえば、棒グラフで X 軸のプロパティとして「Alert Type」を選択し、セグメントの選択肢として「Aircraft Type」を選択すると、各棒に「Alert Type」ごとのオブジェクト件数が「Aircraft Type」ごとにセグメント化されて表示されます。
    • Null 値/欠損値の表示
      • 折れ線グラフでのみ利用できます。
      • 折れ線グラフで null 値や欠損値をどのように表示するかを制御します。
      • 選択肢は、「間隔」(欠損値をプロットされた折れ線の空白として表示)、「無視」(欠損値を無視し、プロットされた折れ線で前後の利用可能な値を接続)、または「ゼロ」(欠損値を「0」と同等の値として扱う)です。
    • 表示の上書き
      • 任意です。
      • 現在の系列の凡例表示名を上書きします。
      • セグメント化されたグラフでは、単一セグメントの凡例表示名を上書きします。
    • セグメントの上書き
      • 棒グラフでのみ利用できます。
      • 棒グラフの各値の表示方法を変更します。
      • 選択肢には、「積み上げ」、「割合」、「グループ化」があります。
  • 選択をフィルターとして使用
    • 任意で、オブジェクトセットを元データとするグラフでのみ利用できます。
    • 設定すると、出力のオブジェクトセットフィルター変数を介して、このグラフレイヤーでの選択と下流のウィジェットのフィルタリングが可能になります。
  • レイヤーの削除
    • 現在のグラフレイヤーを削除できます。
  • シナリオ
    • シナリオと比較
      • この切り替えを有効にすると、比較するデータが含まれるシナリオ配列変数を選択できます。これにより、グラフの「セグメント」軸を使用して、テーブル内のデータと配列内のシナリオの値が比較されます。
      • このオプションを有効にすると、ほかのプロパティでセグメント化することはできません。
      • 単一のレイヤー内で比較するシナリオには色が自動的に割り当てられ、レイヤーの色設定はそのレイヤー内のすべてのシナリオに適用されます。シナリオごとの色を制御するには、シナリオごとに異なる色を設定するの説明に従い、シナリオごとに別のレイヤーを設定し、各レイヤーでシナリオからデータを読み込むを有効にします。
    • シナリオの詳細については、シナリオのドキュメントを参照してください。

実行時の設定オプション

グラフ XY の一部の設定オプションは、ウィジェットの設定パネルではなく、実行時にグラフのツールバーから利用できます。

タイムスタンプのバケットサイズ

グラフレイヤーで日付またはタイムスタンプのプロパティを X 軸のプロパティとして使用し、関数ベースではなく基本集計を使用している場合、実行時にグラフのツールバーに歯車(設定)ボタンが表示されます。このボタンは、これらの条件を満たす場合にのみ表示されます。このアイコンを選択すると、バケットサイズのセレクターが開き、タイムスタンプ値を日、週、月などの単位でどのようにグループ化するかを設定できます。

チャート全体の設定オプション

上記のレイヤーの設定オプションに加えて、Chart XY のメイン設定パネルには、チャート全体の設定オプションがあります。

  • カテゴリ軸
    • タイトルを表示

      • 有効にすると、カテゴリ軸のタイトルが表示され、このタイトルを上書きできるようになります。
      • デフォルトでは、チャートの系列内にプロットされているプロパティタイプがタイトルに表示されます。
    • 数値の形式設定の有効化

      • 有効にすると、カテゴリ軸のキーに表示される数値の設定オプションが利用可能になります。
      • 設定オプションには、数値の桁区切り、表示する小数桁数の最小値/最大値、科学的表記法などがあります。
    • 並べ替え

      • チャートに表示する各値の並べ替えロジックを制御します。
      • デフォルトでは、カテゴリーキーをアルファベット順(A から Z)に並べ替えます。
      • ほかの選択肢には、値による並べ替え(昇順または降順)とカスタムの並べ替えがあります。
      • カテゴリーの順序をカスタムで定義するには、プロパティに数値の並べ替え値を割り当て、そのプロパティを並べ替えのメトリクスとして選択します。
  • 値軸
    • 複数の値軸を使用
      • 複数のチャート系列が設定されている場合にのみ利用可能で、系列ごとに値軸を設定できます。これは、チャート上の系列間で値のスケールが大きく異なる場合に役立ちます。
    • タイトルを表示
      • 有効にすると、値軸のタイトルが表示され、このタイトルを上書きできるようになります。
      • デフォルトでは、チャートの系列内で使用されている集計の種類がタイトルに表示されます。
    • 数値の形式設定の有効化
      • 有効にすると、値軸に表示される数値の設定オプションが利用可能になります。
      • 設定オプションには、数値の桁区切り、表示する小数桁数の最小値/最大値、科学的表記法などがあります。
    • スケールのタイプ
      • 値軸のスケールを「線形」(デフォルト)または「対数」に設定できます。
    • 下限
      • デフォルトでは、表示されているチャートの値に基づいて「下限を自動計算」に設定されています。
      • 「最小値」に切り替えると、モジュールの作成者が値軸に表示される最小値を制御できます。
    • 上限
      • デフォルトでは、表示されているチャートの値に基づいて「上限を自動計算」に設定されています。
      • 「最大値」に切り替えると、モジュールの作成者が値軸に表示される最大値を制御できます。
  • 凡例
    • 凡例を表示
      • チャートの系列のタイトルと色を示す凡例の表示を切り替えます。
    • 配置オプション
      • 「凡例を表示」が有効な場合、チャート内の凡例の配置を制御します。
  • 棒の向き
    • 横方向/縦方向の切り替え
      • チャートの向きを制御します。
      • 棒グラフでは、「横方向」がデフォルトです。
      • 折れ線グラフまたは散布図では、「縦方向」のみ使用できます。

関数による集計(関数ベースのレイヤー)

関数ベースのレイヤーを設定するには、TwoDimensionalAggregation または ThreeDimensionalAggregation を返す関数を記述する必要があります。

このセクションのコード例は、TypeScript v1、TypeScript v2、Python で利用できます。関数のバージョンに対応するタブを選択します。続く2つの具体例は TypeScript のみで示しています。Python で記述する場合は、Python 関数でカスタム集計を作成するに沿って進めてください。TypeScript v1 では、エクスポートされたクラスのメソッドとして各関数を定義し、@foundry/functions-api の @Function() デコレーターを付けます。TypeScript v2 では、各関数をファイルのデフォルトエクスポートとして定義し、@osdk/functions から型をインポートします。詳しい比較については、TypeScript v1 と TypeScript v2 の比較を参照してください。

集計の戻り値の形式

どの関数バージョンにも、次の型パラメーターを持つ2つの集計型が存在します:TwoDimensionalAggregation<Key, Value> と ThreeDimensionalAggregation<Key, Segment, Value>。ただし、TypeScript v1 ではバケットをオブジェクトの buckets キーの下に格納するのに対し、TypeScript v2 ではバケットの配列をそのまま返します。3次元集計では、TypeScript v2 は内側の各バケット配列も value キーではなく groups キーの下に格納します。Python ではラッパーを保持し、functions.api の SingleBucket クラスと NestedBucket クラスから構築します。これらの違いが適用されるのは、関数本文内で構築するリテラルのみです。宣言された戻り値の型が同じであれば、どのバージョンでも同じ出力にシリアライズされるため、移行後にウィジェットを変更する必要はありません。TypeScript v1 の { buckets: ... } リテラルが残っていると、TypeScript v2 の配列型の ThreeDimensionalAggregation を満たさないため、関数内で失敗します。

次の最小限の関数は、各バージョンで同じ2次元集計を返します。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 import { Double, Function, TwoDimensionalAggregation } from "@foundry/functions-api"; export class MyFunctions { @Function() public myTwoDimensionalAggregation(): TwoDimensionalAggregation<string, Double> { return { buckets: [ { key: "bucket1", value: 5.0 }, { key: "bucket2", value: 6.0 }, ], }; } }
Copied!
1 2 3 4 5 6 7 8 9 10 import { Double, TwoDimensionalAggregation } from "@osdk/functions"; function myTwoDimensionalAggregationFunction(): TwoDimensionalAggregation<string, Double> { return [ { key: "bucket1", value: 5.0 }, { key: "bucket2", value: 6.0 }, ]; } export default myTwoDimensionalAggregationFunction;
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from functions.api import ( function, Double, TwoDimensionalAggregation, SingleBucket ) @function def my_two_dimensional_aggregation_function() -> TwoDimensionalAggregation[str, Double]: return TwoDimensionalAggregation( buckets=[ SingleBucket(key="bucket1", value=Double(5.0)), SingleBucket(key="bucket2", value=Double(6.0)), ] )

3次元集計では、最上位の各バケット内に2つ目のバケットリストをネストします。TypeScript v1 では、最上位のバケットを buckets キーの下に格納し、ネストされたリストを value の下に格納します。TypeScript v2 では両方の階層が変わります。配列をそのまま返し、最上位の各エントリーはネストされたリストを groups の下に格納するため、value がキーになるのは最も内側の階層のみです。Python では、最上位の各バケットは NestedBucket であり、その buckets 引数に内側の SingleBucket リストを格納します。各型の完全な形式については、集計型のリファレンスを参照してください。

2次元集計の例

TypeScript v1 では、グループ化された集計の結果自体が TwoDimensionalAggregation であるため、.groupBy(...).sum(...) を直接返すことができます。TypeScript v2 ではそうではありません。.aggregate() はグループごとに1行のフラットな行配列を返し、それらの行を TwoDimensionalAggregation に変換するヘルパーはありません。.aggregate() 呼び出しに集計型の型注釈を付けると型エラーになるため、関数自体で行から戻り値を構築する必要があります。各グループの値は row.$group.<groupByKey> から、メトリクスは row.<propertyApiName>.sum から読み取ります。このメトリクスはプロパティの null 許容性を引き継ぐため、未定義になる可能性があります。

以下の TypeScript v2 の例には、さらに3つの違いが反映されています。

  • TypeScript v1 のバケットキーには、min と max を持つ IRange<Timestamp> を使用します。TypeScript v2 でこれに相当するのは、startValue と endValue を持つ Range<TimestampISOString> です。関数の型である Range と、[start, end] タプルの配列であるグループ化入力 $ranges を混同しないでください。
  • $duration のグループ値は範囲ではなく、バケットの開始を示す単一のスカラー値であるため、この例では1日単位の各バケットの終了を独自に導出します。集計対象のプロパティに値がない場合はメトリクスが存在しないため、各メトリクスに ?? 0 のデフォルト値が必要です。
  • 各 $select エントリーの "unordered" 値は、結果の行順序が定義されていないことを意味し、別々の2回の .aggregate() 呼び出しで、グループが同じ順序で返される保証はありません。そのため、この例では位置ではなくグループ値に基づいて、分子と分母の結果を結合します。

TypeScript v2 の関数にはクラスがないため、TypeScript v1 の private divide メソッドは、TypeScript v2 では同じファイル内のモジュールレベルの関数になります。

以下は、ある時系列を別の時系列で割った結果をチャートに表示するために、TwoDimensionalAggregation を返す完全な例です。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import { Double, Function, TwoDimensionalAggregation, ThreeDimensionalAggregation, IRange, Timestamp } from "@foundry/functions-api"; import { ObjectSet, MyObjectType } from "@foundry/ontology-api" export class TimeseriesAggregations { @Function() public async percentOfTotal(objects:ObjectSet<MyObjectType>): Promise<TwoDimensionalAggregation<IRange<Timestamp>, Double>> { const numerators = await objects.groupBy(e => e.date.byDays()) .sum(e => e.value); const denominators = await objects.groupBy(e => e.date.byDays()) .sum(e => e.total); return this.divide(numerators, denominators); } private divide(numerators:TwoDimensionalAggregation<IRange<Timestamp>, Double>, denominators: TwoDimensionalAggregation<IRange<Timestamp>, Double>): TwoDimensionalAggregation<IRange<Timestamp>, Double> { const percentage = numerators.buckets.map((bucket, i) => { const numerator = bucket.value; const denominator = denominators.buckets[i].value; if (denominator == 0) { return { key: bucket.key, value: 0 }; } return { key: bucket.key, value: numerator / denominator } }); return { buckets: percentage }; } }
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import { ObjectSet } from "@osdk/client"; import { Double, Range, TimestampISOString, TwoDimensionalAggregation } from "@osdk/functions"; import { MyObjectType } from "@ontology/sdk"; const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000; // $duration のグループ値はバケットの開始のみを示すため、Range キーとして使用するには、 // 1日単位のバケットの終了を算出する必要があります。 function toDayRange(start: Date): Range<TimestampISOString> { const end = new Date(start.getTime() + ONE_DAY_IN_MS); return { startValue: start.toISOString(), endValue: end.toISOString() }; } function divide( numerators: TwoDimensionalAggregation<Range<TimestampISOString>, Double>, denominators: Map<string, Double> ): TwoDimensionalAggregation<Range<TimestampISOString>, Double> { return numerators.map(bucket => { const numerator = bucket.value; const denominator = denominators.get(bucket.key.startValue!) ?? 0; if (denominator === 0) { return { key: bucket.key, value: 0 }; } return { key: bucket.key, value: numerator / denominator }; }); } async function percentOfTotal( objects: ObjectSet<MyObjectType> ): Promise<TwoDimensionalAggregation<Range<TimestampISOString>, Double>> { const numeratorRows = await objects.aggregate({ $select: { "value:sum": "unordered" }, $groupBy: { date: { $duration: [1, "days"] } }, }); const denominatorRows = await objects.aggregate({ $select: { "total:sum": "unordered" }, $groupBy: { date: { $duration: [1, "days"] } }, }); const numerators = numeratorRows .filter(row => row.$group.date != null) .map(row => ({ key: toDayRange(new Date(row.$group.date!)), value: row.value.sum ?? 0, })); // 2つの集計には順序がなく、グループが異なる順序で返される可能性があるため、 // 行の位置ではなくバケットの開始をキーにします。 const denominators = new Map<string, Double>( denominatorRows .filter(row => row.$group.date != null) .map(row => [new Date(row.$group.date!).toISOString(), row.total.sum ?? 0]), ); return divide(numerators, denominators); } export default percentOfTotal;

3次元集計の例

TypeScript v1 では、.segmentBy() によって2つ目の集計次元を生成します。TypeScript v2 には独立したセグメント句がありません。利用可能な構文で最も近いものは、同じ $groupBy オブジェクト内の2つ目のキーであり、以下の例ではこれを使用しています。複数キーの $groupBy は、各日付バケット内にセグメントをネストするのではなく、両方のキーで同時にグループ化します。$groupBy に2個以上のキーが含まれると、並べ替えは許可されなくなり、すべての $select 値を "unordered" にする必要があります。結果は引き続きフラットな行配列であり、グループ値の組み合わせごとに1行になります。TypeScript v2 の例では、行を返す前に対応する日付バケットの下にネストし、位置ではなくグループ値に基づいて分子と分母の結果を結合します。

TypeScript v1 の .topValues() は、TypeScript v2 の "exact" 戦略に対応しますが、デフォルトのバケット数は増加しています。TypeScript v1 では1,000、TypeScript v2 では10,000です。グループ化が正確であるのは、プロパティの一意の値の数がこの件数以内に収まる間のみです。この件数を超えると、返されるグループからオブジェクトが除外され、集計は近似になります。プラットフォームは各結果が正確だったか近似だったかを報告しますが、TypeScript のオントロジー SDK はそのフィールドを公開していません。カーディナリティの高いプロパティでは、{ $exactWithLimit: n } を使用して件数を増やします。

以下は、segmentBy() が返す値ごとに別々の系列をチャートに表示する ThreeDimensionalAggregation を返す完全な例です。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import { Double, Function, TwoDimensionalAggregation, ThreeDimensionalAggregation, IRange, Timestamp } from "@foundry/functions-api"; import { ObjectSet, MyObjectType } from "@foundry/ontology-api" export class TimeseriesAggregations { @Function() public async percentOfTotalSegmented(objects:ObjectSet<MyObjectType>): Promise<ThreeDimensionalAggregation<IRange<Timestamp>, string, Double>> { const numerators = await objects.groupBy(e => e.date.byDays()) .segmentBy(e => e.groupId.topValues()) .sum(e => e.value); const denominators = await objects.groupBy(e => e.date.byDays()) .segmentBy(e => e.groupId.topValues()) .sum(e => e.total); return this.divideThreeDimensional(numerators, denominators); } private divideThreeDimensional(numerators:ThreeDimensionalAggregation<IRange<Timestamp>, string, Double>, denominators: ThreeDimensionalAggregation<IRange<Timestamp>, string, Double>): ThreeDimensionalAggregation<IRange<Timestamp>, string, Double> { var percentage = numerators.buckets; //コピー for (let i = 0; i < numerators.buckets.length; i++) { for (let j = 0; j < numerators.buckets[i].value.length; j++) { percentage[i].value[j].value = numerators.buckets[i].value[j].value / denominators.buckets[i].value[j].value; } } return { buckets: percentage }; } }
Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 import { ObjectSet } from "@osdk/client"; import { Double, Range, ThreeDimensionalAggregation, TimestampISOString } from "@osdk/functions"; import { MyObjectType } from "@ontology/sdk"; const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000; // $duration のグループ値はバケットの開始のみを示すため、Range キーとして使用するには、 // 1日単位のバケットの終了を算出する必要があります。 function toDayRange(start: Date): Range<TimestampISOString> { const end = new Date(start.getTime() + ONE_DAY_IN_MS); return { startValue: start.toISOString(), endValue: end.toISOString() }; } // aggregate() は日付とセグメントの組み合わせごとにフラットな行を1行返すため、 // ネストされた3次元の形式に合わせるには、行を再グループ化する必要があります。 function nestSegmentsByDate( rows: Array<{ date: Date; segment: string; value: Double }> ): ThreeDimensionalAggregation<Range<TimestampISOString>, string, Double> { const byDate = new Map<number, Array<{ key: string; value: Double }>>(); for (const row of rows) { const segments = byDate.get(row.date.getTime()) ?? []; segments.push({ key: row.segment, value: row.value }); byDate.set(row.date.getTime(), segments); } return Array.from(byDate, ([start, groups]) => ({ key: toDayRange(new Date(start)), groups, })); } function divideThreeDimensional( numerators: ThreeDimensionalAggregation<Range<TimestampISOString>, string, Double>, denominators: Map<string, Double> ): ThreeDimensionalAggregation<Range<TimestampISOString>, string, Double> { return numerators.map(bucket => ({ key: bucket.key, groups: bucket.groups.map(segment => { const denominator = denominators.get(`${bucket.key.startValue}|${segment.key}`) ?? 0; return { key: segment.key, value: denominator === 0 ? 0 : segment.value / denominator, }; }), })); } async function percentOfTotalSegmented( objects: ObjectSet<MyObjectType> ): Promise<ThreeDimensionalAggregation<Range<TimestampISOString>, string, Double>> { const numeratorRows = await objects.aggregate({ $select: { "value:sum": "unordered" }, $groupBy: { date: { $duration: [1, "days"] }, groupId: "exact", }, }); const denominatorRows = await objects.aggregate({ $select: { "total:sum": "unordered" }, $groupBy: { date: { $duration: [1, "days"] }, groupId: "exact", }, }); const numerators = nestSegmentsByDate( numeratorRows .filter(row => row.$group.date != null) .map(row => ({ date: new Date(row.$group.date!), segment: row.$group.groupId, value: row.value.sum ?? 0, })), ); // 2つの集計には順序がなく、グループが異なる順序で返される可能性があるため、 // 行の位置ではなく日付とセグメントをキーにします。 const denominators = new Map<string, Double>( denominatorRows .filter(row => row.$group.date != null) .map(row => [ `${new Date(row.$group.date!).toISOString()}|${row.$group.groupId}`, row.total.sum ?? 0, ]), ); return divideThreeDimensional(numerators, denominators); } export default percentOfTotalSegmented;

Python では、functions.api の TwoDimensionalAggregation クラスと ThreeDimensionalAggregation クラスを使用して、同じチャートを記述します。Python のオントロジー SDK には、TypeScript v2 にはない変換機能もあり、Python のオントロジー SDK の v2 を使用する場合にのみサポートされます。TwoDimensionalAggregation.from_osdk() と ThreeDimensionalAggregation.from_osdk(result, "date", "groupId") は、グループ化された集計結果をウィジェットが想定するバケット構造に変換します。どちらもグループ化に使用するプロパティのAPI名を受け取ります。このAPI名は、周囲の Python 識別子が snake_case であっても、camelCase のままです。Python の例については、Python 関数でカスタム集計を作成するを参照してください。

TSv1 のその他の例については、Functions ドキュメントのオブジェクトセットの集計とカスタム集計を作成するを参照してください。