Disclaimer up front: I mainly work in Python and I'm pretty sure my problem here has to do with my fundamental misunderstanding of the asynchronous nature of Javascript. If so, any explanation is much appreciated.
Either way, my specific problem is with using plotly and d3 to load data from a csv and then plot it. Here is a sample csv (in my code called "fake_data.csv")
x,y,z
0.0,0.0,5.4
0.0,2.1,4.1
3.2,1.5,3.2
I have an index.html
like so:
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="graph" style="width:100%;height:100%"></div>
<script src="scatter.js"></script>
</body>
Then I have my scatter.js
script, which this calls. It begins with a simple helper function to unpack the csv:
function unpack(rows, key) {
return rows.map(function(row)
{ return row[key]; });
}
For the plotting function, if I just do this it works fine:
Plotly.d3.csv('fake_data.csv', function(err, rows){
var x = unpack(rows , 'x');
var y = unpack(rows , 'y');
var z = unpack(rows , 'z');
Plotly.plot('graph', [
{
type: 'scatter3d',
mode: 'lines',
x: x,
y: y,
z: z
}], {
height: 640
});
});
But I need to be able to load several csv's in order to get all of the necessary information into the plot. So I try to wrap this in two functions instead and call them like this:
var x;
var y;
var z;
function getData(filename) {
Plotly.d3.csv(filename, function(err, rows){
x = unpack(rows , 'x');
y = unpack(rows , 'y');
z = unpack(rows , 'z');
});
}
function makePlot() {
console.log(x)
Plotly.plot('graph', [
{
type: 'scatter3d',
mode: 'markers',
x: x,
y: y,
z: z
}], {
height: 640
});
}
getData('fake_data.csv');
makePlot();
This renders nothing. The console.log(x)
inside of makePlot()
prints undefined
.
However when I type makePlot()
in the console (I'm using Chrome developer tools) after the page has loaded, it works! So what am I doing wrong? My guess is that makePlot()
is being called "before" getData()
so there is no value in x
yet. But I can't get my head around the right way to tell Javascript to call one function and then call another function after it.
Thanks in advance for any advice. This feels like a very basic concept that I am just banging my head against the wall on.