Skip to content

Instantly share code, notes, and snippets.

@githoov
Created May 26, 2015 23:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save githoov/c7fdc8904ffd24ae6b34 to your computer and use it in GitHub Desktop.
Save githoov/c7fdc8904ffd24ae6b34 to your computer and use it in GitHub Desktop.
Custom JS Visualizations

#Custom Visualization Framework

##The Basics As of 3.16, Looker has a custom visualization framework available to on-premise (i.e., self-hosted) customers only. This feature allows customers with engineering resources to load their own visualizations into Looker which can then be used with Looker-generated query results as well as part of other Looker features, including Spaces and Dashboards. The visualizations created by each customer will be available to all users on its instance. To access newly loaded visualization types, select the elipsis icon (...) in the Visualization bar, as below:

image

##How to Create Your Own Visualization

NOTE: This feature requires engineering resources familiar with JavaScript . Additionally, Looker Support cannot help with the troubleshooting of custom JavaScript visualizations.

###Requirements:

  • Visualizations must be written in JavaScript. They can leverage the D3 library, the underscore (_)library and the jQuery library.
  • Visualizations must be located in the looker/plugins/visualizations directory.
  • Visualization files must start with the following line in order to be registered in our visualization system: looker.plugins.visualizations.add({<YOUR VIS CODE GOES HERE>});
  • Visualizations require the following properties to be set:
    • id: A unique id in your system relying on. Ideally, you could prefix it with your company name like looker-bar-chart; however IDs cannot contain the word 'looker.'
    • label: The display label shown in the drop down list of additional visualizations, shown above.
    • create: Must be a function. The function receives the following arguments: element, which is the element referenced in the visualization; and settings, which refer to the visualization's settings.
    • update: Must be a function. It is expected to do the repetitive rendering work, and receives the following arugments: data, which is the data returned from a query; element, same as above; settings, same as above; response.data, which contains metadata about a data request, like the field list for the data, etc.
  • Visualizations have the following methods to assist with error propagation: addError and clearError. addError expects to receive an object with the following properties group, message and title. clearError when called with no arguments clears all the errors. When called with a group name, clears all the errors in that group.
  • Generally, visualizations should be stateless and should only render onto the element passed in.

##Preliminaries:

  • Make sure that custom visualizations are enabled on your license (feel free to reach out to support@looker.com to confirm this).
  • Once this is confirmed, refresh the license key in Looker's admin panel.
  • Restart your Looker.
  • On the machine hosting your instance of Looker run mv ~/looker/plugins/visualizations/examples/looker-heatmap-example.js ~/looker/plugins/visualizations/heatmap.js
  • Remove the examples directory (optional).
  • Uncomment the code in heatmap.js.

##Example: Users with this license feature enabled can find an example to follow in plugins/visualizations/heatmap-example.js

In the first section of the code, a unique id and label are registered, and (optional) style defaults are set:

(function() {
angular.module('Visualizations')
.run(function(VisualizationManager) {
  VisualizationManager.register({
    id: 'heatmap',
    label: 'Heatmap',
    options: {
      colorRange: {
        type: 'array',
        label: 'Color Ranges',
        section: 'Style',
        placeholder: '#fff, red, etc...'
      }
    },

In the next section, error handling is set up to ensure that users are guided to the correct configuration of dimensions, measures, and pivots:

    handleErrors: function(data, resp) {
      if (!resp || !resp.fields) return null;
      if (resp.fields.dimensions.length != 1) {
        this.addError({
          group: 'dimension-req',
          title: 'Incompatible Data',
          message: 'One dimension is required'
        });
        return false;
      } else {
       [...]
    },

We then use the create function to introduce the visualization element (in our example, a table):

    create: function(element, settings) {
      var $el = $(element);
      var table = d3.select(element)
        .append('table')
        .attr('class', 'heatmap')
        .attr('width', '100%')
        .attr('height', '100%');
      this.update(data, element, settings, resp);
    },

We then use the update function to bind the data to a DOM. We start out with error handling, data prep, and then go through to actually create the visuals elements:

    update: function(data, element, settings, resp) {
      
      // handle errors
      if (!this.handleErrors(data, resp)) return;

      this.clearErrors('color-error');
      var colorSettings = settings.colorRange || ['white', 'purple', 'red'];

      if (colorSettings.length <= 1) {
        this.addError({
          group: 'color-error',
          title: 'Invalid Setting',
          message: 'Colors must have two or more values. Each value is separated by a comma. For example "red, blue, green".'
        });
      }
    
    // from data object, extract the first and only dimension, the first and only measure, and a single pivot.
      var dimension = resp.fields.dimensions[0];
      var measure = resp.fields.measures[0];
      var pivot = resp.pivots;

     [...]
    
    // build table and tinker with aesthetics
      var table = d3.select(element)
        .select('table');
    
      var tds = trs.selectAll('td')
        .data(function(datum) {
          var tdData = [];
          tdData.push({type: 'dimension', data: datum[dimension.name]});
          datum[dimension.name];
          var measureData = datum[measure.name];
          pivot.forEach(function(pivot) {
            tdData.push({type: 'measure', data: measureData[pivot.key]});
          });
          return tdData;
        });    
}
@n8agrin
Copy link

n8agrin commented May 28, 2015

This feature allows customers with engineering resources to load their own visualizations into Looker which can then be used with Looker-generated query results as well as part of other Looker features, including Spaces and Dashboards.

I don't think they have anything to do with Spaces.

@n8agrin
Copy link

n8agrin commented May 28, 2015

The visualizations created by each customer will be available to all users on its instance. To access newly loaded visualization types, select the elipsis icon (...) in the Visualization bar, as below:

elipsis is ellipsis

The visualizations created by each customer will be available to all users on its instance. To access newly loaded visualization types, select the elipsis icon (...) in the Visualization bar, as below:

I'd clarify the first bit to: "Custom visualizations will be available to all Looker users."

@n8agrin
Copy link

n8agrin commented May 29, 2015

  • On the machine hosting your instance of Looker run mv ~/looker/plugins/visualizations/examples/looker-heatmap-example.js ~/looker/plugins/visualizations/heatmap.js
  • Remove the examples directory (optional).
  • Uncomment the code in heatmap.js.

I'd list those all under a sub-section titled "optional".

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