この記事は『CRESCO Advent Calendar 2022』8日目の記事です。

 

こんにちは、データテクノロジーセンターのn-satoです。

2022年10月にリリースされたTableau 2022.3ですが、
その中に「テーブル拡張機能(Tableau公式サイト上では表拡張機能)」なる機能が追加されていました。
(Tableau公式サイトURL:https://www.tableau.com/ja-jp/2022-3-features)

内容をみるとPythonやR等と連携して処理結果を他のデータソースと同じように、
テーブルとしてTableauで取り込める機能なのですが、
いざ試してみようと思ったら、どうやって記述すればいいのかで躓いてしまったので、
備忘としてこのテーブル拡張機能を使えるようになるまでの手順を残しておこうと思います。

今回はPythonとの連携を行います。

テーブル拡張機能とは

テーブル拡張機能はPython、Einstein Discovery、Rと連携する分析拡張機能を用いた機能です。
入力をテーブルで渡し、処理スクリプトの結果をTableau側へ出力します。

これまで分析拡張機能では、計算フィールドを介して処理スクリプトを実行し計算結果を1つのフィールド値としてTableau側に出力することができましたが、
このテーブル拡張機能を使うとテーブル自体をTableau側に渡すことができ、入力と違う結果も出力することができるようになります。

実行環境

OS:Windows10
Python:3.9.6
Tableau Desktop:2022.3.0

Python側の準備(TabPyのインストール、TabPy Serverの起動)

まずはPython側でTableauからの入力を受け取れるようにするため、TabPyをインストールします。
オンラインの環境であれば以下でインストールができます。

pip install tabpy

インストールができたらコンソールにTabPyと入力してTabPy Serverを起動します。
起動できると9004番ポートで受け付けしますとログに表示されます。
Tableau Desktopからこのポートを指定することでデータをPython側の処理へ渡すことができるようになります。

(tabpy_venv) C:\Users\n-sato\Documents\VScode\tabpy_try: tabpy
2022-11-23,19:40:11 [INFO] (app.py:app:244): Parsing config file c:\users\n-sato\documents\vscode\tabpy_try\tabpy\lib\site-packages\tabpy\tabpy_server\app\..\common\default.conf
2022-11-23,19:40:11 [INFO] (app.py:app:436): Loading state from state file C:\Users\n-sato\Documents\VScode\tabpy_try\tabpy\Lib\site-packages\tabpy\tabpy_server\state.ini
2022-11-23,19:40:11 [INFO] (app.py:app:332): Password file is not specified: Authentication is not enabled
2022-11-23,19:40:11 [INFO] (app.py:app:347): Call context logging is disabled
2022-11-23,19:40:11 [INFO] (app.py:app:125): Initializing TabPy...
2022-11-23,19:40:11 [INFO] (callbacks.py:callbacks:43): Initializing TabPy Server...
2022-11-23,19:40:11 [INFO] (app.py:app:129): Done initializing TabPy.
2022-11-23,19:40:11 [INFO] (app.py:app:83): Setting max request size to 104857600 bytes
2022-11-23,19:40:11 [INFO] (callbacks.py:callbacks:64): Initializing models...
2022-11-23,19:40:11 [INFO] (app.py:app:106): Web service listening on port 9004

Tableau Desktop側の設定

上部のメニューのヘルプ > 設定とパフォーマンス > 分析拡張機能接続の管理 を選択

TabPy を選択

ローカルホストを指定し、ポート番号は9004を設定。

テスト接続を押下して正常に接続ができましたと表示されることを確認。

保存を押下し、閉じるでウィンドウを閉じます。

これで連携の準備ができました。

テーブル拡張機能を利用する

データに接続していきます。ここではサンプルスーパーストアのデータを利用します。
あまり説明する必要ないかもしれませんが、念のため接続手順も書いておきます。

スタート画面から ファイルへの欄にある「Microsoft Excel」を選択します。

サンプル – スーパーストア.xlsを選択します。

データソース画面に遷移します。
通常ならこのままシート欄にある「注文」をキャンバスに配置してワークシートに遷移するところですが、テーブル拡張機能を利用するにはここで「新しいテーブル拡張機能」をキャンバスに配置します。

キャンバスにドロップすると入力データを配置する部分(「ここにシートをドラッグ」と書かれている部分)と、その横にスクリプトを記載する部分がある画面構成になります。
ここで「注文」を入力データとして配置します。

「注文」シートを配置した状態です。
画面下部のデータグリッドの入力テーブルに「注文」のデータが表示されるようになりました。

Python側で行う処理はスクリプト欄に記述します。
補足ですが、あらかじめ計算処理を関数化しておきたい場合、別途TabPy ClientをPython側でインストールし、TabPy Clientを使って関数をTabPy Serverにデプロイすることで実現できます。
今回は動作確認目的なので、TabPy Clientは用いずにスクリプト欄に処理を記載していきたいと思います。

「製品 ID」のカラムを‐(ハイフン)で分割した結果を追加して返すスクリプトを作成します。
書き方は普通のPythonスクリプトを記載する感覚で行けますが、最後にreturnを記載する必要があります。
後ほどスクリプトでどんな処理を行っているか解説します。

import pandas as pd
df = pd.DataFrame(_arg1)
df_2 = df["製品 ID"].str.split('-', expand=True)
df_2.rename(columns={0: '製品ID_大分類', 1: '製品ID_中分類', 2: '製品ID_No'}, inplace=True)
df_3 = pd.concat([df, df_2], axis=1)
return df_3.to_dict(orient='list')

上記をスクリプト欄に記載の上、「適用」ボタンを押下すると出力テーブルに
スクリプト実行結果が出力されています。
「製品 ID」のカラムを‐(ハイフン)で分割した結果のカラム(「製品ID_大分類」、「製品ID_中分類」、「製品ID_No」)も追加できることが確認できました。
※仕様詳細は未調査ですが、カラムの順番はTableauで自動的にソートされた順番となるようです。

Pythonスクリプトの解説です。

import pandas as pd

pandasのインポートを行っています。

df = pd.DataFrame(_arg1)

入力データをDataFrame形式で読み込んでいます。
テーブル拡張機能における入力データは「_arg1」という名称でマッピングされているので、入力データを取得する際は「_arg1」と記載します。
※入力データの指定方法はこちらを参考にしております。

df_2 = df["製品 ID"].str.split('-', expand=True)
df_2.rename(columns={0: '製品ID_大分類', 1: '製品ID_中分類', 2: '製品ID_No'}, inplace=True)
df_3 = pd.concat([df, df_2], axis=1)

データ加工処理です。
「製品 ID」のカラムを‐(ハイフン)で分割した結果を作成したのち、元のデータに追加する処理を行っています。

return df_3.to_dict(orient='list')

処理結果をTableau側に渡しています。
渡し方はdict(辞書)形式、「orient=’list’」でvalue内は値のみにして渡します。

補足:「orient=’list’」を付ける場合とつけない場合の違い

つけない場合:value内は「行ラベル:値」の情報になります。

{'オーダー ID': {0: 'JP-2021-1000099', 1: 'JP-2022-1001016', 2: 'JP-2020-1001113', … }

つける場合:value内は「値」のみの情報になります。

{'オーダー ID': ['JP-2021-1000099', 'JP-2022-1001016', 'JP-2020-1001113', … }

これでデータの加工は終わりです。あとは通常通りにワークシートへ遷移してビューの作成を行うことができます。
ワークシートに遷移すると、左のペインに3つのフィールドが追加されているのも確認できます。

追加検証:入力データを指定しない状態でテーブル拡張機能を使用することができるのか

結論としては、可能かと思われます。
入力データは何もない状態で、以下のテストスクリプトを組みました。

import pandas as pd
df = pd.DataFrame({'col1': [1, 2, 3], 'col2': ['AAA', 'BBB', 'CCC']})
return df.to_dict(orient='list')

適用を押下すると、スクリプトで定義した値が出力できています。

Pythonスクリプト側で直接CSVファイルを指定して読み込みもできました。
テーブル拡張機能だけでデータソースを準備することもできそうです。

import pandas as pd
df = df = pd.read_csv('C:/data/sample_superstore.csv', encoding='utf8')
return df.to_dict(orient='list')

まとめ

今回はテーブル拡張機能をもちいたTableauとPythonの連携について、連携手順を紹介させていただきました。
テーブル自体をTableauに渡すことが可能なため、計算フィールドでの連携方法より自由度が高くなった印象があります。

スクリプトの書き方はreturn部分の書き方に気を付ければ普通にPythonスクリプトを書く感じでいけるのかなと思います。

テーブル拡張機能使ってみたいけどわからないって方向けの導入手順として活用いただけたら嬉しいです。
最後までお読みいただきありがとうございました。