Skip to content

Instantly share code, notes, and snippets.

@HandcartCactus
Created March 22, 2021 17:48
Show Gist options
  • Save HandcartCactus/73675a2353cf9b617a94c7704ed56374 to your computer and use it in GitHub Desktop.
Save HandcartCactus/73675a2353cf9b617a94c7704ed56374 to your computer and use it in GitHub Desktop.
Advanced analytics with Python in Tableau using tabpy
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Advanced analytics with Python in Tableau using `tabpy` "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## First time:\n",
"1. uncomment and run the following command. (Keep the `!`, you need that)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"#!pip install tabpy-client"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. In a separate Anaconda3 Terminal in your activated env, run:\n",
"```\n",
"python -m pip install tabpy\n",
"tabpy\n",
"```\n",
"3. Stop tabpy with `CTRL+C` and come back to the notebook.\n",
"\n",
"Note: activate your env with `conda activate envName`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Python Stuff:\n",
"### Import libraries"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# jupyter tabpy api\n",
"import tabpy_client\n",
"\n",
"# for our sample function\n",
"import numpy as np\n",
"import scipy.stats as st\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define a sample function\n",
"We define a function that takes two different tableau columns as lists and returns a list.\n",
"Given a normal distribution fit to the `target` column, compute the CDF value at each element in `to_score`."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def sample_fn(to_score, target):\n",
" \"\"\"\n",
" Sample function.\n",
" Given a normal distribution estimated by the target column, \n",
" compute the CDF value at each element in to_score\n",
" \n",
" \n",
" to_score: list\n",
" target: list\n",
" \n",
" returns: list\n",
" \"\"\"\n",
" r = st.describe(target)\n",
" mean = r.mean\n",
" stdv = np.sqrt(r.variance)\n",
" z_scores = np.array(to_score)\n",
" z_scores = (z_scores - mean) / stdv\n",
" cdf = st.norm.cdf(z_scores)\n",
" return list(cdf)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Demonstration:\n",
"Tabpy is going to use python lists, so after using numpy arrays to create values for columns, we convert them to lists just to demonstrate how it's supposed to work."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Target column stats: mean=5, stdv=0.3\n",
"Sample Target values: 5.060, 4.628, 4.967, 4.831, 4.305, 5.320\n",
"\n",
"Sample Input values: 3.000, 3.082, 4.959, 5.122, 6.918, 7.000\n",
"Sample Output values: 0.000, 0.000, 0.503, 0.712, 1.000, 1.000\n"
]
}
],
"source": [
"# Create a column to score \n",
"to_score = list(np.linspace(3,7,50))\n",
"\n",
"# Create a column to use as a target\n",
"# In this case, 100 samples of Normal(mean=5, stdv=0.3)\n",
"n, mean, stdv = 100, 5, 0.3\n",
"target = np.random.randn(n) * stdv + mean\n",
"target = list(target)\n",
"\n",
"# compute and plot output\n",
"scores = sample_fn(to_score, target)\n",
"\n",
"format_lst = lambda x: \", \".join([f'{xi:0.3f}' for xi in [x[0],x[1],x[len(x)//2-1],x[len(x)//2 + 1],x[-2],x[-1]]])\n",
"print(f\"Target column stats: mean={mean}, stdv={stdv}\")\n",
"print('Sample Target values:', format_lst(target))\n",
"print()\n",
"print(\"Sample Input values: \", format_lst(to_score))\n",
"print(\"Sample Output values:\", format_lst(scores))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's just plot the values to see how it looks:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"demo_hist_x = np.linspace(mean-3*stdv, mean+3*stdv, 30)\n",
"demo_hist_y = st.norm.pdf(demo_hist_x, loc=mean, scale=stdv)\n",
"\n",
"plt.hist(target, density=True)\n",
"plt.plot(demo_hist_x, demo_hist_y)\n",
"plt.title(\"Target Column Histogram\\nand the normal distribution that made it\")\n",
"plt.xlabel('Values')\n",
"plt.ylabel('Density')\n",
"plt.show()\n",
"\n",
"plt.scatter(to_score, scores, marker='.', label='scores')\n",
"plt.title(\"sample_fn output\")\n",
"plt.xlabel('to_score')\n",
"plt.ylabel('output')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## TabPy\n",
"We now set up TabPy. First, we establish a TabPy server, in this case running on a locally hosted port. The default port for TabPy is `9004`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"myport = 9004\n",
"\n",
"connection = tabpy_client.Client(f'http://localhost:{myport}')\n",
"\n",
"connection.deploy(\n",
" 'SampleFn',\n",
" sample_fn,\n",
" \"Given a normal distribution estimated by the target column, \\\n",
" compute the CDF value at each element in to_score\",\n",
" override=True # force-updates the server if it's already running on that port\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now open up Tableau Desktop!\n",
"1. In Tableau Desktop, Go to `Help > Settings and Performance > Manage External Service Connection`. Something like this will appear. ![img aaa](https://cdns.tblsft.com/sites/default/files/blog/tabpy2.png) point it to `http://localhost`, port `9004`.\n",
"2. Create a computed field using the following:\n",
"```tableau\n",
"SCRIPT_REAL(\n",
" \"return tabpy.query('SampleFn',_arg1,_arg2)['response']\",\n",
" AVG([YourToScoreColumn]),\n",
" AVG([YourTargetColumn])\n",
")\n",
"```\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment