Custom Chart Tutorial Part Two

Welcome to part two of the custom chart tutorial. In this part, we are going to learn how to work with query variables to instruct Zoomdata how to query the data to power our charts.

Modify Query Variables

Zoomdata’s front end client communicates with the backend data repositories by leveraging a WebSocket API designed to translate query messages into the appropriate native query language. To generate query messages, a chart must define the data variables that specify the query type and required fields.

Let’s build off of the chart created in part one of the tutorial and find the list of query variables created with the default (“Single-Group”) chart template.

Enter the following command in the terminal window from the chart’s root directory window and hit ENTER.

zd-chart edit

Use arrow keys to follow the prompts and press ENTER to select the following options:

  1. Variables
  2. List variables

The output of the terminal window should look like the following image:

List of Variables

Notice the group and metric variable listed in the table. A group variable indicates that the chart generates a request for “grouped/aggregated” data in the query. In this case, the chart defines a single group by field. A metric variable indicates that the chart will perform an aggregation function on a numeric field as part of the “grouped/aggregated” data query. In this chart, we have a single metric specified. The chart’s default configuration defines the actual group-by and metric fields at the source level. We visit the chart’s configuration a little later in this tutorial.

Answer “Y” to the prompt, “Would you like to make additional edits?” and make the following selections:

  1. Variables
  2. Edit a variable
  3. Metric |metric|

For the remaining prompts, enter the following information:

  1. What would you like to edit: Name
  2. Please enter a new name for the variable: Size

Enter “N” when prompted if you would like to make additional edits. If you are still running “watch mode” in the terminal window from part one of this tutorial, the variable change will be automatically pushed to the server. If necessary, you can run zd-chart push to ensure the change is pushed to the server.

At this point, we have defined a group query variable named “Group By” and a metric query variable named “Size” in the chart.

Set the Chart’s Default Configuration

Let’s now define what the query variables should be set to when adding the chart to a dashboard. Navigate to the “Sources” page in Zoomdata by clicking on the gear icon on the navigation bar and selecting Sources.

Click on the data source selected during the chart preview step in part one and continue with the following steps:

  1. Click on the “Charts” tab
  2. Click on the “Custom” tab
  3. Select: “My First Custom Chart”

On the right-hand side of the page, you see the inputs set for the different variables defined in the chart. Some variables types like group expose multiple inputs:

  1. Group By
  2. Group By Limit
  3. Group By Sort
  4. Sorting direction

These indicate the field used to group results, the total number of group values, the sorting field used with the limit parameter and the sort direction. Make a selection for a group-by field, set the limit to 10, and select the same metric for the group-by sort and size. The default settings should look similar to the following image:

Default Chart Settings

Data Preview

It is time to edit the chart code and preview the data retrieved as a result of the defined query variables. In a terminal window, change directories to the local directory of “My First Custom Chart” and enter zd-chart watch to set the CLI to Watch mode. In another terminal window, run the command npm start. For a refresher on this topic, visit the “Edit the Chart’s Code” section part one of this tutorial.

Open the src/index.js file in your preferred text editor or IDE. Let’s modify the code of the controller.update function to output the data received into the console.

// ...
controller.update = data => {
  // Called when new data arrives
// ...

Let’s also remove the code that creates the chart container and “Axis Labels / Pickers” on the chart. We will introduce these concepts later in the tutorial.

// Remove the code below
const chartContainer = document.createElement('div');

  picks: 'Group By',
  orientation: 'horizontal',
  position: 'bottom',
  popoverTitle: 'Group',

  picks: 'Metric',
  orientation: 'horizontal',
  position: 'bottom',

Upon saving the changes of src/index.js, the CLI updates the server’s copy with latest changes. Let’s preview the chart’s data by adding the chart to a new dashboard. Since we are outputting the data to the browser’s console, we need to open the browser’s developer tools to get to console. See instructions for Google Chrome and Mozilla Firefox browsers. The following image shows what the results might look like:

Data Preview in Console

Notice the JSON array with multiple objects in the result. Each object contains a group property with an array of strings (one per group by field) and current object with a nested count property (# of records) and a metrics property (an object with the metrics requested). Each metric objects contains an aggregation function property, like sum and its resulting value.

Some of you may be wondering, “How do we make flexible charts, which can be used across data sources if the objects have hardcoded property names?” Continue reading to find out.

Data Accessors

Now that we have to capture the results of the chart’s query, we need to find a way to reshape the result set in a format that can be consumed by a charting library. We also want tTo ensure our charts remain flexible and applicable to multiple data sources, we do not want to hard-code any object properties in the code. Zoomdata data accessors, exposed via the chart API, can be used to avoid hard-coding property names. Zoomdata has a concept known as Data Accessors, exposed via the chart API, that comes in handy when need to avoid hard-coding property names.

Let’s start out by instantiating some variables to hold the data accessors. We use one per query variable.

const groupAccessor = controller.dataAccessors['Group By']; // Group By is the name given to variable of type group.
const metricAccessor = controller.dataAccessors.Size; // Size is the name we gave to the variable of type metric.

The API is simple: controller.dataAccessors[<variable-name>]. Each data accessor holds the information about the field defined for the variable and provides a raw method that can be used to extract data values given a datum object. A datum refers to the objects inside the returned data array.

Assume we want to reshape our data array so that the contained JSON object looks like:

  name: STRING
  value: NUMBER

With this information, let’s create a reshapeData function that takes the original Zoomdata data array and returns a new array with the desired object structure.

function reshapeData(data) {
  return => ({
    name: groupAccessor.raw(d),
    value: metricAccessor.raw(d),

Finally, let’s use the new reshapeData function to output the reshaped results into the console. Up to this point, the chart’s code should look like:

/* global controller */
import styles from './index.css';

const groupAccessor = controller.dataAccessors['Group By'];
const metricAccessor = controller.dataAccessors.Size;

controller.update = function(data) {
  // Called when new data arrives

function reshapeData(data) {
  return => ({
    name: groupAccessor.raw(d),
    value: metricAccessor.raw(d),

Refresh the dashboard with a copy of the chart and check the contents of the browser console. The array object should look just like we specified, with a name and value property.

Well Done!

We completed part two of the custom chart tutorial. We introduced the concepts of query variables and data accessors, and we learned how to reshape data to make the chart flexible and dynamic.

Now continue to Part Three where you learn how to integrate third-party libraries into your custom charts.