Parsing values from core-response in Polymer - javascript

I'm making a request for x and y values from a flax/python backend using Polymer and I can read the values in console for the XMLHttpResquest response, but now I need to convert the output into a set of discrete x and y values (so it can be read by C3.js - a framework sitting on top D3 for graphing).
Here's the code I'm using to get the XMLHttpResquest response:
<paper-button affirmative hover on-tap="{{addNewGraph}}">Submit</paper-button>
Polymer("add-graphItem",{
addNewGraph: function () {
var HeaderName = this.$.graphOptionsLoad.$.headerValue.selectedItem.label;
var FunctionName = this.$.graphFunctionsLoad.$.functionValue.selectedItem.label;
console.log("The options are " +HeaderName +" and " +FunctionName);
var params = {};
if (this.$.graphOptionsLoad.$.headerValue.selectedItem) {
params['DataHeader'] = this.$.graphOptionsLoad.$.headerValue.selectedItem.label;
}
if (this.$.graphFunctionsLoad.$.functionValue.selectedItem) {
params['FunctionName'] = this.$.graphFunctionsLoad.$.functionValue.selectedItem.label;
}
this.$.sendOptions.params = JSON.stringify(params);
var x = this.$.sendOptions.go();
// this.$.sendOptions.go();
console.log(x)
// var ajax = document.querySelector("sendOptions");
var results = [];
this.addEventListener("core-response",
function(e) {
console.log(x.response);
}
);
}
});
And here's an example of the output from console.log(x.response);:
{
"graph": [
{
"Header": "MakeModeChange"
},
{
"x": [
0.0,
131.35,
26971.3,
27044.75,
27351.4,
27404.483333333334,
27419.416666666668,
33128.96666666667,
33549.13333333333,
34049.48333333333,
77464.26666666666,
77609.71666666666,
174171.85,
259166.98333333334
]
},
{
"y": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14
]
}
]
}
Ultimately I need the output to look something like:
['x', 0.0, 131.35, 26971.3, 27044.75, 27351.4, 27404.483333333334...],
['y', 1, 2, 3, 4, 5, 6]

Here's a quick and dirty way to do it - not recommended for large scale or if you don't fully trust the response values. Also, obvious, but if their api/data structures changes you're SOL.
xArr = JSON.parse(x.response).graph[1].x
xArr.unshift('x')
yArr = JSON.parse(y.response).graph[2].y
yArr.unshift('y')
You'll get both arrays you'll need, you can combine as needed

Related

variable name is appended to json instead of variable value

I get a json from an API I wrote. This json contains some values and one of this should be appended to another json.
The json to append the data to is the following:
originalOrder = {
"nome": 1,
"cognome": 2,
"mail": 3,
"telefono": 4,
"cf": 5,
"data": 6,
"ora": 7,
"cellit": 8,
"cellex": 9
};
The data I need to append is:
var toAppend = data.name;
and if i echo the toAppend value it shows the correct value. Say for example that toAppend echoes dummyData. I want the json to be at the end:
originalOrder = {
"nome": 1,
"cognome": 2,
"mail": 3,
"telefono": 4,
"cf": 5,
"data": 6,
"ora": 7,
"cellit": 8,
"cellex": 9,
"dummyData": 10
};
So I also calculate the length of the array:
var lunghezza = parseInt(originalOrder.length);
lunghezza = lunghezza +2;
and then I add the new item to the array:
originalOrder.toAppend=lunghezza;
but the array ends up like this:
originalOrder = {
"nome": 1,
"cognome": 2,
"mail": 3,
"telefono": 4,
"cf": 5,
"data": 6,
"ora": 7,
"cellit": 8,
"cellex": 9,
"toAppend": NaN
};
so I have two issues:
i get the variable name instead of the variable value
I get not a number instead of 10 (I tried also to force it with parseInt but seems with no luck)
What am I doing wrong here?
Edit:
if I do
var toAppend = data.nome;
console.log('toAppend: '+toAppend);
in console.log:
toAppend: dummyData;
that is the expected behaviour
Thanks!
originalOrder is an object and for this reason, to get the number of keys (i.e., "the length of the object"), you need:
Object.keys(originalOrder).length
To add a key with the value of the var toAppend you need to write:
originalOrder[toAppend] = lunghezza
To use variable value as a key to an object you can use the square bracket in javascript.
const obj = {
"hello": "world"
};
const key = "value";
obj[key] = "any value";
console.log(obj)
will print
{
"hello": "world",
"value": "any value"
}
Also, you can't use length properties on an object. However, you can get list of keys of an object, then get the length.
console.log(Object.keys(obj).length);
will print
2
Hope this helps

