Skip to main content

Understand Custom Chart

Introduction

In this document, we will walk you through the different components of a Custom Chart definition, and the underlying mechanism.

High-level structure

In general, a Custom Chart definition is written using Vega-lite specifications combined with Holistics's specifications on top. To be more specific:

  • Holistics's specifications: a small set of syntax that help you define how your end-users interact with the underlying Vega-lite chart through the usual Data Exploration view. This includes:

    • Field definition: map between your dataset's fields and Vega chart's axes / dimensions.
    • Option definition: map between Holistics's styling options and Vega chart's styling options.
  • Vega-lite specifications: This is where you define the how the visualization should look like. For more details, please refer to Template definition.

    Vega & Vega-lite

    Custom charts can also be created using Vega syntax. While we do not have a dedicated Vega tutorial, you can use Vega and Vega-lite syntax interchangeably.

For example, a very simple Bar Chart definition:

CustomChart {
// === Holistics's specifications ===
// Field definition
fields {
field x {
type: "dimension"
label: "Category"
}
}

// Option definition
options {
option tooltip {
type: "toggle"
label: "Show tooltip"
default_value: true
}
}

// === Vega-lite specifications ===
template: @vgl {
"data": {"values": @{values}},

"mark": {
"type": "bar",
"tooltip": @{options.tooltip.value}, // receive tooltip value (true/false) from 'options' object
},

"encoding": {
"x": {"bin": true, "field": @{fields.x.name},}, // receive field name from 'fields.x' object
"y": {"aggregate": "count"}
}
};;
}

Below is a visual guide showing how each component in the definition will appear in the Data Exploration view:

In the following sections, we will go deeper into each component.

Field definition

This component is written in Holistics Syntax, and it is where you define how your dataset fields map to Vega chart's axes and dimensions. Holistics will read these configurations and prepare the field input boxes in the Data Exploration view.

In the example below, we have defined two fields. They will appear as two field input box in the Visualization's Setting tab:

fields {
field a {
type: "dimension"
label: "This is the label of the first field"
},

field b {
type: "measure"
label: "This is the label of the second field"
}
}

For more information about fields object's properties, please refer to the Field Properties doc.

Option definition

This is written in Holistics Syntax. This is where you define the styling options your chart accepts, such as tooltip visibility, goal line value or histogram bin size customization, etc. These options can be found in Styles tab in Data Exploration view.

For example, you want to give users the option to toggle on/off tooltip. Your Tooltip Option could look something like below:

For more information about option object's properties, please refer to the Option Properties doc.

Chart Template definition

This is written using Vega-lite synxtax. This dictates the visualization properties, such as the shapes to be used (bars, points, lines,...), which field is mapped to the X/Y axis, or styling details like line thickness, colors etc...

A Vega-lite chart is defined with three required properties:

  1. data: specifies the data source of the chart
  2. mark: specifies the shapes that you want to use and their styles
  3. encoding: specifies the mapping between user-input fields and chart's dimensions

Other than these required properties, you can specify how end-users can interact with your chart using Vega-lite's params, and Holistics's holisticsConfig property.

tip

How Custom Chart works

Normally when defining a Vega-lite chart, the user need to hard-code every detail of the chart before rendering it. For example, the data source of a chart must be a pre-defined JSON object, or a link to an external data file.

Open the Chart in the Vega Editor

However, in Holistics, the Vega-lite component receives values from the declared fields and options objects, so that charts can be created dynamically when users drag in a dataset field, or toggle a styling option in the Data Exploration view.

This feature is enabled by string interpolation. For example, we have a Custom Chart definition as below:

CustomChart {
fields {
field a {
type: "dimension"
label: "Dimension Field" // label of the field input's box in Data Exploration view
sort {apply_order: 1 direction: "asc"}
}
field b {
type: "measure" // dataset fields put here here will be aggregated
label: "Measure Field"
sort {apply_order: 2 direction: "desc"}
}
}

options {
option tooltip {
type: 'toggle'
label: 'Show tooltip'
default_value: true
}
}

template: @vgl {
"data": {
"values": @{values}
},

"mark": {
"type": "bar",
"tooltip": @{options.tooltip.value},
},

"encoding": {
"x": {
"field": @{fields.a.name},
"type": "temporal",
},
"y": {
"field": @{fields.b.name},
"type": "quantitative"
}
}
};;
}

Suppose the user drags Created_at field into Dimension Field and Revenue field into Measure Field, and click Get Result. During runtime, the following things will happen:

  • Holistics's engine queries the database according to the field combinations, and return the data. This data is inserted into the values property.
  • Metadata of the fields such as name, data type, format... are passed into the designated places
  • Value true/false returned by toggling the Show tooltip option in the Styles tab will also be passed in.

After that, a complete Vega-lite chart definition will be compiled:

// Compiled Vega-lite chart definition
{
"data": {
"values": [
{"a": "01/01/2022", "b": 28},
{"a": "01/02/2022", "b": 55},
{"a": "01/03/2022", "b": 43},
]
},

fields: {
a: {
name: "Created_at" // value of @{fields.a.name} is passed in here
type: "temporal"
}

b: {
name: "Sum of Revenue" // because the field is aggregated
type: "quantitative"
}
},

options: {
tooltip: {
value: true // @{options.tooltip.value} returned `true` and is passed in here
},
}
}

Reference syntax & String interpolation

To reference a property of a declared object and pass its value into the Vega-lite chart template, we use dot notation and string interpolation syntax:

@{object.object_name.object_property}

For example, to interpolate the name of a dataset field being dragged into field a (Dimension Field) into the chart template: @{fields.a.name}

Similar with field reference, to pass the value of an option to Vega-lite chart: @{options.option_name}


Let us know what you think about this document :)