3

I have a JavaScript array which looks like this:

[
{x: "Station a", y: -77.33333333333333},
{x: "Station b", y: -19},
{x: "Station c", y: 9.492537313432836},
...
]

I wish to create a bar chart using Google Charts. The following code gives me an empty chart... there are no bars. The x-value is supposed to be the label and the y-value creates the bar in the chart. Do I have to manually push the array values into the data table? If so, how would this be done? This is an excerpt of the code, n being the JavaScript array:

// load necessary google charts libraries
google.charts.load("visualization", "1", {'packages':["corechart"]});
google.charts.load('current', {'packages':['bar']});

function plot1() {
        var dataPoints = []; // temporary array
        var n = []; // final array with data
        
        var chartData = new google.visualization.DataTable();
        chartData.addColumn('string', 'Station');
        chartData.addColumn('number', 'Arrival');
        
        n.forEach(function (row) {
            chartData.addRow([row.x, row.y]);
        });
        
        url = // localhost url with json data
        
        // push json data to array
        function addData(data) {
            for (var i = 0; i < data.length; i++) {
                for (var j = 0; j < data[i].delays.length; j++) {
                    dataPoints.push({
                        x: data[i].delays[j].Station,
                        y: data[i].delays[j].Arrival
                    });
                }
            }
            
            // filter "no information" values from array
            values = ["no information"]
            dataPoints = dataPoints.filter(item => !values.includes(item.y));
            
            // eliminate duplicates of x and get average of the y values
            const map = new Map();
            dataPoints.forEach(({ x, y }) => {
                const [total, count] = map.get(x) ?? [null, 0];
                map.set(x, [(total ?? 0) + parseInt(y), count + 1]);
            });
            
            // final array with data in desired format
            n = [...map].map(([k, v]) => ({ x: k, y: v[0] / v[1] }));
            
            console.log(n);
        }
        
        $.getJSON(url, addData);

        var options = {
            width: 700,
            legend: { position: 'none' },
            chart: {
            title: 'Verteilung der Verspätungen bei Ankunft (in Sekunden)'},
            axes: {
                x: {
                0: { side: 'top', label: 'Stationen'} // Top x-axis.
                }
            },
            bar: { groupWidth: "90%" }
                };
        
        var chart = new google.charts.Bar(document.getElementById('plot1'));
        chart.draw(chartData, google.charts.Bar.convertOptions(options));
    };

google.charts.setOnLoadCallback(plot1);

In the HTML header I have specified

<script src = "http://code.jquery.com/jquery-latest.js"></script>
<script src = "https://www.gstatic.com/charts/loader.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
sppokky
  • 115
  • 6

1 Answers1

2

arrayToDataTable expects a simple two-dimensional array, with intrinsic values only.
with the column headings as the first row.

var data = google.visualization.arrayToDataTable([
  ['Station', 'Arrival'],
  ['Station a', -77.33333333333333],
  ['Station b', -19],
]);

you can find the details here.

it returns the full data table, so there is no need to use addColumn afterwards.

-- OR --

you can create a blank data table, then add the columns and rows.

var data = new google.visualization.DataTable();
data.addColumn('string', 'Station');
data.addColumn('number', 'Arrival');

n.forEach(function (row) {
  data.addRow([row.x, row.y]);
});

EDIT

$.getJSON runs asynchronously. so you have to wait until it has finished,
before the data will be available.

move the loop to the end of addData.
then draw the chart once the data is ready.

note: you don't need the first load statement.

see following snippet...

google.charts.load('current', {
  packages: ['bar']
}).then(plot1);

function plot1() {
    var dataPoints = []; // temporary array
    var n = []; // final array with data

    var chartData = new google.visualization.DataTable();
    chartData.addColumn('string', 'Station');
    chartData.addColumn('number', 'Arrival');

    url = // localhost url with json data

    // push json data to array
    function addData(data) {
        for (var i = 0; i < data.length; i++) {
            for (var j = 0; j < data[i].delays.length; j++) {
                dataPoints.push({
                    x: data[i].delays[j].Station,
                    y: data[i].delays[j].Arrival
                });
            }
        }

        // filter "no information" values from array
        values = ["no information"]
        dataPoints = dataPoints.filter(item => !values.includes(item.y));

        // eliminate duplicates of x and get average of the y values
        const map = new Map();
        dataPoints.forEach(({ x, y }) => {
            const [total, count] = map.get(x) ?? [null, 0];
            map.set(x, [(total ?? 0) + parseInt(y), count + 1]);
        });

        // final array with data in desired format
        n = [...map].map(([k, v]) => ({ x: k, y: v[0] / v[1] }));

        console.log(n);

        n.forEach(function (row) {
            chartData.addRow([row.x, row.y]);
        });


        var options = {
            width: 700,
            legend: { position: 'none' },
            chart: {
            title: 'Verteilung der Verspätungen bei Ankunft (in Sekunden)'},
            axes: {
                x: {
                0: { side: 'top', label: 'Stationen'} // Top x-axis.
                }
            },
            bar: { groupWidth: "90%" }
                };

        var chart = new google.charts.Bar(document.getElementById('plot1'));
        chart.draw(chartData, google.charts.Bar.convertOptions(options));

    }

    $.getJSON(url, addData);

};
WhiteHat
  • 59,912
  • 7
  • 51
  • 133
  • thanks for your help! I used the loop example you gave since i have to add data dynamically... unfortunately it throws an error stating: Uncaught (in promise) Error: Data for arrayToDataTable is not an array Do you perhaps need the rest of the code to understand why this is happening? I could edit my post – sppokky Jul 19 '21 at 13:17
  • note the code above, after OR. there is no `arrayToDataTable` -- it's just `DataTable` --> `new google.visualization.DataTable();` – WhiteHat Jul 19 '21 at 13:18
  • `arrayToDataTable` is a static method used to create a `DataTable`, in the second example, we create a blank `DataTable`. – WhiteHat Jul 19 '21 at 13:19
  • ah okay thanks i changed that part... no more errors but still a blank chart :( – sppokky Jul 19 '21 at 13:20
  • if you could edit the question with the latest code, I'll take a look... – WhiteHat Jul 19 '21 at 13:21
  • please include all google charts code, including the `load` statement... – WhiteHat Jul 19 '21 at 13:22
  • done. thanks so much for taking the time to look at it and help me – sppokky Jul 19 '21 at 13:26
  • oh my goodness it works! thanks so much i have sitting forever trying to figure it out, you're amazing – sppokky Jul 19 '21 at 13:38
  • 1
    cheers! glad to help. note: you are using what google calls a _Material_ chart. there are several options that are not supported by _Material_ charts. see --> [Tracking Issue for Material Chart Feature Parity](https://github.com/google/google-visualization-issues/issues/2143) – WhiteHat Jul 19 '21 at 13:46