1

I'm trying to implement a realtime streaming data chart that reads off a page that outputs the last few points of data every second, using the chart.js-plugin-streaming plugin by nagix.

I am reading off of an array in a URL because the chart "resolution" changes depending on which sensor is attached to the backend. Some of them output 1/second, but some of them output 10/second, and in the second case, refreshing the chart 10 times per second doesn't sound like a good idea, both because of processing power (old computers) and number of requests sent to the sensors.

So my URL outputs an array of objects for the last 20 points of data (roughly 2 to 20 seconds worth of data), and I refresh the chart 1 time a second.

I was hoping that the chart would just append only the new points, but I'm having weird behaviour. I've checked the timestamps and they are correct.

The data array is fetched using a simple jQuery $.get() call to the Django view URL that generates the array each time it is called.

This is an example of the URL output per call, for a 1/second sensor:

[
{y: 0.74, x: 1558531380957},
{y: 0.96, x: 1558531379950},
{y: 1.08, x: 1558531378942},
{y: 1.11, x: 1558531377939},
{y: 1.13, x: 1558531376932},
{y: 1.1, x: 1558531375930},
{y: 0.59, x: 1558531374914},
{y: 0.75, x: 1558531373911},
{y: 1.25, x: 1558531372902},
{y: 0.75, x: 1558531371898},
{y: 0.85, x: 1558531370893},
{y: 0.59, x: 1558531369889},
{y: 0.4, x: 1558531368887},
{y: 1.08, x: 1558531367879},
{y: 1.31, x: 1558531366871},
{y: 0.63, x: 1558531365866},
{y: 1.19, x: 1558531364859},
{y: 1.26, x: 1558531363854},
{y: 0.92, x: 1558531362848},
{y: 1.31, x: 1558531361837},
]

The next time it is called, the output will have removed the first point, the array would "scroll" and 1 new points will be show up at the tail end.

The objects inside the array have format: {"y": <float>, "x": <timestamp-in-ms>}

My chart config:

$(document).ready(function() {

    var chartColors = {
        red: 'rgb(255, 99, 132)',
        blue: 'rgb(54, 162, 235)'
    };

    var color = Chart.helpers.color;

    var config = {
        type: 'line',
        data: {
            datasets: [{
                label: 'Z-Score',
                backgroundColor: color(chartColors.blue).alpha(0.75).rgbString(),
                borderColor: chartColors.red,
                fill: false,
                lineTension: 0,
                data: []
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            title: {
                display: false,
            },
            scales: {
                xAxes: [{
                    type: 'realtime',
                    realtime: {
                        duration: 60000,
                        refresh: 1000,
                        delay: 2000,
                        pause: false,
                        ttl: undefined,
                        frameRate: 48,

                        onRefresh: function(chart) {
                            var data = []
                            $.get( "{% url 'live_z_score' %}", function(zScoreJSON) {
                                data = zScoreJSON
                                Array.prototype.push.apply(
                                    chart.data.datasets[0].data, data
                                );
                            });
                        }
                    }
                }],
                yAxes: [{
                    scaleLabel: {
                        display: true,
                        labelString: 'value'
                    }
                }]
            },
            tooltips: {
                mode: 'nearest',
                intersect: false
            },
            hover: {
                mode: 'nearest',
                intersect: false
            }
        }
    };

    var ctx = document.getElementById('myChart').getContext('2d');
    window.myChart = new Chart(ctx, config);

});

At this point it sort of works, except I'm having weird behaviour where a line would connect the first point to all subsequent points:

enter image description here

Example GIF (GIF size was too large, it's about 40 seconds long)

It seems like the graph is creating a new line each time it fetches new data, instead of dumping the previous line? I'm not sure how it handles data internally.

At this point I'm not sure exactly what the problem might be. The chart sort-of works, as it does create a line that is accurate to the graph, but then it seems like it's joining the first point in the array together with the latest point in the array. You can see this behaviour in the GIF.

1 Answer 1

2

This is because you are pushing 20 data points in onRefresh() every second, but only one data point out of 20 points is new and the rest are already inserted ones. This plugin doesn't dedup the data even if the same data with the same timestamp exists, so you see the line iterating the same points over and over.

A workaround would be to store the latest timestamp in your array when it is inserted, and to filter out the older data in the next onRefresh call so that only new data is pushed to chart.data.datasets[0].data.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.