Organising object data by timestep, so as to chart multiple sensor readings against time using Chart JS

I am creating a line chart using the Chart JS library. The data I am using is coming from two different temperature sensors (sensor 1 and sensor 2), that may not necessarily have the same timestamps. I want to split the data into 3 arrays:
1. Sensor 1 readings
2. Sensor 2 readings
3. Timestamps
If there is no value at a particular timestep then for one of the sensors for the other the array should have a blank value like at index 1 of this array: [0, ,1,2]
Here is an example of the data:
zdata =
{ "data": [
{
"timestamp": 10,
"sensor_id": 1,
"temp": 14.5,
},
{
"timestamp": 20,
"sensor_id": 1,
"temp": 18,
},
{
"timestamp": 30,
"sensor_id": 1,
"temp": 25.5,
},
{
"timestamp": 5,
"sensor_id": 2,
"temp": 24.5,
},
{
"timestamp": 20,
"sensor_id": 2,
"temp": 29.5,
}
]
};
And how I want the arrays to turn out:
Timestamp: [5,10,20,30]
Sensor 1: [,14.5,18,25.5]
Sensor 2: [24.5,,29.5,]
I also need the number of sensors to change dynamically, so, for example, the data could come in with 3 sensor readings and I would need an extra array to be generated.
So far I attempted the following, however, the 'result.temp' operation is returning an undefined value so the code does works.
var unique_timestamps = [...new Set(zdata.data.map(item => item.timestamp))];
console.log(unique_timestamps);
var sensors = [...new Set(zdata.data.map(item => item.sensor_id))];
console.log(sensors);
// Will hold final arrays of sensor readings
var temperature_datasets = [];
for (i = 0; i < sensors.length; i++) {
// Holds the array of temperatures for one sensor
readings_arr =[];
for (j = 0; j < unique_timestamps.length; j++) {
var result = zdata.data.filter(obj => {
return (obj.timestamp === unique_timestamps[j] && obj.sensor_id === sensors[i])
})
readings_arr[j]=result.temp;
}
temperature_datasets[i] = readings_arr
}
I have two questions:
Is there a more efficient way of doing this that will take fewer operations?
If not, why am I getting an undefined result for 'result.temp' and how can I get the temperature value.
Here is a modern ES6 version that gets you the same result and is hopefully more readable and is more performant.
Code is explained as comments.
Initially, we pivot an object with time stamp as key and sensor as values.
We then use this to get the timestamp array and an array of sensorValues as shown.
zdata =
{ "data": [
{
"timestamp": 10,
"sensor_id": 1,
"temp": 14.5,
},
{
"timestamp": 20,
"sensor_id": 1,
"temp": 18,
},
{
"timestamp": 30,
"sensor_id": 1,
"temp": 25.5,
},
{
"timestamp": 5,
"sensor_id": 2,
"temp": 24.5,
},
{
"timestamp": 20,
"sensor_id": 2,
"temp": 29.5,
}
]
};
let {sensors ,...sensorTimeMap} = zdata.data.reduce((acc,val) => {
if(!acc[val.timestamp])
acc[val.timestamp] = {};
acc[val.timestamp][val.sensor_id] = val.temp; // pivots the data against timestamp so as to give us more performant lookups later
if(!acc.sensors.includes(val.sensor_id))
acc.sensors.push(val.sensor_id)
return acc;
},{ sensors:[] }); // Since the number of sensors is dynamic and should be extracted from the data object, we collect available sensors in an array and also create a timeStampMap for future reference
let timestamp = Object.keys(sensorTimeMap); // All timestamps of the pivot generated
let sensorValArray = sensors.map(sensor => (Object.values(sensorTimeMap).map(obj => obj[sensor] || ''))); // gives us an array of arrays since we cannot know for sure how many sensors are there beforehand and cannot store in different variables. But this is the only way to handle dynamic length since we cannot know how many variables to declare beforehand!
console.log(timestamp,sensorValArray);

Tournament pairing algorhitm

