Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotly.js - gd.data must be an array

I am using the Plotly.js library to draw 3D graphs. My plan is to draw 4 traces into one 3D graph. But I encounter some strange behavior of my website when I try do this.

Sometimes, when I load my site I get no error and all 4 traces are loaded perfectly in my 3D graph. But at another time not all of my traces are loaded into my graph and I get the error:

Error: gd.data must be an array.

This is my function for adding the traces from a CSV file:

function addTraceFromCSVdarkColor(divname,link)
{
    Plotly.d3.csv(link, function(err, rows)
    {
        function unpack1(rows, key) 
        {
            return rows.map(function(row) { return row[key]; });
        }        

        var trace1 = {
            x: unpack1(rows, 'x'),
            y: unpack1(rows, 'y'),
            z: unpack1(rows, 'z'),
            mode: 'lines',
            type: 'scatter3d',
            opacity: 0.5,
            line: 
            {
                color: 'rgb(252, 185, 0)',
                size: 2,
                opacity: 0.5
            }
        };

        var data = [trace1];
        Plotly.addTraces(divname,data);
    });
}

And this is how i create the 3D graph:

function print3DMultiGraphMain(divname,link)
{
    Plotly.d3.csv(link, function(err, rows)
    {
        function unpack1(rows, key) 
        {
        return rows.map(function(row) { return row[key]; });
        }        

        var trace1 = {
            x: unpack1(rows, 'x'),
            y: unpack1(rows, 'y'),
            z: unpack1(rows, 'z'),
            mode: 'lines',
            type: 'scatter3d',
            line: 
            {
                color: 'rgb(252, 185, 0)',
                size: 2
            }
        };

        var data = [trace1];
        var layout = {
            autorange: false,
            width: 800,
            height: 800,
            scene: 
            {
                aspectratio: 
                {
                    x: 1,
                    y: 1,
                    z: 1
                },
                x: 0,
                y: 0,
                camera: 
                {
                    center: 
                    {
                        z: 0
                    },
                    eye: 
                    {
                        x: 1.25,
                        y: 1.25,
                        z: 1.25
                    },
                    up: 
                    {
                        x: 0,
                        y: 0,
                        z: 1
                    }
                },
                xaxis: 
                {
                    type: 'linear',
                    range: [0, 200],
                    zeroline: false
                },
                yaxis: 
                {
                    type: 'linear',
                    zeroline: false,
                    range: [0, 200]
                },
                zaxis: 
                {
                    type: 'linear',
                    zeroline: false,
                    range: [0, 200]
                }
            },
        };
        Plotly.newPlot(divname, data, layout,{displayModeBar: false});
    });
}

And this is how I call the functions in my html file:

<script>
print3DMultiGraphMain('tester','out1.csv');

addTraceFromCSVlightColor('tester','out2.csv');
addTraceFromCSVdarkColor('tester','out3.csv');
addTraceFromCSVlightColor('tester','out4.csv');
</script>
like image 413
IIIIIIIIIIIIIIIIIIIIII Avatar asked Mar 07 '16 14:03

IIIIIIIIIIIIIIIIIIIIII


1 Answers

The error gd.data must be an array is going to occur when the div containing the chart does not have a property dataof type Array. This might be because the chart is not properly initialized yet when you try to add traces, e.g. in case your asynchronous MultigraphMain call completes after one of your addTrace calls.

In order to circumvent the problem you have to wait for the chart to be created before you try to add traces. Plotly.newPlot() returns a promise. I have attached a minimal showcase below.

var trace1 = {
  x: [1, 2, 3, 4],
  y: [10, 15, 13, 17],
  type: 'scatter'
};

var trace2 = {
  x: [1, 2, 3, 4],
  y: [16, 5, 11, 9],
  type: 'scatter'
};

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function getInitialData() {
  // simulate HTTP call
  await sleep(2000);
  return trace1;
}

getInitialData().then((trace) => {
	Plotly.newPlot('myPlot', [trace]).then(
    () => {
  	  Plotly.addTraces('myPlot', [trace2]);
    }
  );		
})

// if you call addTraces here, it is going to fail
// Plotly.addTraces('myPlot', [trace2]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/plotly.js/1.49.5/plotly.min.js"></script>
<div id="myPlot">
</div>
like image 171
mit Avatar answered Oct 03 '22 10:10

mit