インテージテクノスフィア技術ブログ

株式会社インテージテクノスフィアの社員達がシステム開発や仕事に関する技術情報を随時掲載いたします

【Tableau】ユーザーのことを知りたい! - Tabeau JS API -

こんにちは、アイダです。 利用者の操作をTableau JS API (Tableau JavaScript API)を使って取得することで、開発側はよりユーザー行動を把握することができるようになります。

ユーザーを理解し、ニーズを探るための第一歩として、Tableau JS API 活用例を投稿してもらいました。それではOさん、どうぞ。

f:id:intage-tech:20210708090458p:plain

はじめに

こんにちは。 Oです。

文章を書くのがあまり得意ではないので、気分がのったときに一気に書きたい派です。

これまで、Tableau JS API に関して2本の記事を投稿しました。

www.intage-ts.com

www.intage-ts.com

今回はこれらの知識を組み合わせて、実業務でありそうなことを試してみようと思います。

Tableau を Web アプリケーションに組み込むということは、
そのアプリを通じてユーザーが Tableau を操作することです。

ダッシュボードを表示したり、複数のチャートを見比べたり、フィルター操作をしたり...

開発・運営する側としては、ユーザーが何を見たのか・どんな操作をしたのかを知りたいですよね。
なので、Tableau JS API を通じて把握できる、ユーザー操作をいくつかご紹介します。

やりたいこと

ユーザーのことは全部知りたい! そんな気持ちを押さえて、Tableau JS でできそうなことをピックアップしてみました。

  1. どのグラフを見たのか、ワークブック名・シート名が知りたい
  2. タブの切り替えをしたのか、どのタブを見たのか
  3. どの項目で、フィルター操作をしたのか
  4. どのグラフで、詳細情報を見たのか

使うもの

以前のブログ をご参考ください。

Tableau Javascript API
公式: Tableau Javascript API Reference

tableau-api-js(npmライブラリ)
参考:https://www.npmjs.com/package/tableau-api-js

さっそく

まずはやりたいことをよく見てみましょう。

1 で知りたいワークブック名は Workbook クラス から、シート名は Sheet クラスから getName() で取得できそうです。

2~4 は、ユーザー操作をトリガーとしたイベントなので、onFirstInteractive(e) で検知して、 イベントごとに情報を取得する処理を書いてあげればよいですね。
参考)Viz Event Classes - TableauEventName

onFirstInteractive(e) については、以前のブログに書いているので、ご参考ください。

では1つずつ見ていきます。

1.どのグラフを見たのか、ワークブック名・シート名が知りたい

前述の通り、Tableau JS では Viz が一番外側で扱うクラスです。
階層構造的には、 Viz → Workbook → Sheet なので、順番に情報を取得すれば、目的に辿り着けます。

名前を取得メソッドは、 getName() です。

// ワークブック 情報を取得
const workbook =  viz.getWorkbook();
// ワークブック名を取得
const workbookName = workbook.getName();
// 現在表示されているシート(アクティブシート)の情報を取得
const activeSheet = workbook.getActiveSheet();
// シート名を取得!!
const sheetName = activeSheet.getName();
 
console.log(`ワークブック名 ${workbookName}`);
console.log(`シート名 ${sheetName}`);

2.タブの切り替えをしたのか、どのタブを見たのか

タブ(ワークブックにおけるシート)の切り替えは、TAB_SWITCH イベントを検知することで、情報を取得できます。

onFistInteractive 内にイベントリスナー用意して、TAB_SWITCH を検知したら onTabSwitch メソッドが呼ばれるように設定します。

// タブ切替イベント
viz.addEventListener(
    Tableau.TableauEventName.TAB_SWITCH,
    onTabSwitch,
);

onTabSwitch では、階層構造(Viz → Workbook → Sheet)をたどって、シート名(タブ名)を取得します。

// タブ切替
const onTabSwitch = (e:any) => {
    const viz = e.getViz();
    const workbook = viz.getWorkbook();
    const activeSheet = workbook.getActiveSheet();
    const sheetName = activeSheet.getName();
    console.log(`タブが変更されました。${sheetName}`);
};

3.どの項目で、フィルター操作をしたのか

3,4は 2とほぼ同じです。どんどん行きましょう。

フィルター操作の情報は、FILTER_CHANGE イベントで 取得します。

onFistInteractive 内にイベントリスナー用意して、FILTER_CHANGE を検知したら onFilterChange メソッドが呼ばれるように設定します。

// フィルター変更イベント
viz.addEventListener(
    Tableau.TableauEventName.FILTER_CHANGE,
    onFilterChange,
);

