tableau / TabPy

Execute Python code on the fly and display results in Tableau visualizations:
https://tableau.github.io/TabPy/
MIT License
1.56k stars 598 forks source link

Table Extension - Full Workflow is Unclear #569

Closed stephenlprice closed 1 year ago

stephenlprice commented 1 year ago

Environment information:

Describe the issue

  1. I followed the steps for setting up an Analytical Extension on my Tableau Cloud site and Tableau Desktop (Heroku deployment docs are really sparse so I first tried port 9004 (as described here), then I tried port 443 since HTTPS is included with this deployment option. Testing the connection in Desktop results in a successful connection response with port 443. At this point, I assume the connectivity to TabPy has been established.

  2. I then followed the steps to add a Table Extension to a published workbook.

  3. Using this example as a reference I started out just importing the dependencies I needed to run my script since the example shows sklearn and numpy imports without needing to call on a deployed function. However, when I run the script requesting data from the OpenWeather API I get an error response:

An error occurred while communicating with the Analytics Extension data source 'Analytics Extension'

Error Code: 15823CAD Analytics extension script is invalid

405: Method Not Allowed405: Method Not Allowed

** Questions***

To Reproduce Follow the steps described in the above section and then try to run this script in Tableau Desktop without calling on a deployed function:

NOTE: this may not be optimal but it's a quick test. I am sure someone with more pandas experience can use a normalize function with a few parameters to get the same result. Share feedback if you got any.

def current_weather():
  import requests
  import pandas as pd

  api_key = "API KEY"

  # creates a data frame from current weather data
  def current(api_key):
    payload = rest_current(api_key)
    data = transform_current(payload)
    return data

  # gets current weather data for the specified geolocation
  def rest_current(api_key):
    url = f'https://api.openweathermap.org/data/2.5/weather?lat=30.2711286&lon=-97.7436995&appid={api_key}'
    response = requests.get(url)
    payload = response.json()
    return payload

  # creates a dataframe from the JSON payload with current weather
  def transform_current(payload):
    # coordinates
    coord = payload["coord"]
    coord["row"] = 1
    coord = pd.DataFrame.from_dict([coord])

    # weather results
    weather = payload["weather"][0]
    del weather["id"]
    weather["row"] = 1
    weather = pd.DataFrame.from_dict([weather])

    # main weather data
    main = payload["main"]
    main["row"] = 1
    main = pd.DataFrame.from_dict([main])

    # visibility 
    visibility = {}
    visibility["visibility"] = payload["visibility"]
    visibility["row"] = 1
    visibility = pd.DataFrame.from_dict([visibility])

    # wind
    wind = {}
    wind["wind speed"] = payload["wind"]["speed"]
    wind["wind deg"] = payload["wind"]["deg"]
    wind["row"] = 1
    wind = pd.DataFrame.from_dict([wind])

    # clouds
    clouds = {}
    clouds["clouds"] = payload["clouds"]["all"]
    clouds["row"] = 1
    clouds = pd.DataFrame.from_dict([clouds])

    # country
    country = {}
    country["country"] = payload["sys"]["country"]
    country["row"] = 1
    country = pd.DataFrame.from_dict([country])

    # name (city)
    name = {}
    name["name"] = payload["name"]
    name["row"] = 1
    name = pd.DataFrame.from_dict([name])

    # joins the dataframes into a single row of data
    data = pd.merge(coord, weather, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, main, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, visibility, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, wind, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, clouds, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, country, left_on='row', right_on='row', sort=False)
    data = pd.merge(data, name, left_on='row', right_on='row', sort=False)

    return data

  # runs the workflow
  return current(api_key)

Expected behavior The above script returns a dataframe that can be consumed by Tableau Desktop via a Table Extension and that can then be published to Tableau Cloud configured with the same Analytical Extension.

Screenshots

error

Additional context The goal is to test Table Extensions for connectivity to web services via Tableau.

AmirMK commented 1 year ago

I believe the / should be removed from the hostname. It should be "tableau-tabpy-herokuapp.com" instead of "tableau-tabpy-heroku.com/"