Skip to content

Instantly share code, notes, and snippets.

@KobaKhit
Last active October 18, 2023 18:36
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save KobaKhit/c4f0d3b80e2471ca027d321ce6fb4912 to your computer and use it in GitHub Desktop.
Save KobaKhit/c4f0d3b80e2471ca027d321ce6fb4912 to your computer and use it in GitHub Desktop.
A simple class that enables you to download (workbooks) or (csv from views) from a Tableau Server.
import tableauserverclient as TSC
import pandas as pd
from io import StringIO
class Tableau_Server(object):
"""docstring for ClassName"""
def __init__(self,username, password,site_id,url, https = False):
super().__init__() # http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods
# authorize
tableau_auth = TSC.TableauAuth(username, password, site_id)
server = TSC.Server(url)
server.add_http_options({'verify': https}) # if not https server skip warnings
server.auth.sign_in(tableau_auth)
server.use_highest_version() # make sure to use the same api version as server
server.server_info.get()
self.server = server
# get all workbooks in site
self.all_books, pagination_item = self.server.workbooks.get()
self.all_books_names = [wb.name for wb in self.all_books]
print('\nThere are {} workbooks on "{}" Tableau Server site.'.format(pagination_item.total_available,site_id))
def check_wb_name(self,wb_name):
# check if workbook exists
if wb_name not in self.all_books_names:
print('Workbook with name {} not found.'.format(wb_name))
return
def download_wb(self,wb_name):
# downlaod workbook given workbook name
self.check_wb_name(wb_name)
wb = [w for w in self.all_books if w.name == wb_name][0]
self.server.workbooks.download(wb.id)
def download_view_csv(self,wb_name, view_name = None):
# downlaod view csv given workbook name and view name (optional)
self.check_wb_name(wb_name)
wb = [w for w in self.all_books if w.name == wb_name][0]
# request views
self.server.workbooks.populate_views(wb)
views = [view for view in wb.views]
view_names = [view.name for view in wb.views]
if view_name is not None and view_name not in view_names:
print('View with name "{}" not found in workbook "{}". Below are available views.'.format(view_name,wb_name))
print(view_names)
return
# get either first view or user defined view
view_item = [view for view in views][0]
if view_name is not None:
view_item = [view for view in views if view.name == view_name][0]
self.server.views.populate_csv(view_item) # request view csv
# Perform byte join on the CSV data
string = StringIO(b''.join(view_item.csv).decode("utf-8"))
df = pd.read_csv(string, sep=",")
# pivot view csv so its in wide format if there is "Measure Values" column
# if not just save to csv
if 'Measure Values' not in df.columns.values:
df.to_csv('{}.csv'.format(view_item.name), index = False)
return
df['Measure Values'] = pd.to_numeric(df['Measure Values'].str.replace('\\,|\\$|\\%', ''))
cols = [c for c in df.columns.values if c not in ('Measure Values','Measure Names')]
df = pd.pivot_table(df,values = 'Measure Values', columns = 'Measure Names', index = cols).reset_index()
df.to_csv('{}.csv'.format(view_item.name), index = False)
def main():
username = ''
password = ''
site_id = ''
url = ''
ts = Tableau_Server(username,password,site_id,url)
# download a workbook
ts.download_wb('First Touch Report')
# download a view csv
ts.download_view_csv('First Touch Report','First Touch Report')
if __name__ == '__main__':
main()
@rodrigopizzano
Copy link

Thank you very much, lots of pages have the populate_csv example but none of them thought about pivoting the table, the "Measure Values" in a single column is awful.

@rodrigopizzano
Copy link

Hello again.

Allow me to suggest something. In order to avoid the alphabetic order for the columns you can store the original order in a list and then pass that list to the final datafarme. Also order the rows by the "cols" index would be helpfull.

Something like this:

cols_order = table_dataframe_raw['Measure_Names'].unique().tolist()
cols = [c for c in table_dataframe_raw.columns.values if c not in (
    'Measure_Values', 'Measure_Names')]
table_dataframe = table_dataframe_raw.pivot(
    index=cols, columns=['Measure_Names'], values='Measure_Values')[cols_order]
table_dataframe.sort_values(cols)

Let me know what you think!

@theiconik
Copy link

hey @rodrigopizzano,
i need to retain columns order of the view (avoid the alphabetic order), so can you help with the case when Measure Names and Measure Values is not present. It would be great if you can share your reorganise function here in the gist comments. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment