Flot Plugins – X Gap Threshold

Live Example
Github Code

You can insert breaks/gaps into a line graph drawn using Flot by inserting coordinate pairs that are set to null.

For example, from the Flot API:

If a null is specified as a point or if one of the coordinates is null or couldn’t be converted to a number, the point is ignored when drawing. As a special case, a null value for lines is interpreted as a line segment end, i.e. the points before and after the null value are not connected.

This works fine at breaking line graphs when the data has a detectable gap in it. That is, when x values have a greater distance between them that is predictable through the data measurement procedures.  For example, say we are polling networking data every 3 minutes, if there is a 6 minute gap between two x values then we should break the line graph at this point to indicate data loss.

While using Flot over summer, I found that breaking line graphs in this way is quite a common requirement. Particularly when working with time series data.

I developed plugin that automates adding null coordinates into the data series based on a given, x gap threshold value. The Flot plugin also allows the gaps to be highlighted in a given color to make them more obvious. Here is a screenshot of the ‘Hello World!’ example.

X Gap Threshold Example Graph

There is a small amount of configuration that is worth mentioning.

The plugin must be configured in the global x-axis options as well as for each individual series that a threshold needs to be set for. The global options enable the plugin and set the gap color. It may make sense to move all the options to the series in future versions so that gaps can be turned on and off and different colors can be used for each series. I leave this up to the reader to change if they require it 🙂

Global X-Axis Options:

xaxis: {
   insertGaps: true,  // enable or disable this plugin
   gapColor: rgba(100,100,100,0.2) // the color to use for gaps
}

Per-Series Options:

var series1 = {
  data: [ ... ],
  label: 'Series 1',
  xGapThresh: 300 // A value of 300 here indicates that a x-gap > 300 will insert a gap
}

Ask in the comments if you have any further questions and be sure to check the basic example.

Tufte Bar Chart Redesign in jQuery Flot

I have been reading (very slowly) through Edward R. Tufte’s ‘The Visual Display of Quantitative Information’ book. On page 126 Tufte proposes an alternative design for the Bar Chart / Histogram using all of his suggested principles.

The design basically attempts to emphasis the data opposed to the graph related lines. You will notice in the image below that there are no:

  1. Axis Ticks – Tufte states that the white grid marks remove the need for these
  2. Grid – The box around the bar graph does not aid understanding

I set out to implement this design using jQuery Flot. Here is the final result and the javascript source code to go with it.

var data, ticks, options, series, plot, ctx, lineWidth, offset;

        // some data close to Tufte's example
        data = [
            [0, 9], [1, 12], [2, 7], [3, 8], [4, 3],
            [5, 18], [6, 14], [7, 9], [8, 6], [9, 11],
            [10, 5], [11, 10]
        ];

        ticks = [ 5, 10, 15 ];
        options = {
            series: { bars: { show: true, fillColor: "rgb(128,128,128)" } },
            grid: { show: true, borderWidth: 0, color: "#fff" },
            xaxis: { show: false, min: -0.5 },
            yaxis: {
                tickFormatter: function(number) { return number + "%"; },
                ticks: ticks
            }
        };

        series = [{ data: data, bars: { barWidth: 0.5 }, color: "#fff" }];
        plot = $.plot($("#plot"), series, options);
        ctx = plot.getCanvas().getContext("2d");

        // need to set the label colour to not be white
        $(".tickLabel").css("color", "#000");

        // draw line at baseline because it "looks good"
        lineWidth = 2;
        offset = plot.offset();
        ctx.fillStyle = "rgb(128,128,128)";
        ctx.lineStyle = lineWidth;
        ctx.fillRect(offset.left + lineWidth * 3 , plot.height() + lineWidth,
            plot.width() - lineWidth * 8, lineWidth);

        // draw horizontal lines to remove need for ticks
        $.each(ticks, function(index, tick) {
            var yaxis = plot.getYAxes()[0];

            ctx.fillStyle = "#fff";
            ctx.lineWidth = lineWidth;
            ctx.fillRect(offset.left, yaxis.p2c(tick) + lineWidth / 2,
                plot.width(), lineWidth);
        });