I'm doing a pretty trivial thing in D3, but I'm running into weird issues with the order of code execution. I'm taking an array of image names, looping through them, and adding each svg to a parent svg as a g element. All that works great. Here's the code that's doing so:
var names = ['a', 'b', 'c']
var over = d3.select('#overlay');
var w = 20;
for (var i = names.length - 1; i >= 0; i--) {
var x = w * i + w
console.log('1. '+ x)
d3.xml(names[i]+'.svg', function(error, xml) {
console.log('2. '+ x)
over.append('g')
.attr('transform','translate('+ x +','+ 20 +')')
.html(xml.getElementsByTagName('svg')[0].innerHTML)
})
}
However, I'm running into issues with the transforms all being the same, and decided to log x to check it out. The log should be this:
1. 60
2. 60
1. 40
2. 40
1. 20
2. 20
Instead, it's logging this:
1. 60
1. 40
1. 20
2. 20
2. 20
2. 20
What could possibly be making this run out of order like that?? Is the d3.xml call asynchronous? I can't figure it out.
d3.xml() is asynchronous function and is not started in sequence as expected but little later which is enough that loop is over and x has value 20.
You have to make closure for value x using for example:
(function (x) {
d3.xml(names[i]+'.svg', function(error, xml) {
console.log('2. '+ x)
over.append('g')
.attr('transform','translate('+ x +','+ 20 +')')
.html(xml.getElementsByTagName('svg')[0].innerHTML)
});
})(x)
That way you will get in console log:
1. 60
1. 40
1. 20
2. 60
2. 40
2. 20
Related
I have following code and want to check commutative property with impure functions. Can anyone explain why the first two console log print 3, 3 and why the direct function call print 3 and -3?
var multi = 1;
const f = x =>{
multi = -multi;
return x * multi;
}
let a = f(2);
let b = f(5);
console.log("a+b:: ",a+b);
console.log("a+b:: ",b+a);
console.log("a+b:: ",f(2) + f(5));
console.log("a+b:: ",f(5) + f(2));
Any suggestions/explanation is appreciated.
For the first two logs, you're only invoking the functions twice - in these lines:
let a = f(2);
let b = f(5);
after which a and b don't change. 5 + -3 is the same as -3 + 5.
For the last two logs, you invoke the functions four times, and the signs invert each time the function is called, resulting in
f(2) + f(5) // -2 + 5
f(5) + f(2) // -5 + 2
Im just getting started on d3.js and was going through Nick's source code on github here and got stuck at the part where he is passing a function as data into d3.js.
The var x in the function assigned to next var gets incremented from 0 to the loop counter as i show in the jsbin link below. I cant quite wrap my head around how x gets incremented automatically and how does it know the loop counter that it needs to get incremented upto everytime.
the next variable is called from >> newdata from the >>render function ?
I just setup a jsbin here
This part:
.data(newData);
is simply going to call the newData function and bind the return to the selection.
So each call to render in the setInterval simply pushes the next function into his data array.
This part then:
selection.attr("class", "v-bar")
.style("height", function (d, i) {
return d(i) + "px"; // <- E
})
.select("span")
.text(function(d, i){
return d(i); // <- F
});
Calls d which is the next function for each element in the data array. It's passing the index position in the data array.
So the first render call is:
15 + 0 * 0;
Second is:
15 + 0 * 0;
15 + 1 * 1;
Third is:
15 + 0 * 0;
15 + 1 * 1;
15 + 2 * 2;
First, for simplification, this
var selection = d3.select("#container").selectAll("div")
.data(newData); // <- D
is just like writing
var arrayOfFunctions = newData();
var selection = d3.select("#container").selectAll("div")
.data(arrayOfFunctions); // <- D
So, for example, calling this code 3 times (via setInterval) builds up arrayOfFunctions like this:
arrayOfFunctions = [
function (x) { return 15 + x * x; },
function (x) { return 15 + x * x; },
function (x) { return 15 + x * x; }
]
(Note: it's not literally like that, because in actuality they're just pointers to the same function next)
So nothing about that increments x. But once it binds those functions to DOM elements (via data(arrayOfFunctions) and runs through this bit:
selection.attr("class", "v-bar")
.style("height", function (d, i) {
return d(i) + "px"; // <- E
})
d is function (x) { return 15 + x * x; } and i (which is 0, 1, or 2) is passed in as x to that function when it calls d(i).
And that's what essentially increments x.
So I have an array of values that I need to scale down while maintaining a minimum value for the scaled value.
For example, let's say I have an array of values [1, 1, 3, 5] with a minimum scale factor of .2.
By normalizing the array, we get the array [.1, .1, .3, .5]. However, keeping in mind the minimum scale factor, we'd have values [.2, .2, .3, .5], which adds up to 1.2, not 1.
My thinking was to iterate over the array and first set all values that would be under the minimum to the minimum, keeping a carry variable to determine how much still needs to be redistributed to the other elements in the array that were over the minimum.
With all of the values that were over the minimum, scale their values with respect to the carry variable and then subtract that from their values.
So with the example above, we'd subtract 3/8 * .2 from .3, and 5/8 * .2 from .5 to get [.2, .2, .225, .375].
Is there any other way to do this more efficiently? Or an alternative way to scale the remaining values?
Edit: Sorry, scaling might be the incorrect term, but in the end the values of the array are to be divided in such a way that their values are changed with respect to the total value.
I'll explain the specific implementation so that the question might be more clear:
I have a number of posts, and each of the posts is to be shown for a certain amount of time before fading out, after which the next post is to be shown. I want the delay between posts to be dependent on the number of words within each post, but also constrained to be at least some minimum value.
There is a total amount of time for all of the posts to be shown, and the time is supposed to be split up between all of the posts.
I want the delay between posts to be dependent on the number of words within each post, but also constrained to be at least some minimum value.
There is a total amount of time for all of the posts to be shown, and the time is supposed to be split up between all of the posts.
You cannot guarantee that you'll meet both requirements. If you have 30 posts, each of which must be displayed for at least one second, and only 20 seconds in which to display them, then it's impossible meet both requirements. You'll have to:
Extend the total time; OR
Reduce the minimum time
We have a sample set s = [ 1 1 3 5 ], and we are looking for a function f(x) which takes a single sample and returns the display time.
Requiring Sum(Map(s, f)) = 1.0, (that is, the sum of f(s) for all s[i]) and also that s[i] >= minVal for all s[i], consider first the linear function
f(x) = ax + b
For the minimum
a.xmin + b = minVal
b = minVal - a.xmin
Sum:
total = Sum(f(x) for x in s)
= Sum((a*x + b) for x in s)
= b*len(s) + Sum(a*x for x in s)
= b*len(s) + a * Sum(s)
1 = b*len(s) + a * Sum(s)
a = (b * len(s) - 1.0) / Sum(s)
Substit
1 = b*len(s) + a * Sum(s)
1 = (minVal - a.xmin) * len(s) + a * Sum(s)
1 = minVal * len(s) - xmin * len(s) * a + Sum(s) * a
1 - (minVal * len(s)) = (Sum(s) - xmin*len(s)) * a
a = (1 - (minVal * len(s))) / (Sum(s) - xmin*len(s))
Given a,
b = minVal - a.xmin
Thus in javascript we can have a function factory to give you a scaling function f, given a sample set s:
function makeScalingFun(s, minVal) {
var total = s.reduce(function(a, b) { return a + b; });
var xmin = s.reduce(function(a, b) { return Math.min(a,b); });
// f(x) = ax + b
var a = (1.0 - (minVal * s.length)) / (total - xmin * s.length)
var b = minVal - a * xmin
var f = function(x) {
return a * x + b;
};
return f;
}
And in use:
var scaler = makeScalingFun(s, 0.2);
console.log("Index, Value: Calced Delay");
for(var i = 0; i < s.length; ++i) {
console.log(i + ", " + s[i] + ": " + scaler(s[i]));
}
Result:
Index, Value: Calced Delay
0, 1: 0.2
1, 1: 0.2
2, 3: 0.26666666666666666
3, 5: 0.3333333333333333
If you have further requirements, you could use them to construct a quadratic target function instead of a linear one, etc.
Note that the smallest value always gets given the minVal delay, which isn't perhaps very realistic. Consider modifying to use a constant value for xmin, e.g. 0, so that if you have 3 posts of 450, 451 and 452, you don't just get a comparatively tiny delay for the first just because it's the shortest.
I would take the following approach:
Assume you have the values as in your example: [1 1 3 5]. The sum of the values is 10.
So, divide all values by 10 and correct the values under the minimum. Keep track of the number of corrected values. In this case that's 2. Multiply 2 by .2. That is .4.
Now, 1 - .4 = .6 should be divided over the values 3 and 5. The sum of 3 and 5 is 8. So, divide each uncorrected original value by 8 and multiply it by .6: e.g. 3 / 8 * .6.
That will give you your normalized list of values: [.2 .2 .225 .375].
Obviously you can't scale the terms in the usual sense of the word, as you may end up with times less than your minimum time. Also you will have trouble if the number of posts * minimum time exceeds your total time available.
But assuming not...I would suggest giving each post the minimum time plus extra time proportional to the number of extra words in the longer documents. So, given the values [1 1 3 5] and the requirement that the minimum is 0.2...
1) Subtract the minimum value from each value to give [0 0 2 4]
2) Normalize this to give [0 0 0.333 0.667]
3) Scale by (1 - 4*0.2) (that is 1 - number_of_values*min_time) to give [0 0 0.0667 0.133333]
4) Finally add the minimum to each value to give [0.2 0.2 0.267 0.333]
Now each post gets a base time plus an extra time proportional to its extra length.
I'm having some problems with this code. My problem is that with the code below, it doesn't plus the detection-ratio text with the 'incr'. It just enters the incr, but doesn't plus.
This is my code.
(function loop() {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
var incr=Math.floor(Math.random()*6);
setTimeout(function() {
document.getElementById('detection-ratio').innerText = '0 / '+ ++incr;
loop();
}, rand);
}());
The 'detection-ratio' text looks like this as default:
0 / 0
Then, lets say 'incr' generates the number '3', then it should increase the last 0 with 3, so it would look like this:
0 / 3
Then, lets say it's going to generate a new 'incr', lets say '5'. Then it would look like this:
0 / 8
---> But right now, it doesn't do that. It just writes the 'incr' into the 'detection-ratio' without increasing it.
Hope this code would help you to get the expected output, let me know if something breaks. Also stop iteration once it reaches > 26
var incr = 0;
(function loop() {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
incr += Math.floor(Math.random()*6);
setTimeout(function() {
console.log('0 / '+ incr);
loop();
}, rand);
}());
Thanks for the explanation and patience.
I am assuming you are trying to append text to detection-ratio
if so you need to
document.getElementById('detection-ratio').innerText += '0 / '+ incr;
++ before a variable is a pre-increment operator, since you are generating random numbers i am assuming that is not actually what you want.
Since you're calling the loop recursively anyway, you may want to consider a more functional approach:
(function loop(startctr) {
var rand = Math.round(Math.random() * (3000 - 500)) + 500;
nextctr = startctr + Math.floor(Math.random()*6);
setTimeout(function() {
console.log('0 / '+ nextctr);
loop(nextctr);
}, rand);
}(0));
So this is the question that is given.
You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.
At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.
And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time.
Is this a trick question or something? Because I'm not sure what to do from here.
Here is the jsfiddle http://jsfiddle.net/cQUaH/
var console = {
log : function(s) {
document.body.innerHTML += s + "<br>";
}
};
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 2;
while(chairArr.length > 1) {
console.log('removing ' + chairArr[j]);
chairArr.splice(j, 1);
j++;
if(j >= chairArr.length) {
console.log('--- Finished pass');
console.log('--- Array state:');
console.log(chairArr);
j = (j == chairArr.length) ? 0 : 1;
}
}
console.log('--- Final result: ' + chairArr);
//result 74
With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.
A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.
The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.
As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [3,4,5,2].
var killAndRotate = function(array) { // say [1,2,3,4,5]
var dead = array.shift(), // dead = 1, array = [2,3,4,5]
skipped = array.shift(); // skipped = 2, array = [3,4,5]
array.push(skipped); // array = [3,4,5,2]
}
And then the main loop becomes:
while (chairArray.length > 1) {
killAndRotate(chairArray);
}
alert(chairArray[0]); // or console.log, or return.
// In turn, array is:
// [1,2,3,4,5]
// [3,4,5,2]
// [5,2,4]
// [4,2]
// [2] and we alert, log, or return 2.
Added
The easy way to find that result for the original Josephus problem is to see that:
If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.
1 2 3 4 5 6 7 8
X X X X
Now there are 2^(l - 1) people. Again, the first person survives:
1 2 3 4 5 6 7 8
X X X X
X X
Repeat the process; the first person survives each pass, and so is the last survivor.
Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.
1 2 3 4 5 6 7 8 9 10 11 12 13
X X X X X Y
Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.
One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.
It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.
var chairArr = [];
for (var i = 1; i <= 100; i++)
chairArr.push(i);
for (i = 1; i < chairArr.length-2; i = i + 2)
chairArr.push(chairArr[i]);
console.log('--- Final result: ' + chairArr[i]);
What have you described here is the Josephus problem, and can be solved using dynamic programming:
function josephus(n, k)
{
if (n == 1) {
return 1;
} else {
return ((josephus(n-1, k) + k - 1) % n) + 1;
}
}
alert(josephus(100, 2));
Source: Wikipedia
The n denotes the number of chairs and k indicates every kth person leaving.
The result here is 73.
Update
Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)
Solving your code problem is rather simple, start with the first person instead of the third in the first round.
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 0;
while (chairArr.length > 1) {
chairArr.splice(j, 1);
j = (j + 1) % n;
}
You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}
And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}
The cool thing about the original problem, is that you can work with binary. For example:
100 = 1100100
Take the first '1' and place it to the last:
1001001 = 73