getData() function in the new Tableau 10 JavaScript API

 In Clojure, FOR BI PROS, just blog, Tableau

Tableau getData() functionTableau’s Javascript API evolves fast. In just a few versions we have arrived from the basic embedding to an event based, fully asynchronous API. Maybe the last, missing piece was accessing the summary and underlying data (however most of us used the vud  vizql controller to get the underlying data as featured in our excel downloader for tableau). With Tableau 10 this is also possible in a standard way: you can use two new Sheet level getData functions: getSummaryData()  and getUnderlyingData() .

But why is this such a great deal?

Use Cases for getUnderlyingData()

The most important thing is that you can complete visualizations with more, data driven components. You can retrieve users’ selection and embed their data to D3 visualizations, show interactive google maps with the selected marks’ underlying dataset. The possibilities are unlimited. In this blog post I will show the function’s basic usage: getting the data and printing it in a nice, interactive table to view and search the data.

Getting Summary or Underlying data from a Viz

Getting Summary or Underlying data from a Viz

Indigents: DataTables, React and CLJS

For the best experience I use Data Tables to show the underlying and summary table. It’s a cutting edge jQuery plugin that allows to display searchable, paginated tables with almost no efforts. To render the page I use my standard toolset: bootstrap css to have some basic style, react/reagent to manage HTML/DOM (you remember, in 2016 no one writes HTML) and ClojureScript because I still truly believe that only a few people on this planet can write good javascript while everyone tries and I’m most probably not one of those.

Tableau getData API

JavaScript API was completed with two new functions in the Sheet  class: getSummaryDataAsync  and getUnderlyingDataAsync . Both take one parameter (getSummaryDataOptions ) where you can specify if you’d like to ignore the column name aliases and/or current selections, the maximum number of rows to return and in case of underlying data if you’d like to see all columns or just the relevant ones.

After calling both functions the result is a SheetData object. It contains the data (getData() ) that is a simple two dimensional array of cells and the columns metadata (getColumns() ) with column name, index and datatype.

The working code

The complete code is less than 100 lines so let’s see what it has for us.

  (:require [reagent.core :as reagent :refer [atom]]
            [reagent-modals.modals :as reagent-modals]))

(defonce viz (reagent/atom {:maxRows 100 :includeAllColumns false}))
(declare modal)

;; Tableau API
(def viz-url

(def viz-options
    "hideTabs" true
    "hideToolbar" true
    "height" "500px"
    "width" "500px"
    "onFirstInteractive" #(swap! viz assoc :ready true)))

(swap! viz assoc :ready false :vizobj
       (js/tableau.Viz. (.getElementById js/document "tableau-div") viz-url viz-options))

This is the same usual viz initalization: when we reach the onFirstInteractive state we just update the application state with :ready = true .  Please note that we store the maxRows and includeAllColumns in the application state as well.

(defn underlying-button []
   {:disabled (not (:ready @viz))
    :on-click (fn [] (get-data-and-show-modal! #(.getUnderlyingDataAsync %1 %2)))} 
   "Show underlying data"])

(defn summary-button []
   {:disabled (not (:ready @viz))
    :on-click (fn [] (get-data-and-show-modal! #(.getSummaryDataAsync %1 %2)))} 
   "Show summary data"])

These two reagent components will render two buttons. If those are clicked we call get-data-and-show-modal!  and pass a callback function that calls an another callback calling getSummaryData or getUnderlyingData respectively. What a callception!

The last part is to show the modal window and call the getData function depending on the first parameter from the button’s on-click:

(defn get-data-and-show-modal!
  (-> (:vizobj @viz)
      (f (clj->js @viz))
      (.then (fn [data] 
               (swap! viz assoc :columns (.getColumns data) :data (.getData data))
               (reagent-modals/modal! [modal] {:size :lg}) ))))

;; UI  / Reagent Components
(defn modal-render []
  [:div {:style {:overflow-y :auto}}
    {:cell-spacing "0" :width "100%"}
     (reduce (fn [res col] (conj res (vector :th (.getFieldName col)))) [:tr] (:columns @viz))]

    ; tbody, reduce from [[{formattedValue: val]] to [:tbody [:tr [:td val1] [:td val2]]]
    (reduce (fn [res row] 
              (conj res 
                      (fn [tr col] (conj tr (vector :td (get col "formattedValue")))) 
            (js->clj (:data @viz)))]])

(defn modal-did-mount [this]
  (.DataTable (js/$ (.getElementById js/document "data-table"))))

(defn modal []
  (reagent/create-class {:reagent-render modal-render
                         :component-did-mount modal-did-mount}))

The modal-render  function does the magic: it transforms the SheetData  to a nice HTML table.

All together

The source code is here, the demo site is here and the comment box is over there – feel free to ask your questions if you have any.


Contact Us

We're not around right now. But you can send us an email and we'll get back to you, asap.

Not readable? Change text. captcha txt