onFilterChange では、イベントの引数(e)から直接情報が取得できるので、フィルターが発生したフィールド名を取得しましょう。

参考)FilterEvent Class

// フィルター変更
const onFilterChange = (e:any) => {
    const fieldName = e.getFieldName();
    console.log(`フィルターが変更されました。${fieldName}`);
};

さらに、getFilterAsync() メソッドを使うと、フィルターで設定した値まで取得できます。

4.どのグラフで、詳細情報を見たのか

グラフ上でオブジェクトをクリックすると、選択状態になり、詳細情報を見ることができます。

f:id:intage-tech:20210629164519p:plain

このユーザー操作は、MARKS _SELECTION イベントで 取得することができます。

onFistInteractive 内にイベントリスナー用意して、MARKS _SELECTION を検知したら onMarksSelection メソッドが呼ばれるように設定します。

// オブジェクト選択イベント
viz.addEventListener(
    Tableau.TableauEventName.MARKS_SELECTION,
    onMarksSelection,
);

onMarksSelection では、イベントの引数(e)からシート名を取得することができます。

参考)MarksEvent Class

さらに、getMarksAsync() メソッドを使うと、具体的にどのマーク(日付や数値)を選択したのかという情報も取得することができます。

// オブジェクト選択
const onMarksSelection = (e:any) => {
    const sheetName = e.getWorksheet().getName();
    console.log(`選択されたオブジェクトが存在するシート名 ${sheetName}`);
    e.getMarksAsync().then((marks:any) => {
        marks.forEach((v:any) => {
            console.log(v.getPairs().get('<フィールド名>'));
        });
    });
};

最終的なソースコード

1~4を合わせると、こんな感じになりました。

※ React のコンポーネント部分は省略しています。

クリックすると展開され、ソースコードが表示されます

const initViz = () => {
    // Tableauを埋め込む要素を取得
    const containerDiv:any = document.getElementById('vizContainer');
    // URL
    const vizUrl = 'https://public.tableau.com/shared/W2Y96S62M';   // TableauPublic からお借りしました
    // 描画オプション生成
    const options = {
        width: containerDiv.offsetWidth,
        height: 700,
 
        onFirstInteractive: (e:any) => {
            console.log('First Interactive!');
 
            // ワークブック 情報を取得
            const workbook =  viz.getWorkbook();
            // ワークブック名を取得
            const workbookName = workbook.getName();
            // 現在表示されているシート(アクティブシート)の情報を取得
            const activeSheet = workbook.getActiveSheet();
            // シート名を取得!!
            const sheetName = activeSheet.getName();
 
            console.log(`ワークブック名 ${workbookName}`);
            console.log(`シート名 ${sheetName}`);
 
            // タブ切替イベント
            viz.addEventListener(
                Tableau.TableauEventName.TAB_SWITCH,
                onTabSwitch,
            );
            // フィルター変更イベント
            viz.addEventListener(
                Tableau.TableauEventName.FILTER_CHANGE,
                onFilterChange,
            );
            // オブジェクト選択イベント
            viz.addEventListener(
                Tableau.TableauEventName.MARKS_SELECTION,
                onMarksSelection,
            );
        },
    };
    // Tableau呼び出し
    viz = new Tableau.Viz(containerDiv, vizUrl, options);
};
// タブ切替
const onTabSwitch = (e:any) => {
    const viz = e.getViz();
    const workbook = viz.getWorkbook();
    const activeSheet = workbook.getActiveSheet();
    const sheetName = activeSheet.getName();
    console.log(`タブが変更されました。${sheetName}`);
};
// フィルター変更
const onFilterChange = (e:any) => {
    const fieldName = e.getFieldName();
    console.log(`フィルターが変更されました。${fieldName}`);
};
// オブジェクト選択
const onMarksSelection = (e:any) => {
    const sheetName = e.getWorksheet().getName();
    console.log(`選択されたオブジェクトが存在するシート名 ${sheetName}`);
    e.getMarksAsync().then((marks:any) => {
        marks.forEach((v:any) => {
            console.log(v.getPairs().get('<フィールド名>'));
        });
    });
};

おわり

クライアント側で console.log をするだけでは、せっかく取得した情報が蓄積されずに消えてしまうので、 実際のアプリケーションに組み込むときは、ログを蓄積するための環境を用意する必要があります。

クライアントログを収集する方法はいくつかありますが、 私のチームで開発・運用しているアプリでは、 ログ収集用の API を AWS の API Gateway + Lambda を使用して作成して、CloudWatch に蓄積されるようにしています。

CloudWatch にさえあれば、インサイトで軽く集計してもよし、S3に出力してAthena経由で Tableau にデータを渡してダッシュボード化してもよしですね!

おしまい。