こんにちは、アイダです。 利用者の操作をTableau JS API (Tableau JavaScript API)を使って取得することで、開発側はよりユーザー行動を把握することができるようになります。
ユーザーを理解し、ニーズを探るための第一歩として、Tableau JS API 活用例を投稿してもらいました。それではOさん、どうぞ。
- はじめに
- やりたいこと
- 使うもの
- さっそく
- 1.どのグラフを見たのか、ワークブック名・シート名が知りたい
- 2.タブの切り替えをしたのか、どのタブを見たのか
- 3.どの項目で、フィルター操作をしたのか
- 4.どのグラフで、詳細情報を見たのか
- 最終的なソースコード
- おわり
はじめに
こんにちは。 Oです。
文章を書くのがあまり得意ではないので、気分がのったときに一気に書きたい派です。
これまで、Tableau JS API に関して2本の記事を投稿しました。
今回はこれらの知識を組み合わせて、実業務でありそうなことを試してみようと思います。
Tableau を Web アプリケーションに組み込むということは、
そのアプリを通じてユーザーが Tableau を操作することです。
ダッシュボードを表示したり、複数のチャートを見比べたり、フィルター操作をしたり...
開発・運営する側としては、ユーザーが何を見たのか・どんな操作をしたのかを知りたいですよね。
なので、Tableau JS API を通じて把握できる、ユーザー操作をいくつかご紹介します。
やりたいこと
ユーザーのことは全部知りたい! そんな気持ちを押さえて、Tableau JS でできそうなことをピックアップしてみました。
- どのグラフを見たのか、ワークブック名・シート名が知りたい
- タブの切り替えをしたのか、どのタブを見たのか
- どの項目で、フィルター操作をしたのか
- どのグラフで、詳細情報を見たのか
使うもの
以前のブログ をご参考ください。
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)から直接情報が取得できるので、フィルターが発生したフィールド名を取得しましょう。
// フィルター変更 const onFilterChange = (e:any) => { const fieldName = e.getFieldName(); console.log(`フィルターが変更されました。${fieldName}`); };
さらに、getFilterAsync() メソッドを使うと、フィルターで設定した値まで取得できます。
4.どのグラフで、詳細情報を見たのか
グラフ上でオブジェクトをクリックすると、選択状態になり、詳細情報を見ることができます。
このユーザー操作は、MARKS _SELECTION イベントで 取得することができます。
onFistInteractive 内にイベントリスナー用意して、MARKS _SELECTION を検知したら onMarksSelection メソッドが呼ばれるように設定します。
// オブジェクト選択イベント
viz.addEventListener(
Tableau.TableauEventName.MARKS_SELECTION,
onMarksSelection,
);
onMarksSelection では、イベントの引数(e)からシート名を取得することができます。
さらに、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 にデータを渡してダッシュボード化してもよしですね!
おしまい。