I am attempting to load some files asynchronously using d3's queue, defer and await. The problem is trying to do so in a loop, and for each item in the loop, store the fetched data in the dictionary:
var myDictionary = {};
// e.g. hierarchy = ["State", "County"]
hierarchy.forEach(function(geo) {
queue()
.defer(d3.json, 'assets/data/geo/' + geo + '/' + geo + '.json')
.defer(d3.csv, 'assets/data/geo/' + geo + '/' + geo + '_info.csv')
.await(myFunc);
});
function myFunc(error, jsonData, csvData) {
// need access to geo
console.log(geo);
myDictionary[geo].jsonData = jsonData;
myDictionary[geo].csvData = csvData;
}
in myFunc, I would like access to geo to fill in the appropriate keys in the dictionary, however passing them inside .await.myFunc(geo) would print undefined inside myFunc.
I don't know whether this problem pertains to Javascript's callback functions, or D3's await(), or both.
Any recommendations?
Thanks
You can use this:
function myFunc(geo) {
return function(error, jsonData, csvData) {
// geo available here
console.log(geo);
myDictionary[geo].jsonData = jsonData;
myDictionary[geo].csvData = csvData;
};
};
Then:
var myDictionary = {};
// e.g. hierarchy = ["State", "County"]
hierarchy.forEach(function(geo) {
queue()
.defer(d3.json, 'assets/data/geo/' + geo + '/' + geo + '.json')
.defer(d3.csv, 'assets/data/geo/' + geo + '/' + geo + '_info.csv')
.await(myFunc(geo));
});
You could add it as a task so it gets passed into your myFunc.
queue()
.defer(d3.json, 'assets/data/geo/' + geo + '/' + geo + '.json')
.defer(d3.csv, 'assets/data/geo/' + geo + '/' + geo + '_info.csv')
.defer(callback=>callback(geo))
.await(myFunc);
...
function myFunc(error, jsonData, csvData, geo) {
console.log(geo);
}
Related
I am writing a function calling an API to fetch URLs. These are the steps that I wish to accomplish:
Parsing in an array of objects (restaurants) as arguments
For each object, call the Google Search API to get some imageURLs
Store those imageURLs in an array
Add imageURLs as an attribute called imageURLs to each object within the array in the argument
The code is able to log the imageURLs within the GET request, but outside of the request, imageURLs is just an empty array.
var googleSearch = function(restaurants, cb){
console.log("google starts");
const apiKey = google_apiKey;
const cseKey = cseID;
Array.from(restaurants).forEach(function(restaurant){
var keyWord = restaurant.name + " "+ restaurant.location.city
+ " "+ restaurant.location.state + " food";
var googleURL = "https://www.googleapis.com/customsearch/v1?key="+ apiKey +
"&q="+ keyWord +
"&searchType=image" +
"&cx=" + cseKey +
"&num=7" +
"&safe=medium"
;
//image URLs of each restaurants to be displayed in the front end
var imageURLs = [];
request
.get(googleURL,
{
json : true, headers: {
'User-Agent' : 'thaorell'
}
})
.then(function(response){
Array.from(response.items).forEach(function(item){
imageURLs.push(item.link)
});
})
.catch(e => {
console.log(e);
})
restaurant.imageURLs = imageURLs
})
cb(null, restaurants);
}
You're misunderstanding the Promise API:
var googleSearch = function (restaurants, cb) {
console.log("google starts");
const apiKey = google_apiKey;
const cseKey = cseID;
return Promise.all(Array.from(restaurants).map(function (restaurant) {
var keyWord = restaurant.name + " " + restaurant.location.city
+ " " + restaurant.location.state + " food";
var googleURL = "https://www.googleapis.com/customsearch/v1?key=" + apiKey +
"&q=" + keyWord +
"&searchType=image" +
"&cx=" + cseKey +
"&num=7" +
"&safe=medium"
;
return request
.get(googleURL,
{
json: true, headers: {
'User-Agent': 'thaorell'
}
}
)
.then(function (response) {
restaurant.imageURLs = Array.from(response.items).map(function (item) {
return item.link;
});
return restaurant;
})
})
)
.then(restaurants2 => cb(null, restaurants2))
.catch(cb)
}
As you can see you need to wait for all of the requests to finish before you pass the data back to the callback.
I am using node.js to develop firebase cloud functions. I need to connect to google maps api to get the distance between two Latlng points. I am making an https get request and receiving a response with a JSon object. The problem is that the received object is empty with a status: INVALID_REQUEST in most cases. However, in some rare cases it returns the desired value. I have tried the path and host of my request on the browser and the json object is retrieved successfully there. I do not know exactly where my problem is. Is it in the callback? the path? something else?
I am giving my code and the output of it.
My code is :
function getStatusCode(options, callback) {
https.get(options, function(http_res) {
var data = "";
console.log('inside the https request');
http_res.on("data", function (chunk) {
data += chunk;
console.log("I am reading the data");
console.log(data);
// callback(http_res.statusCode, data)
});
http_res.on("end", function () {
console.log("I am in the ON_END listener");
console.log('data contains: >> ' + data + ' I am in the ONEND listener')
callback(http_res.statusCode, data)
});
});
}
and I am calling it as follows:
console.log('startingPoints ' + startingPoints);
console.log('lat and lng are: '+lat+" , "+lng);
var options = {
host: 'maps.googleapis.com',
path: '/maps/api/distancematrix/json?units=imperial&origins='+startingPoints+'&destinations='+lat+','+lng+'&key=MY_GOOGLEMAPSAPI_KEY',
method: get
};
getStatusCode(options, function(statusCode, data){
console.log('The status code is : '+statusCode);
console.log('and data is : '+data);
// parsing json object:
jData = JSON.parse(data);
rows = jData.rows;
console.log('the length of the rows array is >> ' + rows.length + ', the length of the techs array is >> ' + techs.length);
min = -1;
for(var i = 0; i < rows.length; i++){
console.log('the array of techs + the equivalent values of the array of row >>' + techs[i] + ' and ' + rows[i].elements[0].distance.value);
if( min < 0 || rows[i].elements[0].distance.value < rows[min].elements[0].distance.value)
min = i;
console.log('minimum distance tech in the loop; the id is >> ' + techs[min] + ", and the distance is >> " + rows[min].elements[0].distance.value);
}
console.log('the min value before return is >> ' + min);
and the retrieved json object is:
{
"destination_addresses" : [],
"origin_addresses" : [],
"rows" : [],
"status" : "INVALID_REQUEST"
}
any idea please,,
I have found a solution. precisely, found my problem. The problem was not within google-map-api. It was with assignment of the starting_points variable.
I have my selenium test set up to take screenshots, but they are not saving to the directory which I have specified. Can anybody show me what I am missing?
Here is how I am configuring the screenshots in the test:
function writeScreenshot(data, name) {
var fs = require('fs');
name = name || 'ss.png';
var screenshotPath = mkdirp(configuration.readSettings('screenshotDirectory') + fileNameURL + "/", function(err){});
fs.writeFileSync(screenshotPath + name, data, 'base64');
};
and then I take the screenshot:
driver.takeScreenshot().then(function(data) {
var screenshotFile = os + '_' + osVersion + '_' + browser + '_' + browserVersion + '.png';
writeScreenshot(data, screenshotFile);
});
The screenshots end up being saved instead in the projects root directory and with the file name preceded by 'undefined'. (ex. undefinedWindows_8_chrome_46.png)
It does, however, create the folders shown here: var screenshotPath = mkdirp(configuration.readSettings('screenshotDirectory') + fileNameURL + "/", function(err){});
So why is this happening?
mkdirp() is an async method. That is why you pass a callback. You will need to change your code to something like the following:
function writeScreenshot(data, name) {
var fs = require('fs');
name = name || 'ss.png';
var screenshotPath = configuration.readSettings('screenshotDirectory') + fileNameURL + "/";
mkdirp(screenshotPath, function(err){
if (err) {
// something else happened while creating the dir. You decide what to do
return;
}
// Otherwise (if dir was created)
fs.writeFileSync(screenshotPath + name, data, 'base64');
});
};
mkdirp() function is asynchronous - it creates a directory and returns nothing - this is why you having that leading undefined in the filename.
Save the file in the callback:
var screenshotPath = configuration.readSettings('screenshotDirectory') + fileNameURL + "/";
mkdirp(screenshotPath, function (err) {
if (!err) {
fs.writeFileSync(screenshotPath + name, data, 'base64');
} else {
// handle error
}
});
Or, synchronously create the directory and write to it this way:
var screenshotPath = configuration.readSettings('screenshotDirectory') + fileNameURL + "/";
if (mkdirp.sync(screenshotPath)) {
fs.writeFileSync(screenshotPath + name, data, 'base64');
}
I can create a HeatMap using d3.js, dc.js and crossfilter, using data in a CSV file.
code:
var chart = dc.heatMap("#test");
d3.csv("morley.csv", function(error, experiments) {
var ndx = crossfilter(experiments),
runDim = ndx.dimension(function(d) { return [+d.Run, +d.Expt]; }),
runGroup = runDim.group().reduceSum(function(d) { return +d.Speed; });
chart
.width(45 * 20 + 80)
.height(45 * 5 + 40)
.dimension(runDim)
.group(runGroup)
.keyAccessor(function(d) { return +d.key[0]; })
.valueAccessor(function(d) { return +d.key[1]; })
.colorAccessor(function(d) { return +d.value; })
.title(function(d) {
return "Run: " + d.key[0] + "\n" +
"Expt: " + d.key[1] + "\n" +
"Speed: " + (299000 + d.value) + " km/s";})
.colors(["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"])
.calculateColorDomain();
chart.render();
});
but i want to do this same thing using JSON data, perhaps an array with some json data. This seems like a noob question but I was unable to find any example which uses JSON data for heatmap.
If you're using a JSON file then the code is going to be largely the same just replace d3.csv with d3.json.
If the data is already loaded in the browser then you can remove this function and just run:
var experiments = JSON.parse(json_object) //if json_object is still a string
var ndx = crossfilter(experiments)
and the rest of the code will be the same.
I'm not the best with Javascript and I seem to have got stuck.
I have a map in place and I need the Lat/Long for a location (that's fine) but the output comes in an alert box. I just need the values themselves.
E.g document.write(latt); document.write(longg);
At the moment this is the code that outputs the box:
function showPointLatLng(point)
{
alert("Latitude: " + point.lat() + "\nLongitude: " + point.lng());
}
Any help would be great, Thanks!
P.S
I think this is the controller:
function usePointFromPostcode(postcode, callbackFunction) {
localSearch.setSearchCompleteCallback(null,
function() {
if (localSearch.results[0])
{
var resultLat = localSearch.results[0].lat;
var resultLng = localSearch.results[0].lng;
var point = new GLatLng(resultLat,resultLng);
callbackFunction(point);
}else{
alert("Postcode not found!");
}
});
localSearch.execute(postcode + ", UK");
}
Looks like you can swap the showPointLatLng call with:
document.write( point.lat() + "," + point.lng() );
As lat/long come from calls to methods of the existing point object.
If you are asking how to make that work...
function showPointLatLng(point) {
document.write("Latitude: " + point.lat() + "\nLongitude: " + point.lng());
}
// Eg, ...
showPointLatLng({
lat : function(){ return 98; }
lng : function(){ return 42; /*the meaning of life!*/ }
});
Instead of document.write you could do something like this:
var info = document.createElement('div');
info.innerHTML = point.lat() + "," + point.lng();
document.body.appendChild(info);