I am using d3.js to read data from a tsv file,but I found that there is something strange in the procedure,I read the data and push each line into an array called dataset and then want to calculate the variable total by using a for loop,but it seems to fail(there is no any datum in dataset),maybe it is because the javascript just going on without waiting for finish reading the file.The code is here:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>THis is a te</title>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript" charset="utf-8"></script>
<script src="fun.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var dataset = new Array();
var parseDate = d3.time.format('%Y-%b-%e').parse;
d3.tsv("data.tsv",function(error,data){
for(var i in data){
//console.log(data[i].date);
//console.log(parseDate(data[i].date));
var elapse = (i == 0) ? 0 : dateElapse(parseDate(data[i-1].date),parseDate(data[i].date));
dataset.push({
date : parseDate(data[i].date),
state : data[i].state,
elapse : elapse
});
}
});
var total = 0;
for(var i in dataset){
total =total + dataset[i].elapse;
}
console.log(total);
var tau = Math.PI * 2;
var width = 960,height = 500;
var svg = d3.select("body").append("svg").attr({
"width" : width,
"height": height,
});
var container = svg.append("g").attr({
"transform":"translate(" + width / 2 + "," + height / 2+ ")"
});
var arc = d3.svg.arc()
.innerRadius(180)
.outerRadius(240)
.startAngle(0);
var background = container.append("path")
.datum({endAngle: tau})
.style("fill","#ddd")
.attr("d",arc)
var foreground = container.append("g").append("path")
.datum({endAngle: 0.25 * tau})
.style("fill","#ffa500")
.attr("d",arc)
</script>
</body>
</html>
fun.js:
var month = [31,28,31,30,31,30,31,31,30,31,30,31];
var millseconds_per_day = 86400000;
function getDateParser(specifier) {
return d3.time.format(specifier).parse;
}
function day( ) {
return this.getDate();
}
function month() {
return this.getMonth();
}
function year( ) {
return this.getFullYear();
}
function dateElapse(start,end) {
return Math.ceil((end - start) / millseconds_per_day);
}
function loadtsv(file,arr){
arr = new Array();
d3.tsv(file,function(error,data){
var parser = getDateParser("%Y-%b-%e");
for(var i in data){
var elapse = (i == 0) ? 0 : dataElapse(parser(data[i-1].date,parser(data[i].data)));
arr.push({
date : parser(data[i].data),
state: data[i].state,
elapse : elapse
})
}
});
}
and the data file:
date state
2014-May-12 task1
2014-May-25 task2
2014-Jun-28 tsak3
NOTICE:The tsv file should separate its every datum by tab,assure that your paste code doesn`t change that,that may cause a fail reading.
I kown the skill like:
var reader = new FileReader();
read.onload=...
but I don`t kown what to do in my situation.
The easiest fix is to move the total calculation inside the tsv callback function.
d3.tsv("data.tsv",function(error,data){
for(var i in data) {
...
}
var total = 0;
for(var i in dataset){
total =total + dataset[i].elapse;
}
console.log(total);
});
Note that Javascript is an asynchronized language so the callback function doesn't block the rest of code from running, and since loading data.tsv file needs I/O operations the lines after the callback actually run before the callback function and by that time your array is still empty.
Related
Using this script i m facing this error Not a number value that i don t understand,
How can I fix this ?
<!DOCTYPE html>
<html>
<head>
<title>The Cube</title>
</head>
<body>
<script>
var cube = function(side) {
this._side = side;
this.volume = function() {
var vol = Math.pow(this.side, 3);
return vol;
};
this.surface = function() {
var totalLength = 12 * this.side;
return totalLength;
};
};
var firstCube = new cube(2);
document.write("Volumul " + firstCube.volume() + "<br>");
document.write("Total length " + firstCube.surface());
</script>
</body>
</html>
You assign the value of side to this._side. Therefore you can access it as side inside of the function and as this._side inside of every method (as your methods are inside the function too, both will work). But this.side does not exist, it is not defined, and multiplying it results in Not a Number.
How I would write that:
class Cube {
constructor(side) { this.side = side; }
get volume() { return Math.pow(this.side, 3); }
get surface() { return 12 * this.side; }
}
const cube = new Cube(3);
console.log(cube.volume, cube.surface);
I'm perform a task on json data. I want to upload file locally and want to assign its data to a global variable so that I can use that data in my further functions.
<!DOCTYPE html>
<head>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<style>
#result {
display:block;
width:400px;
height:200px;
}
#import {
margin:10px 0;
}
</style>
</head>
<body>
<div id="myDiv" style="width: 900px; height: 602px;"><!-- Plotly chart will be drawn inside this DIV --></div>
<input type="file" id="selectFiles" value="Import" /><br />
<button id="import">Import</button>
<textarea id="result">
</textarea>
<script>
//for uploading json file
document.getElementById('import').onclick = function() {
var files = document.getElementById('selectFiles').files;
console.log(files);
if (files.length <= 0) {
return false;
}
var fr = new FileReader();
fr.onload = function(e) {
console.log(e);
var result = JSON.parse(e.target.result);
var formatted = JSON.stringify(result, null, 2);
document.getElementById('result').value = formatted;
}
fr.readAsText(files.item(0));
};
want to assign either direct JSON data to text or after stringify in above function then to abz var globally. so that I can use that var for further functions
var text = ''
var abz1 = JSON.parse(text);
var abz = JSON.stringify(abz1);
var rt1 = []
var in1 = []
var rt2 = []
var in2 = []
var rt3 = []
var in3 = []
var a = abz.groups[0].peaks[0].eic.rt
var b = abz.groups[0].peaks[1].eic.rt
var c = abz.groups[0].peaks[2].eic.rt
//console.log(abz.groups[0].peaks[0].eic.rt)
//console.log(abz.groups[0].peaks[0].eic.intensity)
// a.push(abz.groups[0].peaks[0].eic.rt)
// b.push(abz.groups[0].peaks[0].eic.intensity)
//console.log(a)
// console.log(b)
for (i=0;i < a.length;i++){
rt1.push(abz.groups[0].peaks[0].eic.rt[i])
in1.push(abz.groups[0].peaks[0].eic.intensity[i])
}
for (i=0;i < b.length;i++){
rt2.push(abz.groups[0].peaks[1].eic.rt[i])
in2.push(abz.groups[0].peaks[1].eic.intensity[i])
}
for (i=0;i < c.length;i++){
rt3.push(abz.groups[0].peaks[2].eic.rt[i])
in3.push(abz.groups[0].peaks[2].eic.intensity[i])
}
var trace1 = {
x: rt1,
y: in1,
mode: 'markers'
};
var trace2 = {
x: rt2,
y: in2,
mode: 'markers'
};
var trace3 = {
x: rt3,
y: in3,
mode: 'markers'
};
var data = [ trace1, trace2, trace3 ];
var layout = {
title:'Intensity vs Retension Time - Scatter Plot',
height: 600,
width: 1200
};
Plotly.newPlot('myDiv', data, layout);
</script>
</body>
I is not clear what is your question or what not works in your code.
But I guess you maybe have a callback problem. Your process that loads the file needs some milliseconds until it calls the specified onload method with the loaded file-data. So the statements, that lists after fr.readAsText(); will be called BEFORE the onload method will be called. In conclusion: You want to use the data before it was loaded. So the trick is to put all the further data actions into the onload callback method.
fr.onload = function(e) {//this is a callback method that will be called, if the file is loaded
console.log(e);
var result = JSON.parse(e.target.result);
//put here your plot code or call a function for using the result variable!!!
//e.g.:
var a = result.groups[0].peaks[0].eic.rt
}
fr.readAsText(files.item(0));//this starts the loading process. Needs some milliseconds. and then it calls asynschrously the before specified onLoad-method
console.log("this output will be made BEFORE the file was loaded, cause the FileReader answers asynchron");
Feel free to ask further questions.
everybody. I have an interesting question. Would be grateful for your help. Working on solution to one task:
Implement a financials ticker grid using the CSV data provided Initial
View
Load and parse the data in snapshot.csv into a model.
Render a grid based on that data to the DOM.
Write an engine to work through deltas.csv and emit update messages to
parse.
When only a number exists on a line, that amount of time in
milliseconds should be waited until processing the next set of deltas.
When the last set of deltas is processed, return to the start of the
file and repeat.
Each set of deltas should be merged into the existing dataset and then
propagated to the DOM in the most efficient manner possible.
Provide notification that an item has been updated via a visual flare
in the UI.
My path:
I've managed to load the snapshot.csv, parse it, create table, then(using promises), upload the second file delta.csv, parse it, trying to update table, but struggling to create timer function to update the table according to the amount of miliseconds in the delta csv file. Thanks in advance for your advice))I'm learning javascript, and looking for challenges, this looked like an interesting one.
function CSVToArray( strData, strDelimiter ){
strDelimiter = (strDelimiter || ",");
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
var arrData = [[]];
var arrMatches = null;
while (arrMatches = objPattern.exec( strData )){
var strMatchedDelimiter = arrMatches[ 1 ];
if (
strMatchedDelimiter.length &&
strMatchedDelimiter !== strDelimiter
){
arrData.push( [] );
}
var strMatchedValue;
if (arrMatches[ 2 ]){
strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
strMatchedValue = arrMatches[ 3 ];
}
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
}
function httpGet(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (this.status == 200) {
resolve(this.response);
} else {
var error = new Error(this.statusText);
error.code = this.status;
reject(error);
}
};
xhr.onerror = function() {
reject(new Error("Network Error"));
};
xhr.send();
});
}
var r1,r2
httpGet('snapshot.csv').then(function(result) {
r1 = CSVToArray(result);
createTable(r1);
return httpGet('deltas.csv')
}).then(function(result2) {
r2 = CSVToArray(result2);
updateTable(r2)
});
var hInterval = null;
var k = 0;
var iteration=0;
function updateTable(how) {
var myTable = document.getElementById('myTable');
var j=1;
var watch_dog=0;
var x = document.getElementById("myTable").rows[0].cells;
console.log(x);
while(j<myTable.rows.length) {
if (typeof(how[k]) !== "undefined") { //
var startPos = 2; //In file we have broken data (some time 6 columns some time 5)
if (how[k].length === 5)
startPos = 1;
var valueAdded=0; //How much value changed
for (var i = startPos; i < startPos + 3; i++) {
var value = how[k][i];
if (typeof(value) !== "undefined") {
valueAdded++;
if (value.length > 0) {
if (startPos === 2)
myTable.rows[j].cells[i].innerHTML = value;
else
myTable.rows[j].cells[i + 1].innerHTML = value;
}
}
}
if (valueAdded>0) //if some values changed we are increment j
j++;
k++; //Increment global row pointer
} else {
//Restart when we finished
iteration=1;
k=0;
break;
}
}
}
function createTable(now) {
var body = document.getElementsByTagName("body")[0];
// create elements <table> and a <tbody>
var tbl = document.createElement("table");
var tblBody = document.createElement("tbody");
tbl.setAttribute("id","myTable");
// cells creation
for (var j = 0; j < now.length-1; j++) {
// table row creation
var row = document.createElement("tr");
for (var i = 0; i < now[0].length; i++) {
// create element <td> and text node
//Make text node the contents of <td> element
// put <td> at end of the table row
var cell = document.createElement("td");
var cellText = document.createTextNode(now[j][i]);
cell.appendChild(cellText);
row.appendChild(cell);
}
//row added to end of table body
tblBody.appendChild(row);
}
// append the <tbody> inside the <table>
tbl.appendChild(tblBody);
// put <table> in the <body>
body.appendChild(tbl);
// tbl border attribute to
tbl.setAttribute("border", "2");
}
<!DOCTYPE html>
<html>
<head>
<title>Application</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="Demo project">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" href="styles.css">
<style type="text/css"></style>
</head>
<body>
<p>Let the game begin!</p>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</html>
Project files:
https://dw3i9sxi97owk.cloudfront.net/uploads/jobAttachments/150928161919_pph.zip
You could write a recursive function that processes one row at a time, then set's up the timeout to process the next row in X seconds. The code below is just kind of pseudo, it doesn't use your variables or anything... but hopefully you can get the idea from this. It's a recursive function that calls itself for the next row after waiting the amount of time.
function processRow(row, waitTime) {
setTimeout(function() {
//do your row stuff here
//move on to the next row, look at it's wait time and pass that along
var nextRow = row+1,
nextWaitTime = nextRow.waitTime;
processRow(nextRow, nextWaitTime);
}, waitTime);
}
//run the first instance
var firstRow = 1,
firstWait = firstRow.wait;
processRow(firstRow, firstWait);
Very old, but very UNsolved subject: image.onload not called.
Code tells the story better than words ...
Calling .html =
<script>
var newConnection = new MeasureConnectionSpeed();
if (newConnection.isHighSpeed())
doSomething1;
else
doSomething2;
</script>
Called .html =
<script>
function MeasureConnectionSpeed() {
var connection = this;
var imgDownloadSrc = "http://someLargeImage.jpg";
var imgDownloadSize = 943 * 1024; // bytes
var startTime = 0,
endTime = 0; // set later
connection.isHighSpeedConnection = false; // = a Object Property
// an Object Method ...
// just the function declaration which is called via
// connection.computeResults()
connection.isHighSpeed = isHighSpeed;
connection.computeResults = computeResults; // another Object Method
var testImgDownload = new Image();
testImgDownload.onload = function () {
endTime = (new Date()).getTime();
connection.computeResults();
} // testImgDownload.onload
testImgDownload.onerror = function (err, msg) {
alert("Invalid image, or error downloading");
}
// We immediately continue while testImgDownload is still loading ...
// the timer is started here and ended inside testImgDownload.onload
startTime = (new Date()).getTime();
// This forces an attempt to download the testImgDownload and get the
// measurements withOUT actually downloading to your Cache:
var cacheBuster = "?nnn=" + startTime;
testImgDownload.src = imgDownloadSrc + cacheBuster;
function computeResults() {
var speedMbps = someNumber;
connection.isHighSpeedConnection = speedMbps > 20;
} // computeResults
// this.isHighSpeed() = isHighSpeed()
function isHighSpeed() {
return connection.isHighSpeedConnection;
}
} // MeasureConnectionSpeed
</script>
* EDIT #1 *
Two more bits ...
I decided to download Google's Chrome and test my .html locally on it. Chrome accessed the .onerror Event Handler of my original code. Safari and Firefox never did???
Another curious observation ... using Chrome, alert(err) inside my .onerror Event Handler produced "undefined". But, I did use alert(this.width) and alert(this.naturalWidth), each showing 0 ... which means it is an invalid image???
And the invalid image error even occurs if I place the src before the .onload Handler.
That really is it for now!
* EDIT #2 - on August 8th, 2015 *
1) I am truly very sorry I have not returned earlier ... but I began to not feel well, so got a little more physical rest
2) Anyway, I implemented Dave Snyder's wonderful IIFE code and it definitely worked ... the code within the .onload Handler properly worked and I am truly extremely grateful to Dave and all the time he provided to little-ole-me. Of course, I dumped the newConnection = new MeasureConnectionSpeed() and used Dave's IIFE approach.
Now, all I have to figure out why this code is giving me about 5 Mbps speed numbers where I have 30 Mbps via my Ethernet Router. I would truly expect to see a number close.
I really, really hate to have to include another API since my whole purpose of speed measurement is to decide weather to redirect to a relatively "busy" site or to a "keep it simple" version.
Tons of thanks, Dave. You're my hero.
John Love
This works for me in Chrome.
(function(){
var imgDownloadSrc = "https://upload.wikimedia.org/wikipedia/commons/d/d8/Schwalbenschwanz_%28Papilio_machaon%29.jpg",
testImgDownload = new Image(),
startTime, endTime,
stackOverflowLog = document.getElementById('log');
var log = function(message, str) {
stackOverflowLog.innerHTML += message.replace("%s", str) + "<br>";
console.log(message, str);
}
testImgDownload.onload = function () {
log('image loaded!');
endTime = +new Date();
log('end time: %s', startTime);
log('total time: %s', (endTime - startTime));
}
testImgDownload.onerror = function (err, msg) {
throw "Invalid image, or error downloading";
}
startTime = +new Date();
log('start time: %s', startTime);
testImgDownload.src = imgDownloadSrc + "?" + startTime;
log('downloading: %s', testImgDownload.src);
})();
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Untitled Document</title>
</head>
<body>
<pre id="log"></pre>
</body>
</html>
Here's your code, slightly modified so it runs. image.onload seems to work fine, but isHighSpeed() is called before the image has finished downloading. It will need to be refactored / reordered so that you call isHighSpeed() after it's been set. It's common to use a callback for this kind of thing.
/* for illustration */
var stackOverflowLog = document.getElementById("log");
var log = function(message, str) {
stackOverflowLog.innerHTML += message.replace("%s", str) + "<br>";
console.log(message, str);
}
/* calling.html */
var newConnection = new MeasureConnectionSpeed();
log('newConnection.isHighSpeed()? %s', newConnection.isHighSpeed());
/* called.html */
function MeasureConnectionSpeed() {
var connection = this;
var imgDownloadSrc = "https://upload.wikimedia.org/wikipedia/commons/d/d8/Schwalbenschwanz_%28Papilio_machaon%29.jpg";
var imgDownloadSize = 1709360 * 8; // bits (~1.6mb * 8)
var startTime = 0,
endTime = 0; // set later
connection.isHighSpeedConnection = undefined; // = a Object Property
// an Object Method ...
// just the function declaration which is called via
// connection.computeResults()
connection.isHighSpeed = isHighSpeed;
connection.computeResults = computeResults; // another Object Method
var testImgDownload = new Image();
testImgDownload.onload = function () {
endTime = (new Date()).getTime();
log('endTime: %s', endTime);
connection.computeResults();
} // testImgDownload.onload
testImgDownload.onerror = function (err, msg) {
log("!!! ERROR Invalid image, or error downloading");
}
// We immediately continue while testImgDownload is still loading ...
// the timer is started here and ended inside testImgDownload.onload
startTime = (new Date()).getTime();
log('startTime: %s', startTime);
// This forces an attempt to download the testImgDownload and get the
// measurements withOUT actually downloading to your Cache:
var cacheBuster = "?nnn=" + startTime;
testImgDownload.src = imgDownloadSrc + cacheBuster;
log('loading: %s', testImgDownload.src);
function computeResults() {
var duration, speed, speedMbps;
duration = (endTime - startTime) / 1000; // seconds
speed = imgDownloadSize / duration; // bits per second
speedMbps = speed / 1000000; // megabits
log('duration: %s', duration);
log('speed: %s', speed);
log('speedMbps: %s', speedMbps);
connection.isHighSpeedConnection = speedMbps > 20;
} // computeResults
// this.isHighSpeed() = isHighSpeed()
function isHighSpeed() {
return connection.isHighSpeedConnection;
}
} // MeasureConnectionSpeed
<pre id="log"></pre>
How can I send two Javascript values to a xively feed, One as the ID and one as the value. Current code is. I want to get those values in to a xively feed so I can access them via an arduino with wifi. Unfortunately getting the values directly from the website from JS does not seem straight forward so this is my workaround unless anyone has a better way of accessing this data from an arduino. Using this example for reference execept i want to send the data from website rather than retrieve it. http://xively.github.io/xively-js/tutorial/
<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script src="jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="parse-1.2.16.min.js"></script>
</head>
<body>
<script>
jQuery(function($){
xively.setKey( "APIKEY" );
Parse.initialize("APIKEY", "APIKEY");
var mValue = Parse.Object.extend("mValue");
var queryLngLat = new Parse.Query(mValue);
var classObject = new mValue();
var existingMarkers= [];
var databaseMarkers= [];
var counter = 0;
var div ;
var resultsLength;
setInterval(function update() {
queryLngLat.notEqualTo("longAndLat", null);
queryLngLat.find({
success: function(results) {
console.log("Successfully retrieved " + results.length + " scores.");
for (var j = 0; j < results.length; j++ ) {
databaseMarkers = (results[j].attributes.longAndLat);
resultsLength = results.length;
counter++;
var markerValueRead = results[j].attributes.Val;
CoordsPush = databaseMarkers.substring(1, databaseMarkers.length - 1);
div = document.createElement("div");
div.style.width = "400px;";
div.style.background = "white";
div.style.color = "black";
div.innerHTML = /*"Database LatLng: " + CoordsPush + " Marker Value: " + */markerValueRead;
div.setAttribute("id", CoordsPush);
document.body.appendChild(div);
//alert(div.id);
JSON.stringify(markerValueRead);
xively.setKey("UYby76Zocsur664I6sRd13BXKUKrpM3xDSntN5qB5fvPxMhG");
var feedID = 129375335,
datastreamID = "LatLng";
selector = "50.3754565, -4.14265649999993"
xively.datastream.get(feedID, datastreamID, function(datastream) {
$selector.html( datastream["current_value"] );
xively.datastream.subscribe(feedID, datastreamID, function( even, datastream_updated) {
$(selector).html(datastream_updated["current_value"]);
});
});
//console.log("(" + markers[d].getPosition().d + ", " + markers[d].getPosition().e +")");
console.log("Database LatLng: " + databaseMarkers + " Marker Value: " + markerValueRead);
}
counter = 0;
}
});
document.body.innerHTML = '';
}, 15000);
});
</script>
<script src="http://d23cj0cdvyoxg0.cloudfront.net/xivelyjs-1.0.4.min.js"></script>
</body>
</html>
Here's a simple example of sending a single value to each of two channels ("foo" and "bar") in a feed...
<!DOCTYPE HTML>
<html>
<head>
<title>Xively Test</title>
<script language="JavaScript" type="text/javascript" src="lib/jquery/jquery-1.10.2.min.js"></script>
<script language="JavaScript" type="text/javascript" src="lib/xively/xivelyjs-1.0.4.min.js"></script>
<script language="JavaScript" type="text/javascript">
var API_KEY = "YOUR_API_KEY";
var FEED_ID = "YOUR_FEED_ID";
$(document).ready(function() {
// Set your API key first
xively.setKey(API_KEY);
// build the data packet
var timestamp = new Date().toISOString();
var data = { "version" : "1.0.0",
"datastreams" : [
{ "id" : "foo", "datapoints" : [ {"at" : timestamp, "value" : 10} ] },
{ "id" : "bar", "datapoints" : [ {"at" : timestamp, "value" : 20} ] }
]
};
// upload the data
xively.feed.update(FEED_ID, data, function(response) {
if (response.status == "200") {
console.log("Yay, it worked!: " + JSON.stringify(response, null, 3));
}
else {
console.log("Boo, something went wrong!: " + JSON.stringify(response, null, 3));
}
});
});
</script>
</head>
<body>
Look in the console for output.
</body>
</html>