Visualizing Time-Series Data with Highcharts & InfluxDB

As a time series maestro-in-the-making, I get to spend a lot of my time playing around with time series data. And I can tell you firsthand, plotting high volumes of time-stamped data in real time can often be a tricky task, requiring quite a bit of finesse and a plethora of patience. Luckily, we’ve got the InfluxData platform to handle a lot of difficulties for us out of the box. We can collect and store data efficiently and securely, build out visualizations and even set alerts. I love our tools, yet sometimes there are instances where our internal dashboarding tool, Chronograf, doesn’t fit a particular use-case.

Cue Highcharts.
This tutorial provides a short guide on visualizing your time series data from InfluxDB (a purpose-built time series data store) via the Highcharts charting library.

Initial Steps

Before you start throwing those graphs on the page though, you’ll need to make sure you have an instance of InfluxDB up and running, so you have a place to store and query your data. You can get all the TICK Stack components set up locally or spin up the stack in our handy sandbox mode.
I recently published a beginner’s guide on the Node-influx client library as an alternative for integrating with InfluxDB without necessarily having to use the plugin-driven collecting agent, Telegraf, to collect your data. This visualization is built out using the same ocean tide data from that post. Clone the repo down here to view the final result.

Let’s Get to Work

Pulling in the library is our first step. I added the following script tag to the head section of the index.html file.

<script src="https://code.highcharts.com/highcharts.js"></script>

To the body of the index.html file, you’ll need a container div with an id of ‘container’ so we can later target that in the script file, like so:

<div id="container"></div>

The Highcharts graph will be rendered within this container.

In our server file we’ve already set up an endpoint to query the data from our ocean tides database (see below), so we’ll need to fetch the data in our script file and set it into our Highcharts constructor function.

app.get('/api/v1/tide/:place', (request, response) => {
  const { place } = request.params;
  influx.query(`
    select * from tide
    where location =~ /(?i)(${place})/
  `)
  .then( result => response.status(200).json(result) )
  .catch( error => response.status(500).json({ error }) );
});

The above request queries InfluxDB based on the place name parameter and uses a regular expression to match anything related to that string. It then sends those results back to the front-end in JSON format.
In the script file, I wrote a simple fetch function that retrieves the data based on the location name passed in.

const fetchData = (place) => {
  return fetch(`/api/v1/tide/${place}`)
    .then(res => {
      if (res.status !== 200) {
        console.log(res);
      }
      return res;
    })
    .then(res => res.json())
    .catch(error => console.log(error));
}

To fetch all the data for the four different locations, I used Promise.all() and then mutated the results to fit into the required format referenced in the Highcharts documentation.

return Promise.all([
            fetchData('hilo'),
            fetchData('hanalei'),
            fetchData('honolulu'),
            fetchData('kahului')
         ])
        .then(parsedRes => {
          const mutatedArray = parsedRes.map( arr => {
            return Object.assign({}, {
              name: arr[0].location,
              data: arr.map( obj => Object.assign({}, {
                x: (moment(obj.time).unix())*1000,
                y: obj.height
              }))
            });
          });
        })
        .catch(error => console.log(error));

Constructing Our Graph

Now that we have our data ready to go, we can construct our graph.

Highcharts.chart('container', {
            colors: ['#508991', '#175456', '#09BC8A', '#78CAD2'],
            chart: {
              backgroundColor: {
                  linearGradient: [0, 600, 0, 0],
                  stops: [
                    [0, 'rgb(255, 255, 255)'],
                    [1, 'rgb(161, 210, 206)']
                  ]
              },
              type: 'spline'
            },
            title: {
              text: 'Hawaii Ocean Tides',
              style: {
                'color': '#175456',
              }
            },
            xAxis: {
              type: 'datetime'
            },
            yAxis: {
              title: {
                text: 'Height (ft)'
              }
            },
            plotOptions: {
              series: {
                turboThreshold: 2000,
              }
            },
            series: mutatedArray
          });

As you can see, there are a few different things happening here. The Highcharts library comes with the method chart() which accepts two arguments: the target element within which to render the chart and an options object within which you can specify various properties such as style, title, legend, series, type, plotOptions, and so on.
Let’s go through each of the options:

  • colors: [array] – The colors property accepts an array of hex codes which will represent the default color scheme for the chart. If all colors are used up, any new colors needed will result in the array being looped through again.
  • chart: {object} – The chart property accepts an object with various additional properties including type, zoomtype, animation, events, description and a number of style properties. In this instance, I’ve given the background a linear gradient and designated the type as spline.
  • title: {object} – This represents the chart’s main title and can be additionally given a style object to jazz things up a bit.
  • xAxis: {object} – In this scenario, because I’m using time series data, I know the x-axis will always be time so I can designate the type as ‘datetime’ and the scale will automatically adjust to the appropriate time unit. However, there are numerous other options here including styling, labels, custom tick placement, and logarithm or linear type.
  • yAxis: {object} – Similar to the xAxis property, the y-axis takes an object and has access to a number of options to customize the design and style of the chart’s y-axis. I’ve only specified y-axis title in this case, and deferred to Highcharts automatic tick placement.
  • plotOptions: {object} – The plotOptions property is a wrapper object for config objects for each series type. The config objects for each series can also be overridden for an individual series item as given in the series array. Here I’ve used the plotOptions.series property to override the default turboThreshold of 1000 and change it to 2000. This allows for charting a greater number of data points (over the default of 1000). According to the docs, conf options for the series are accessed at three different levels. If you want to target all series in a chart, you would use the plotOptions.series object. For series of a specific type, you would access the plotOptions of that type. For instance, to target the plotOptions for a chart type of ‘line’ you would access the plotOptions.line object. Lastly, options for a specific series are given in the series property (see next bullet point).
  • series: [array] or {object} – This is where you’ll pass in your data. You can additionally define the type for the data to be passed in, give it a name, and define additional plotOptions for it.

The result is displayed in the chart below:

Conclusion

Time series data can be visualized in so many different ways that the possibilities are endless. This post presented just one example of time series data visualization. Why not take a look at the Highcharts documentation and/or demos and tweet us @InfluxDB or @mschae16 about all your new creations with InfluxDB and Highcharts?
A version of this post was originally published at www.influxdata.com on April 19, 2018.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.