d3.min / d3.max - getting values with related date - javascript
I'm using d3.js for displaying some line-graphs based on a csv-file which holds the SERP-rankings for different keywords for each day.
The structure of the csv-file looks like this:
Keyword,Date,Google
Keyword1,2015/5/24,6
Keyword1,2015/5/25,6
Keyword1,2015/5/26,6
Keyword1,2015/5/27,6
Keyword1,2015/5/28,6
Keyword1,2015/5/29,6
Keyword1,2015/5/30,6
Keyword1,2015/5/31,6
Keyword1,2015/6/1,6
Keyword1,2015/6/2,6
Keyword1,2015/6/3,6
Keyword1,2015/6/4,6
Keyword1,2015/6/6,6
Keyword1,2015/6/7,6
Keyword1,2015/6/8,6
Keyword1,2015/6/9,6
Keyword1,2015/6/10,6
Keyword1,2015/6/11,6
Keyword1,2015/6/12,6
Keyword1,2015/6/13,6
Keyword1,2015/6/14,6
Keyword1,2015/6/16,6
Keyword1,2015/6/17,6
Keyword1,2015/6/18,6
Keyword1,2015/6/19,6
Keyword1,2015/6/20,6
Keyword1,2015/6/21,20
Keyword1,2015/6/22,20
Keyword1,2015/6/23,20
Keyword1,2015/6/24,20
Keyword1,2015/6/25,21
Keyword1,2015/6/26,21
Keyword1,2015/6/27,21
Keyword1,2015/6/28,21
Keyword1,2015/6/29,21
Keyword1,2015/6/30,21
Keyword1,2015/7/1,21
Keyword1,2015/7/2,21
Keyword1,2015/7/3,22
Keyword1,2015/7/4,22
Keyword1,2015/7/5,22
Keyword1,2015/7/6,22
Keyword1,2015/7/7,22
Keyword1,2015/7/8,22
Keyword1,2015/7/9,22
Keyword1,2015/7/10,22
Keyword1,2015/7/11,22
Keyword1,2015/7/12,22
Keyword1,2015/7/15,22
Keyword1,2015/7/16,21
Keyword1,2015/7/19,21
Keyword1,2015/7/20,21
Keyword1,2015/7/21,21
Keyword1,2015/7/22,21
Keyword1,2015/7/24,21
Keyword1,2015/7/25,20
Keyword1,2015/7/26,21
Keyword1,2015/7/27,21
Keyword1,2015/7/28,22
Keyword1,2015/7/29,20
Keyword1,2015/7/30,20
Keyword1,2015/7/31,20
Keyword1,2015/8/1,21
Keyword1,2015/8/3,22
Keyword1,2015/8/4,22
Keyword1,2015/8/5,18
Keyword1,2015/8/6,35
Keyword1,2015/8/7,5
Keyword1,2015/8/8,5
Keyword1,2015/8/9,3
Keyword1,2015/8/10,3
Keyword1,2015/8/11,3
Keyword1,2015/8/12,3
Keyword1,2015/8/13,3
Keyword1,2015/8/14,3
Keyword1,2015/8/15,3
Keyword1,2015/8/16,3
Keyword1,2015/8/16,6
Keyword2,2015/5/6,40
Keyword2,2015/5/7,39
Keyword2,2015/5/8,41
Keyword2,2015/5/9,41
Keyword2,2015/5/10,41
Keyword2,2015/5/11,48
Keyword2,2015/5/12,45
Keyword2,2015/5/13,44
Keyword2,2015/5/14,45
Keyword2,2015/5/15,49
Keyword2,2015/5/16,49
Keyword2,2015/5/17,91
Keyword2,2015/5/18,26
Keyword2,2015/5/19,27
Keyword2,2015/5/20,26
Keyword2,2015/5/21,55
Keyword2,2015/5/22,51
Keyword2,2015/5/23,51
Keyword2,2015/5/24,56
Keyword2,2015/5/25,26
Keyword2,2015/5/26,59
Keyword2,2015/5/27,59
Keyword2,2015/5/28,58
Keyword2,2015/5/29,58
Keyword2,2015/5/30,58
Keyword2,2015/5/31,53
Keyword2,2015/6/1,57
Keyword2,2015/6/2,56
Keyword2,2015/6/3,57
Keyword2,2015/6/4,59
Keyword2,2015/6/6,28
Keyword2,2015/6/7,54
Keyword2,2015/6/8,53
Keyword2,2015/6/9,51
Keyword2,2015/6/10,57
Keyword2,2015/6/11,59
Keyword2,2015/6/12,60
Keyword2,2015/6/13,55
Keyword2,2015/6/14,55
Keyword2,2015/6/16,55
Keyword2,2015/6/17,55
Keyword2,2015/6/18,59
Keyword2,2015/6/19,57
Keyword2,2015/6/20,59
Keyword2,2015/6/21,29
Keyword2,2015/6/22,27
Keyword2,2015/6/23,29
Keyword2,2015/6/24,29
Keyword2,2015/6/25,31
Keyword2,2015/6/26,28
Keyword2,2015/6/27,28
Keyword2,2015/6/28,27
Keyword2,2015/6/29,35
Keyword2,2015/6/30,35
Keyword2,2015/7/1,34
Keyword2,2015/7/2,29
Keyword2,2015/7/3,29
Keyword2,2015/7/4,25
Keyword2,2015/7/5,25
Keyword2,2015/7/6,27
Keyword2,2015/7/7,27
Keyword2,2015/7/8,27
Keyword2,2015/7/9,27
Keyword2,2015/7/10,30
Keyword2,2015/7/11,29
Keyword2,2015/7/12,29
Keyword2,2015/7/15,26
Keyword2,2015/7/16,25
Keyword2,2015/7/19,23
Keyword2,2015/7/20,27
Keyword2,2015/7/21,28
Keyword2,2015/7/22,28
Keyword2,2015/7/23,21
Keyword2,2015/7/24,21
Keyword2,2015/7/25,20
Keyword2,2015/7/26,20
Keyword2,2015/7/27,27
Keyword2,2015/7/28,26
Keyword2,2015/7/29,27
Keyword2,2015/7/30,20
Keyword2,2015/7/31,20
Keyword2,2015/8/1,21
Keyword2,2015/8/3,21
Keyword2,2015/8/4,21
Keyword2,2015/8/5,20
Keyword2,2015/8/6,19
Keyword2,2015/8/7,33
Keyword2,2015/8/8,30
Keyword2,2015/8/9,29
Keyword2,2015/8/10,29
Keyword2,2015/8/11,29
Keyword2,2015/8/12,26
Keyword2,2015/8/13,27
Keyword2,2015/8/14,37
Keyword2,2015/8/15,33
Keyword2,2015/8/16,36
Keyword2,2015/8/16,36
When I use some code the "normal" way, like I saw in my researches, everything works fine:
s.max = d3.max(s.values, function (d) {
return d.Google;
})
s.min = d3.min(s.values, function (d) {
return d.Google;
})
This works well and outputs this:
Keyword1
Best position: 3
Worst position: 35
Keyword2
Best position: 19
Worst position: 91
But this only outputs the Google-value.
What I want to achieve is that the related "Date" to the found max-value gets displayed as well.
So I tried it like this:
s.max = d3.max(s.values, function (d) {
var parseDate = d3.time.format("%d-%m-%Y");
return d.Google + " (" + parseDate(d.Date) + ")";
})
s.min = d3.min(s.values, function (d) {
var parseDate = d3.time.format("%d-%m-%Y");
return d.Google + " (" + parseDate(d.Date) + ")";
})
This looks nice at first. But the problem is, that sometimes the output isn't correct.
Keyword1
Best position: 18 (05-08-2015)
Worst position: 6 (31-05-2015)
Keyword2
Best position: 19 (06-08-2015)
Worst position: 91 (17-05-2015)
So as you can see, the output for Keyword2 is correct, but not for Keyword1 ,which should be :
Keyword1
Best position: 3 (09-08-2015)
Worst position: 35 (06-08-2015)
I also tried it without the "parseDate", but this results in the same wrong output.
Can anyone tell me what is getting wrong here, why the output isn't correct?
Looks like in the first example you are sorting numbers and in the second you are sorting strings. 3 < 21 and "3" > "21" are both true. It's not the most efficient approach in the world, but I'd say just sort your array by number and then grab the first and last elements. Something like:
var sorted = s.values.map(function(d) { return d; }).sort(function(a,b) {
return b.Google - a.Google;
});
// Note: I can never remember if Array.sort is ascending or descending by default. Use with caution.
var max = sorted[0].Google + " (" + formatDate(sorted[0].Date) + ")";
var min = sorted[sorted.length - 1].Google + " (" + formatDate(sorted[sorted.length - 1].Date) + ")";
Then do whatever you want to build your displayed string based on min/max.
Related
JavaScript Math Expression Yields Different Results
The following is a line I have in my Javascript code. It outputs -5108024 and some change when sqftVal = 2828 and bathsVal = 3.5. out.value = -6932000 + 221400 * Math.log(sqftVal) + 637.2*Math.exp(bathsVal) + 51640; However, when I manually type this in my calculator, I get roughly -5099721 and some change. I get the same result in R. Why does JavaScript mess up the math, and what can I do to fix this? Calculator/R input: -6932000 + 221400 * ln(2828) + 637.2 * e^(3.5) + 51640 = -5099721.073 I don't believe this is a floating point error because as I add more terms, the difference becomes fairly large. Plus, everything was matching up until I added the fourth term (+51640) which made no sense to me.
There must be some other code that is interfering with your values or something, because the code shown does not produce the value you report. var sqftVal = 2828; var bathsVal = 3.5; var value = -6932000 + 221400 * Math.log(sqftVal) + 637.2*Math.exp(bathsVal) + 51640; console.log(value);
Loop through attributes but only output certain ones - javascript
I dont know much of js but I have a code that with a little modification, will do exactly what I want. So here is a part of it that Im stuck. I have some visual objects that have several attributes, most of these attributes are needed for drawing them on the map so I cant just comment them out. I also have a function that prints all the attributes of the object on("mouseover"). I want it to only display the attributes I want, not all. .on("mouseover", function(d) { var out = ""; out += d.name + "<br /><br />"; for (v in d) { out += (!Number.isNaN(Number(d[v])) ? v + ": " + Number(d[v]) + "<br />" : ""); } document.getElementById("detail").innerHTML = out; } I understand what this code does, but what is the most elegant way to constraint the for loop or the out to only include the attributes I want? The current outcome obj name attrIwant1: value attrIwant2: value attrIwant3: value attrIwant4: value w: blah x: blah y: blah z: blah I only want to display up until w:blah.
Put the attributes you care about in a set, then when you loop, see if d[v] belongs to the set. const set1 = new Set(['attrIWant1', 'attrIWant2']); // add the attributes here for (v in d) { if (set1.has(d[v])) { // this is one we care about } } Read more about sets here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
If you always expect the same number of attributes, you can terminate the loop early when out has a certain number of <br />'s in it. In your example you want to stop when you have 4 attributes, so you would terminate the loop when out contains 6 <br />'s. Your new for loop would be this: for (v in d) { out += (!Number.isNaN(Number(d[v])) ? v + ": " + Number(d[v]) + "<br />" : ""); if (out.match(/<br \/>/g).length === 6) break; } It is not "elegant", but it's probably the best you'll get without telling me what d is :^)
"Try...Catch" Block not Working with parseInt()
What I'm trying to do: I have a javascript program that, when a button is clicked, takes in 4 strings from 4 text boxes in a form, and outputs those strings into a formatted textarea. function testResults(form){ var errorhandle1 = parseInt(document.myForm.Item_Code.value); var errorhandle2 = parseInt(document.myForm.Item_Cost.value); var errorhandle3 = parseInt(document.myForm.Quantity.value); //above variables are for error handling. var d = " "; var subtotal = parseInt(form.Item_Cost.value) * parseInt(form.Quantity.value); var subtotalValue = parseInt(document.myForm.Subtotal.value); var testVar = "Item Code: " + form.Item_Code.value + d + "Item Name: " + form.Item_Name.value + d + "Item Cost: " + form.Item_Cost.value + d + "Quantity: " + form.Quantity.value + '\n'; document.myForm.myTextarea.value += testVar; document.myForm.Subtotal.value = parseInt(subtotal) + subtotalValue; document.myForm.Sales_Tax.value = document.myForm.Subtotal.value * salestax; document.myForm.Total.value = parseInt(document.myForm.Subtotal.value) + parseFloat(document.myForm.Sales_Tax.value); } The above code works just fine, and does exactly what I want it to do for the scope of my program. try { if ((isNaN(errorhandle3) == true) || (isNaN(errorhandle2) == true)) { throw "Error1"; } } catch (e) { if (e == "Error1") { alert("Error! You must enter a number into the qty and cost fields!"); } } What I'm trying to accomplish with the try...catch block is simply to make sure that document.myForm.Item_Code.value document.myForm.Item_Cost.value document.myForm.Quantity.value are actually numbers. The try...catch statements trigger every time I run the program and doesn't care what I put in the corresponding text boxes. I would greatly appreciate any and all insight on this! Also: I looked at both of these links and was unable to understand my problem. javascript parseInt return NaN for empty string http://www.w3schools.com/jsref/jsref_isnan.asp
Your root problem here is that isNaN() tests to see if the value is NaN. It does not test to see if a string is a proper number. It has some coercion rules to try to deal with strings, but that really isn't what it is designed for. You can see ways to test if something can be parsed into a valid number here: Validate decimal numbers in JavaScript - IsNumeric() It's worth reading the detail in the good answers there, but it boils down to something like this which is a bit more than you need, but is general purpose: function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } And, then there's no reason to use exceptions in your code, so you can just do this: if (!isNumber(errorhandle3) || !(isNumber(errorhandle2)) { alert("Error! You must enter a number into the qty and cost fields!"); } Also, in your code, some .Value properties look like maybe they should be .value (lowercase).
In your first code block var errorhandle2 = parseInt(document.myForm.Item_Cost.Value); var errorhandle3 = parseInt(document.myForm.Quantity.Value); You are using Value, which should be value, that's case-sensitive. By the way, isNaN returns boolean, you don't have to compare with true
JavaScript - Reposition a DIV incrementally onClick
Very simple code, very simple problem. When a link is pressed, it moves a div either up or down. However, I cannot get it to move incrementally. I know this is a simple syntax error, but google isn't revealing the error of my ways. Anyone willing to enlighten me? <a class="galsel" onclick="document.getElementById('innerscroll').style.bottom -='167px';">«</a> <a class="galsel" onclick="document.getElementById('innerscroll').style.bottom +='167px';">»</a> I already have it so that the div tiles itself vertically, so I'm not worried about it going "too high" or "too low" Here's what it looks like right now: drainteractive.com/FBD/projects.php
You have to parse the value from the string containing px // Increase by 167 document.getElementById('innerscroll').style.bottom = (parseInt(document.getElementById('innerscroll').style.bottom, 10) + 167) + ' px' // Decrease by 167 document.getElementById('innerscroll').style.bottom = (parseInt(document.getElementById('innerscroll').style.bottom, 10) - 167) + ' px' // Abstracted function addToBottom(el, amount) { // You probably add lower and upper bound check conditions el.style.bottom = (parseInt(el.style.bottom) + amount) + ' px'; } var el = document.getElementById('innerscroll'); addToBottom(el, 167); addToBottom(el, -167); Also be sure to make it work for cases where bottom wasn't set initially var currentBottom = parseInt(document.getElementById('innerscroll').style.bottom) || 0;
+='167px' will concatinate it an it will become '167px167px167px167px167px'. Not sure what will result -='167px', but probably will result an error.
You need to rip the 'px' off the string, convert(?) it to an int, then subtract from that. onclick="var mElem = document.getElementById('innerScroll'); mCur = parseInt(mElem.style.bottom.replace('px', 0)); mElem.style.bottom = (mCur-167)+'px'" Naturally, this should all be put into a separate function, who is then called in the onclick, rather than the monstrosity above. function moveUp() { var mElem = document.getElementById('innerScroll'); var mCur = parseInt(mElem.style.bottom.replace('px', 0)); mElem.style.bottom = (mCur-167)+'px'; } ... <strike>onlick="moveUp()"</strike> onclick="moveUp()" My mind must have been somewhere else..
display pointlabel in highlighter jqplot
I've many series of just two points on a graph to simulate a timeline. These points have a pointlabel. I'd like to have the name of that pointlabel in the highlighter. How do I do that? please see my JsFiddle http://jsfiddle.net/NVbjv/8/ I'd tried to add a highlighter object to each series, and give it a format string. But how can I make this more dynamic? I also like to only display time in the hoverbox-thingy in the bottom right. How do I get remove the ",1 " and ",2"?
The only idea that comes to my mind is to use a custom processing of the tooltip of highlighter and cursor. Something along the lines as it is presented here. In your case you would apply the following code: $("#container").bind('jqplotMouseMove', function(ev, gridpos, datapos, neighbor, plot) { var date = new Date(datapos.xaxis); var time = "" + (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":" + (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()); $(".jqplot-cursor-tooltip").html(time + " Oi"); if (neighbor) { $(".jqplot-highlighter-tooltip").html("Label name= " + neighbor.data[2] + "; time= " + time); } }); The working code sample is available here. EDIT: In Chrome I have noticed that the null is printed for the pointLabels therefore use empty strings for their values instead.