I have an array of data in the following form:
_data = [
{key: <String>, values: [<number>...]}
]
If the 'values' variable in each JSON object were an array of JSON coordinates (i.e. "x: ?, y: ?"), I could just use the following:
d3.layout.stack()
.values(function(d) {
return d.values;
});
Instead, I need to read x from each layer's values array as the index in the values array, and y as the number. Like so:
_data = [
{key: "oranges", values: [5, 6, 8]},
{key: "bananas", values: [2, 1, 9]}
]
becomes
"oranges": (0, 5), (1, 6), (2, 8);
"bananas": (0, 2), (1, 1), (2, 9);
How can this be done?
If I understand your question correctly, you are looking for the appropriate accessor function to access your specific data format from within D3's stack layout. The following code should do what you are looking for:
d3.layout.stack()
.values(function(d) {
return d.values.map(function(y, i) {
return { "x": i, "y": y };
});
});
The call to .map() will transform your data.values array and return an array consisting of objects having x and y coordinates set to the values you specified.
Is this what you're looking for?
var data = [
{key: "oranges", values: [5, 6, 8]},
{key: "bananas", values: [2, 1, 9]}
];
var newData = [];
var fruit;
var coords;
for (var i = 0; i < data.length; i++) {
coords = [];
for (var x = 0; x < data[i].values.length; x++) {
coords.push([x, data[i].values[x]]);
}
fruit = {};
fruit[data[i].key] = coords;
newData.push(fruit);
}
alert(JSON.stringify(newData));
Or something like this? Where you format only the array you need, when you need it?
d3.layout.stack()
.values(function(d) {
var coords = [];
for (var x = 0; x < d.values.length; x++) {
coords.push([x, d.values[x]]);
}
return coords;
});
Related
How can I write a function swap that takes 3 arguments, two arrays and a number and swaps two items in these arrays at the specified position/index which is the third argument,and then return these two arrays inside another array?
I tried this
function swap (arr1, arr2, pos) {
var x = arr1[pos];
arr2.splice(pos, 1, x);
var y = arr2[pos];
arr1.splice(pos, 1, y)
var newArray = arr1 + arr2;
}
But is not working. I just get undefined in the console.
function swap (arr1, arr2, pos) {
var x = arr1[pos];
var y = arr2[pos];
arr1[pos] = y;
arr2[pos] = x;
return [arr1, arr2];
}
It can be done using this nefty trick
const array1 = [1,2,3];
const array2 = [4,5,6];
function swap (arr1, arr2, pos) {
[arr1[pos],arr2[pos]] = [arr2[pos],arr1[pos]];
return [...arr1, ...arr2];
}
console.log(swap(array1, array2, 1));
You forgot to write return at the end
function swap (arr1, arr2, pos) {
var x = arr1[pos];
arr2 = arr2.splice(pos, 1, x);
var y = arr2[pos];
arr1 = arr1.splice(pos, 1, y)
return arr1 + arr2;
}
Try this code... I hope this serves your problem
let arr1 = [11, 12, 13, 14, 15];
let arr2 = [21, 22, 23, 24, 25];
let pos = 2;
function swap(arr1, arr2, pos) {
var x = arr1[pos];
var y = arr2[pos];
arr2.splice(pos, 1, x);
arr1.splice(pos, 1, y)
var newArray = [...arr1, ...arr2];
return newArray
}
let x = swap(arr1, arr2, pos);
console.log(x)
Output
[ 11, 12, 23, 14, 15, 21, 22, 13, 24, 25 ]
I think I'm misunderstanding something about variable scope in JavaScript. The goal is, given an array of numbers, to generate a 2D array that contains all the rotations of that array. So, the array [1,2,3,4] should yield a 2D array of:
[ [1,2,3,4],[2,3,4,1],[3,4,1,2],[2,3,4,1] ]
I'm coming from Ruby, where the following would work just fine:
row = [3,1,6,4];
function rotations(arr) {
var rotations = [];
var i = 0;
var k = arr.length;
while(i < k) {
arr.unshift(arr.pop());
rotations.push(arr);
i++;
};
return rotations;
};
console.log(rotations(row));
However, what this logs is a 2D array containing 4 iterations of the original array:
[ [ 3, 1, 6, 4 ], [ 3, 1, 6, 4 ], [ 3, 1, 6, 4 ], [ 3, 1, 6, 4 ] ]
So it appears that the original array row is not being modified in the scope of the function - only in the scope of the nested while loop.
You just need to copy your array before modifying it with unshift, because it modifies origin array
var row = [3,1,6,4];
function rotations(arr) {
var rotations = [arr];
var i = 1;
var k = arr.length;
var copiedArr = arr
while(i < k) {
copiedArr = [...copiedArr]
copiedArr.unshift(copiedArr.pop());
rotations.push(copiedArr);
i++;
};
return rotations;
};
console.log(rotations(row));
console.log(rotations([1,2,3,4]))
More about unshift is here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift
Or if you need the first element also being rotated
var row = [3,1,6,4];
function rotations(arr) {
var rotations = [];
var i = 0;
var k = arr.length;
var copiedArr = arr
while(i < k) {
copiedArr = [...copiedArr]
copiedArr.unshift(copiedArr.pop());
rotations.push(copiedArr);
i++;
};
return rotations;
};
console.log(rotations(row));
console.log(rotations([1,2,3,4]))
I render a line chart using Chart.js. I don't want to rescale the x-axis to get more sample points.
What would be the best way to render jumps in case y axis values change discontinuously?
Ideally, I would be able to define two y values per x value. So assuming my passed in data array for {datasets: [{data : []}]} is [1, 2, 4, 5] with a jump at idx 1 then I would like to define it as [1, [2, 3], 4, 5].
Here you go: https://jsbin.com/kacecejade/1/edit?js,output
I loop through the data array and when there's not a number but an array I double the array element in the labels array so I have two labels for two data.
var sLabels = ['2018-10-26', '2018-11-02', '2018-11-09', '2018-11-16', '2018-11-23', '2018-11-30', '2018-12-07', '2018-12-14', '2018-12-20', '2018-12-28', '2018-12-31', '2019-01-01', '2019-01-04', '2019-01-11', '2019-01-18']
var sData = [-4.43, [-3.47, -3.34], -3.62, [-4.20, -3.70], -4.04, -3.75, -4.46, -4.50, -4.50, -4.50, -4.05, [-3.76, -3.64], [-3.38, -3.09], -3.24, -2.88]
function formatData() {
var newLabels = []
var newData = []
for (var i = 0; i < sLabels.length; i++) {
if (Array.isArray(sData[i])) {
for (var j = 0; j < sData[i].length; j++) {
newLabels.push(sLabels[i])
newData.push(sData[i][j])
}
} else {
newLabels.push(sLabels[i])
newData.push(sData[i])
}
}
return [newLabels, newData]
}
var [labels, datasetData] = formatData()
var data = {
labels: labels,
datasets: [{
data: datasetData,
lineTension: 0
}]
}
I have a function that takes an array of arrays and two input values. The function needs to return an array containing all of this information; however, once the third level of arrays is accessed, it copies a value of "undefined", instead of the actual array that is there.
I have also tried passing in a copy of the array instead of the original reference, but the same issue occurs.
function relation(list, x, y){
var x = [list, x, y];
return x;
}
The attempt using the copy function:
function copy(list){
var newList = [];
for (var i = 0; i < list.length; i++){
if (Array.isArray(list[i])){
newList[i] = list[i].slice();
}
else newList[i] = list[i];
}
return newList;
}
function relation(copy(list), x, y){
var x = [list, x, y];
return x;
}
Regardless of which version of relation() is used, calling the function
var x = [0, [0, [0, 1, 2] ] ];
var y = relation(x, 5, 10);
console.log(y);
should be
[ [ 0, [ 0, [0, 1, 2] ] ], 5, 10]
But actually returns
[ [ 0, [ 0, [Array] ] ], 5, 10]
Likewise, when trying to access elements in the innermost array:
console.log(y[0][0][0]);
the function returns undefined.
Is there an easy way to copy this innermost array?
Just use console.log(JSON.stringify(y)) and you will realize that everything works as you expected.
For a shallow copy of an array use the spread operator: ...
let copy = [...array]
BTW be mindful of how you assign your variables: var x = [list, x,y];
var nested = [0, [0, [0, 1, 2] ] ];
function notMuchChanged(array, x, y){
let outerArray = [];
let copyArray = [...array];
outerArray.push(copyArray);
outerArray.push(x);
outerArray.push(y);
return outerArray;
}
console.log(JSON.stringify(notMuchChanged(nested, 5, 10)));
I have a JSON object returned from a web service, which is an array of objects. I need to add the "data" arrays together to form a summed array. The JSON response looks like this:
[
{
"data":[
0,3,8,2,5
],
"someKey":"someValue"
},
{
"data":[
3,13,1,0,5
],
"someKey":"someOtherValue"
}
]
There could be N amount of objects in the array. The desired output for the above example would be:
[3, 16, 9, 2, 10]
I was intending on creating an empty array variable (var arr), then looping over the objects, and for each object, loop through the "data" key and for each key increment the corresponding key in arr by the value.
Is there a more efficient way of doing this using some sort of merge function?
How about this, I believe it should work for all cases.
var data = [{
"data": [
0, 3, 8, 2, 5
],
"someKey": "someValue"
}, {
"data": [
3, 13, 1, 0, 5
],
"someKey": "someOtherValue"
}];
var datas = data.reduce(function(a, b) {
b.data.forEach(function(x, i) {
a[i] = a[i] || 0;
a[i] += x;
});
return a;
}, []);
console.log(datas);
If every object has the same data length, you can try with:
var input; // Your input data
var output = [];
for (var i = 0; i < input[0].data.length; i++) {
output[i] = input.reduce(function(prev, item) {
return +(item.data[i]) + prev;
}, 0);
}
console.log(output);
// [3, 16, 9, 2, 10]
If every object has different data size:
var input; // Your input data
var i = 0, output = [];
while (true) {
var outOfIndex = true;
var sum = input.reduce(function(prev, item) {
if (item.data[i] !== undefined) {
outOfIndex = false;
}
return +(item.data[i]) + prev;
}, 0);
if (outOfIndex) {
break;
}
output[i++] = sum;
}
console.log(output);
// [3, 16, 9, 2, 10]
Slightly less imperative solution:
//zip takes two arrays and combines them per the fn argument
function zip(left, right, fn) {
var shorter = (right.length > left.length) ? left : right;
return shorter.map(function(value, i) {
return fn(left[i], right[i]);
});
}
//assuming arr is your array of objects. Because were using
//zip, map, and reduce, it doesn't matter if the length of the
//data array changes
var sums = arr
.map(function(obj) { return obj.data; })
.reduce(function(accum, array) {
//here we want to combine the running totals w/the current data
return zip(accum, array, function(l, r) { return l + r; });
});