I need to find ideal pairing amongst tournament players based on following rules:
players with equal points score or similar should be matched
two players can have only one mutual match in tournament
all players must have a match in a round
Its basically a simplified Swiss tournament system.
I have followings standings:
[{
"playerIndex": 0,
"points": 0,
"opponents": [3, 2, 4]
}, {
"playerIndex": 1,
"points": 3,
"opponents": [4, 5, 2]
}, {
"playerIndex": 2,
"points": 3,
"opponents": [5, 0, 1]
}, {
"playerIndex": 3,
"points": 4,
"opponents": [0, 4, 5]
}, {
"playerIndex": 4,
"points": 6,
"opponents": [1, 3, 0]
}, {
"playerIndex": 5,
"points": 2,
"opponents": [2, 1, 3]
}]
Read as: first array item is player number (index) 0 that already played with players number (index) 3, 2 and 4 and gained 0 points, each item for one of six players in a tournament.
And I need to pick three matches for the fourth match. Following a rule that no two players can play a mutual match more than once I choose from following matches:
[ [ 0, 1 ], [ 0, 5 ], [ 1, 3 ], [ 2, 3 ], [ 2, 4 ], [ 4, 5 ] ]
Each of these six possible matches has a points difference between the two players as follows:
[3, 2, 1, 1, 2, 4]
So ideal pairing for the fourth round that gives each player a match in a round with lowest points difference between paired players is:
[ [0, 5], [1, 3], [2, 4] ]
Is there any way of finding these ideal pairings in real time? It is impossible to try all the possible combinations, because there can be more than 100 people in a tournament and the calculations would take forever.
I have been advised to use https://en.wikipedia.org/wiki/Edmonds%27_algorithm or https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm (both available in JS: https://www.npmjs.com/package/edmonds-blossom and https://github.com/sfentress/edmunds-karp). But I am not sure how to read the results.
Can somebody help please?
Edit: Hungarian algorithm fails if there is too many possible solutions. In my case after first round when there is a lot of players with same amount of points.
Edmond Blossoms algorithm performs much better (found this JS implementation available via NPM https://github.com/mattkrick/EdmondsBlossom).
Just had trouble understanding how to use it. The main difference is that you need to feed it with pairs and the points difference between pairs is higher for the pairs that should be preferred. So I use zero difference for pairs that already played before.
My final (hopefully) solution:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
var possiblePairs = []
availablePlayers.forEach(player => {
availablePlayers.forEach(opponent => {
if (
player.playerIndex !== opponent.playerIndex // &&
// player.opponents.indexOf(opponent.playerIndex) === -1
) {
var match = [player.playerIndex, opponent.playerIndex]
match.sort(function(a, b) {
return a - b;
})
if (player.opponents.indexOf(opponent.playerIndex) === -1) {
match.push(maxDiff - Math.abs(player.points - opponent.points))
}
else {
match.push(0)
}
if (this.searchForArray(possiblePairs, match) === -1) {
possiblePairs.push(match)
}
}
})
})
var rawPairing = edmondsBlossom(possiblePairs)
rawPairing.forEach((match, index) => {
if (match !== -1 && match < index) {
round.matches.push({
home: match,
home_score: '',
away: index,
away_score: '',
referee: -1
})
}
})
First I count max possible points difference amongst players (expecting someone could gain zero points and someone else all of them). Then create all possible combinations between players and mark them with MAX POSSIBLE POINTS - PLAYERS POINTS DIFFERENCE or ZERO for players that matched before.
Then feed the array to EdmondsBlossom function that returns array of integers...
[6,8,14,5,15,3,0,10,1,12,7,13,9,11,2,4]
...read as follows: player index 0 should be paired with player 6, player 1 vs 8, player 2 vs 14, player 3 vs 5... player 5 vs 3 (duplicates). Sometimes there is -1 value in the output that is simply skipped.
Here is my solution (deprecated):
Thanks to #VedPrakash's comment I found the Hungarian algorithm that solves my problem. Luckily there is also a JS implementation available on NPM https://github.com/addaleax/munkres-js.
The Munkers function needs a matrix as input. In my case it is players points difference on intersections of my matrix (see below). The pairs that already played each other have higher value that cant be achieved (9 in my case).
Input matrix:
[ [ 9, 4, 9, 9, 9, 3 ],
[ 4, 9, 9, 2, 9, 9 ],
[ 9, 9, 9, 2, 4, 9 ],
[ 9, 2, 2, 9, 9, 9 ],
[ 9, 9, 4, 9, 9, 5 ],
[ 3, 9, 9, 9, 5, 9 ] ]
Output:
[ [ 0, 5 ], [ 1, 3 ], [ 2, 4 ], [ 3, 1 ], [ 4, 2 ], [ 5, 0 ] ]
The last thing to take care of is filter the Munkers output (that contains duplicates - both pairs 0vs1 and 1vs0) so i filter them simply by comparing first and second index.
My implementation:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
// prepare matrix
var matrix = [];
for (var i = 0; i < availablePlayers.length; i++) {
matrix[i] = new Array(availablePlayers.length);
matrix[i].fill(0)
}
// fill matrix with players points diff
for (var y = 0; y < availablePlayers.length; y++) {
var playerY = availablePlayers[y]
for (var x = 0; x < availablePlayers.length; x++) {
var playerX = availablePlayers[x]
if (x === y) {
matrix[x][y] = maxDiff
}
else if (playerY.opponents.indexOf(x) !== -1) {
matrix[x][y] = maxDiff
matrix[y][x] = maxDiff
}
else {
var value = Math.abs(playerX.points - playerY.points)
matrix[x][y] = value
matrix[y][x] = value
}
}
}
// console.table(matrix)
// console.table(computeMunkres(matrix))
// return
// make pairing
var rawPairing = computeMunkres(matrix)
rawPairing.forEach(pairing => {
if (pairing[0] < pairing[1]) {
round.matches.push({
home: pairing[0],
home_score: '',
away: pairing[1],
away_score: '',
referee: -1
})
}
})

Selectively flattening a nested JSON structure

So this is a problem that I have no idea where to even start so even just a pointer in the right direction would be great.
So I have data that looks like so:
data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
{
...
},
{
...
},
...
]
}
}
Now from the example, within 'agg' there are N 'agg1' results, within each 'agg1' result there is a 'keyWeWant'. Each 'agg1' result also has a list of 'some_nested_agg' results which each contain a 'keyWeWant2'. Each 'keyWeWant2' value is associated a single 'keyWeWant' value somewhere up in the hierarchy. Similarly each 'keyWeWant2' also contains a set of results for 'some_nested_agg2' (not a list but rather a map this time). Each of the set of results contains a 'keyWeWant3'.
Now I want to flatten this structure while still preserving the association between 'keyWeWant', 'keyWeWant2', and 'keyWeWant3' (I'm essentially de-normalizing) to get something like so:
What I want the function to look like:
[
{
"keyWeWant" : "*-20",
"keyWeWant2" : 20,
"keyWeWant3" : 2.857142857142857
},
{
"keyWeWant" : "*-20",
"keyWeWant2" : 25,
"keyWeWant3" : 6.375
},
{
...
},
{
...
}
]
This is an example where there is only depth 3 but there could be arbitrary depth with some nested values being lists and some being arrays/list.
What I would like to do is write a function to take in the keys I want and where to find them, and then go get the keys and denormalize.
Something that looks like:
function_name(data_map, {
"keyWeWant" : ['agg', 'agg1'],
"keyWeWant2" : ['agg', 'agg1', 'some_nested_agg'],
"keyWeWant" : ['agg', 'agg1', 'some_nested_agg', 'some_nested_agg2']
})
Any ideas? I'm familiar with Java, Clojure, Java-script, and Python and am just looking for a way to solve this that's relatively simple.
Here is a JavaScript (ES6) function you could use:
function flatten(data, keys) {
var key = keys[0];
if (key in data)
keys = keys.slice(1);
var res = keys.length && Object.keys(data)
.map( key => data[key] )
.filter( val => Object(val) === val )
.reduce( (res, val) => res.concat(flatten(val, keys)), []);
return !(key in data) ? res
: (res || [{}]).map ( obj => Object.assign(obj, { [key]: data[key] }) );
}
// Sample data
var data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
]
}
};
// Flatten it by array of keys
var res = flatten(data, ['keyWeWant', 'keyWeWant2', 'keyWeWant3']);
// Output result
console.log(res);
Alternative using paths
As noted in comments, the above code does not use path information; it just looks in all arrays. This could be an issue if the keys being looked for also occur in paths that should be ignored.
The following alternative will use path information, which should be passed as an array of sub-arrays, where each sub-array first lists the path keys, and as last element the value key to be retained:
function flatten(data, [path, ...paths]) {
return path && (
Array.isArray(data)
? data.reduce( (res, item) => res.concat(flatten(item, arguments[1])), [] )
: path[0] in data && (
path.length > 1
? flatten(data[path[0]], [path.slice(1), ...paths])
: (flatten(data, paths) || [{}]).map (
item => Object.assign(item, { [path[0]]: data[path[0]] })
)
)
);
}
// Sample data
var data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
]
}
};
// Flatten it by array of keys
var res = flatten(data, [
['agg', 'agg1', 'keyWeWant'],
['some_nested_agg', 'keyWeWant2'],
['some_nested_agg2', 'keyWeWant3']]);
// Output result
console.log(res);
There is probably a better way to solve this particular problem (using some ElasticSearch library or something), but here's a solution in Clojure using your requested input and output data formats.
I placed this test data in a file called data.json:
{
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}]
}]}
}
Then Cheshire JSON library parses the data to a Clojure data structure:
(use '[cheshire.core :as cheshire])
(def my-data (-> "data.json" slurp cheshire/parse-string))
Next the paths to get are defined as follows:
(def my-data-map
{"keyWeWant" ["agg", "agg1"],
"keyWeWant2" ["agg", "agg1", "some_nested_agg"],
"keyWeWant3" ["agg", "agg1", "some_nested_agg", "some_nested_agg2"]})
It is your data_map above without ":", single quotes changed to double quotes and the last "keyWeWant" changed to "keyWeWant3".
find-nested below has the semantics of Clojure's get-in, only then it works on maps with vectors, and returns all values instead of one.
When find-nested is given a search vector it finds all values in a nested map where some values can consist of a vector with a list of maps. Every map in the vector is checked.
(defn find-nested
"Finds all values in a coll consisting of maps and vectors.
All values are returned in a tree structure:
i.e, in your problem it returns (20 25) if you call it with
(find-nested ['agg', 'agg1', 'some_nested_agg', 'keyWeWant2']
my-data).
Returns nil if not found."
[ks c]
(let [k (first ks)]
(cond (nil? k) c
(map? c) (find-nested (rest ks) (get c k))
(vector? c) (if-let [e (-> c first (get k))]
(if (string? e) e ; do not map over chars in str
(map (partial find-nested (rest ks)) e))
(find-nested ks (into [] (rest c)))) ; create vec again
:else nil)))
find-nested finds the values for a search path:
(find-nested ["agg", "agg1", "some_nested_agg", "keyWeWant2"] my-data)
; => (20 25)
If all the paths towards the "keyWeWant's are mapped over my-data these are the slices of a tree:
(*-20.0
(20 25)
(2.857142857142857 6.375))
The structure you ask for (all end results with paths getting there) can be obtained from this tree in function-name like this:
(defn function-name
"Transforms data d by finding (nested keys) via data-map m in d and
flattening the structure."
[d m]
(let [tree (map #(find-nested (conj (second %) (first %)) d) m)
leaves (last tree)
leaf-indices (range (count leaves))
results (for [index leaf-indices]
(map (fn [slice]
(if (string? slice)
slice
(loop [node (nth slice index)]
(if node
node
(recur (nth slice (dec index)))))))
tree))
results-with-paths (mapv #(zipmap (keys m) %) results)
json (cheshire/encode results-with-paths)]
json))
results uses a loop to step back if a leaf-index is larger than that particular slice. I think it will work out for deeper nested structures as well -if a next slice is always double the size of a previous slice or the same size it should work out -, but I have not tested it.
Calling (function-name my-data my-data-map) leads to a JSON string in your requested format:
[{
"keyWeWant": "-20.0",
"keyWeWant2": 20,
"keyWeWant3": 2.857142857142857 }
{
"keyWeWant": "-20.0",
"keyWeWant2" 25,
"keyWeWant3" 6.375 }]
/edit
I see you were looking for a relatively simple solution, that this is not. :-) maybe there is one without having it available in a library. I would be glad to find out how it can be simplified.

How to count and display the occurrence of a number in a json array of numbers

Please forgive me if this is a dumb or basic question but I have not been able to find a good solution. I have a json array of numbers:
[30, 37,34,56,76,87,54,34,2,4,2,5,5,3,4,3,4, 90]
I would like to count how many times each number occurs and use that data to produce a graph using d3js. How can I go about doing this? If there is a D3 method that does this, that would be great. But a javascript/jquery solution would do as well.
In plain Javascript:
var items = [30, 37, 34, 56, 76, 87, 54, 34, 2, 4, 2, 5, 5, 3, 4, 3, 4, 90],
histogram = items.reduce(function (r, a) {
r[a] = (r[a] || 0) + 1;
return r;
}, {});
document.write('<pre>' + JSON.stringify(histogram, 0, 4) + '</pre>');
For the graphing, check out c3. This can be easily done with something like this:
var chart = c3.generate({
data: {
x: 'x',
columns: [
numbers.unshift('x'),
occurrences.unshift('occurrences'),
],
type: 'bar'
} });
where numbers is an array of all distinct numbers and occurrences is an array of the numbers of time each occurs.
Demo

Categories