I'm trying to populate the dataset for a barchart. I would like to add 'dataset' to existing barData1 object.
But I'm getting following error. What am I doing wrong here?
error: jquery-3.1.1.min.js:2 Uncaught TypeError: Cannot read property
'splice' of undefined
<script type="text/javascript">
var jsprojStatList = #Html.Raw(ViewBag.projStatList);
$(document).ready(function () {
var barData1 = {
labels: ["No. Of Line Items", "Line Items Ordered", "( % )", "Line Items to be Ordered", "( % )", "PO Generated", "PO Approved", "PO Waiting for Approval"]
};
//var obj = JSON.parse(barData1);
//var parse_obj = JSON.parse(barData1);
var i = 0;
for (var key in jsprojStatList) {
if (jsprojStatList.hasOwnProperty(key)) {
var val = jsprojStatList[key];
barData1['datasets'].splice(i, 0, {
"label": val.BudgetTypeTitle, "backgroundColor": "rgba(220, 220, 220, 0.5)", "rgba(220, 220, 220, 0.5)": "#fff"
, "data": [val.NoOfBudgetItems, val.NoOfBudgetItemsOrdered, val.NoOfBudgetItemsOrderedPercentage, val.NoOfBudgetItemsToBeOrdered
, val.NoOfBudgetItemsToBeOrderedPercentage, val.POGenerated, val.POApproved, (val.POGenerated - val.POApproved)]
});
i++;
};
};
//}
var barOptions1 = {
responsive: true
};
var ctx21 = document.getElementById("barChart1").getContext("2d");
new Chart(ctx21, { type: 'bar', data: barData1, options: barOptions1
});
</script>
You'll have to define barData1['datasets'] itself as an array before you can add values to it:
var barData1 = {
datasets: [], // populated below
labels: ["No. Of Line Items", "Line Items Ordered", "( % )", "Line Items to be Ordered", "( % )", "PO Generated", "PO Approved", "PO Waiting for Approval"]
};
.splice() won't/can't automatically create the array for you with the first use.
Side notes:
Since it doesn't appear you're using i for anything else, .push(value) can be used in place of .splice(i, 0, value). That'll let you discard var i = 0 and i++.
If jsprojStatList is an Array (guessing from List in its name), a for..in loop isn't usually appropriate with them.
Related
I want to visualize a dataset using dc.graph.js, and I want to have the nodes to show different colors based on different values of a specific attribute in the data file. Here is a sample json dataset that I would like to visualize:
"nodes": [
{
"id": 0,
"name": "beans",
"fiber content":"high"
},
{
"id": 1,
"name": "meat",
"fiber content":"low"
},
{
"id": 2,
"name": "apple",
"fiber content":"high"
},
{
"id": 3,
"name": "walnut",
"fiber content":"medium"
},
{
"id": 4,
"name": "egg",
"fiber content":"low"
};
I want all the food items with high fiber content to have the same color on the graph, and those with medium fiber content to show another color, and the ones with low fiber content to have a third color. In other words, I hope to basically have the nodes grouped into three groups: high, medium and low fiber content, then assign colors respectively to each group. I read through the dc.graph.js API and found that nodeKey is a unique identifier of the node's attributes, so I looked at the demo js and found this function which does the data file import and define the attribute terms:
function on_load(filename, error, data) {
var graph_data = dc_graph.munge_graph(data),
nodes = graph_data.nodes,
edges = graph_data.edges,
sourceattr = graph_data.sourceattr,
targetattr = graph_data.targetattr,
nodekeyattr = graph_data.nodekeyattr;
var edge_key = function(d) {
return d[sourceattr] + '-' + d[targetattr] + (d.par ? ':' + d.par : '');
};
var edge_flat = dc_graph.flat_group.make(edges, edge_key),
node_flat = dc_graph.flat_group.make(nodes, function(d) { return d[nodekeyattr]; }),
cluster_flat = dc_graph.flat_group.make(data.clusters || [], function(d) { return d.key; });
I'm not sure how it recognizes the attributes from the imported dataset, so I wonder if I need to point out and link to the "fiber content" attribute somewhere in my code to tell it what my color groups are based on. And for the color settings, the brushing-filtering demo actually has colors on the graph working but the graphs are auto-generated randomly without a dataset, so there isn't any grouping around attributes involved. I tried to add this following code snippet about colors (which I mostly followed from the brushing-filtering.js) to the same on_load function above, but it didn't work:
var colorDimension = node_flat.crossfilter.dimension(function(n) {
return n.color;
}),
colorGroup = colorDimension.group(),
dashDimension = edge_flat.crossfilter.dimension(function(e) {
return e.dash;
}),
dashGroup = dashDimension.group();
var colors = ['#1b9e77', '#d95f02', '#7570b3'];
var dasheses = [
{name: 'solid', ray: null},
{name: 'dash', ray: [5,5]},
{name: 'dot', ray: [1,5]},
{name: 'dot-dash', ray: [15,10,5,10]}
];
Diagram
.autoZoom('once-noanim')
.altKeyZoom(true)
.nodeFixed(function(n) { return n.value.fixed; })
.nodeLabelFill(function(n) {
var rgb = d3.rgb(Diagram.nodeFillScale()(Diagram.nodeFill()(n))),
// https://www.w3.org/TR/AERT#color-contrast
brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
return brightness > 127 ? 'black' : 'ghostwhite';
})
.nodeFill(function(kv) {
return kv.value.color;
})
.nodeFillScale(d3.scale.ordinal().domain([0,1,2]).range(colors))
Any tips on how I might accomplish this?
I am trying to access JSON values. This is the JSON object:
{
"attrs": {
"width": 1728,
"height": 787,
"dragabble": true
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"stroke": "green",
"strokeWidth": "5",
"points": [
348,564.125
]
},
"className": "Line"
}
]
}
]
}
And I am trying to use these values, like points, here:
socket.on("canvas-data", function(data){
var interval = setInterval(function(){
if(isDrawing) return;
setIsDrawing(true);
clearInterval(interval);
var obj = JSON.parse(data);
setStageData(obj);
var layer = new Konva.Layer();
var lines = new Konva.Line(
{
stroke: stageData.stroke,
strokeWidth: stageData.strokeWidth,
points: stageData.points
})
layer.add(lines);
stageEl.current.add(layer);
}, 200)
})
data is the JSON string, I tried to parse data into obj, set my stageData to obj and then set the corresponding JSON attributes to the values like stroke, strokeWidth and points. This doesn't work however, they're undefined. How do I access them?
(I also tried skipping the step where I set my stageData to obj, and just use obj.stroke instead of stageData.stroke etc.)
You can just skip using setStageData() and use the parsed object directly if you wish, or just name the parsed object stageData by default.
In any case, when you have nested objects and values in an Object, you access them by using the correct index, in your case, it would look this way:
socket.on("canvas-data", function(data) {
var interval = setInterval(function() {
if (isDrawing) return;
setIsDrawing(true);
clearInterval(interval);
var stageData = JSON.parse(data);
var layer = new Konva.Layer();
var lines = new Konva.Line(
{
stroke: stageData.children[0].children[0].attrs.stroke,
strokeWidth: stageData.children[0].children[0].attrs.strokeWidth,
points: stageData.children[0].children[0].attrs.points
});
layer.add(lines);
stageEl.current.add(layer);
}, 200);
})
Doesn't look very nice, but it works. You can always use this app called JSON Path list, which shows you all the possible paths and their values in a JSON object.
I have two arrays
$scope.tags = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }]
Other one is
$scope.skillsInterested = [1,2];
What is want to do ?
How can i map the above arrays and print only names of the id's in$scope.skillsInterested
I want to print names in first array only the id's present in second.
I have tried this after getting several answers
var tag_map = {};
for (var x = 0; x < $scope.tags.length; x++) {
tag_map[$scope.tags[x]['id']] = $scope.tags[x]['name'];
}
$scope.skillsInts = $scope.skillsInterested.map(function(x) {
return tag_map[x]
On running console.log
console.log("Result", tag_map);
It sometimes give result sometimes it gives 'map' of undefined.
TypeError: Cannot read property 'map' of undefined
at controllers.js:141
at angular.js:16383
at m.$eval (angular.js:17682)
at m.$digest (angular.js:17495)
at m.$apply (angular.js:17790)
at l (angular.js:11831)
at J (angular.js:12033)
at XMLHttpRequest.t.onload (angular.js:11966)
Thanks in advance.
Make a map of your data that looks like this:
var tagMap = { 1: "python", 2: "NodeJs" /* etc. */ };
You can do this by looping over your tags and adding a new property to an object. reduce lets you do this without creating any extra variables.
Then, you can select names from your newly created object using the [] notation: tagMap[1] returns "pyhton".
var tags = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }]
var selectedExpTags = [1,2];
// Make a map for `id: name`
var tagMap = tags.reduce(function(map, tag) {
map[tag.id] = tag.name;
return map;
}, {});
// Quickly select names from the map:
var selectedNames = selectedExpTags.map(function(id) {
return tagMap[id];
});
console.log(selectedNames);
Using this approach, you minimise the iterations over your data. The creation of the map loops over the tags once. Creating the array with names, loops over the selected tags once. So, roughly, the "loop count" is tags.length + selectedTags.length. If you would use an indexOf based approach, your loop count would be tags.length * selectedTags.length.
Use the filter function for first, and then check the id's existnent then map the names from the array.
var first = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }];
var selectedExpTags = [1,2];
var names = first.filter(item => selectedExpTags.some(id => item.id === id)).map(item => item.name);
console.log(names);
You can loop over $scope.selectedExpTags and get a list of all names. You can use array.find if you want first value only.
Sample
var first = [
{ "id": 1, "name": "python" },
{ "id": 2, "name": "NodeJs" },
{ "id": 3, "name": "git" }];
var selectedExpTags = [1,2];
var names = selectedExpTags.map(x=> first.find( y=> y.id === x ).name )
console.log(names);
$scope.newArray = []; // If you need a new array to work with
angular.forEach($scope.tags, function(tag){
$scope.selectedExpTags.forEach(function(selectedTag){
if(selectedTag == tag.id){
//tag.hide = false; // - If you want to update the current array
$scope.newArray.push(tag);
}
// else{ // - If you want to update the current array
// tag.hide = true;
// }
})
})
Lodash is more efficient than angular for manipulating data.
I'm trying the create a pie chart using d3pie.js user input values. Below is my code that is functional but takes random numbers on button click.
But I wan't the new segment value to be taken from user input field. I tried assigning the jquery function to a variable and then assigning that variable to value like below but that didn't work. I also tried to directly define the Jquery function to define value.
Attempt 1 (Didn't work):
var a = $("#first").val();
var num = 4;
$("#addData").on("click", function() {
adata.push({
label: num.toString(),
value: a
});
pie.updateProp("data.content", adata);
num++;
Attempt 2 (Didn't work):
adata.push({
label: num.toString(),
value: $("#first").val()
});
Below is my working code, would really appreciate some inputs from the folks on this.
var adata = [
{
"label": "JavaScript",
"value": 5,
},
{
"label": "Ruby",
"value": 3,
},
{
"label": "Java",
"value": 2,
}
];
--------------------
"data": {
"sortOrder": "value-desc",
"content": adata
--------------------
var num = 4;
$("#addData").on("click", function() {
adata.push({
label: num.toString(),
value: Math.floor(Math.random() * 10) + 1
});
pie.updateProp("data.content", adata);
num++;
--------------------
<input type="text" class="form-control" id="first">
<button type="button" class="btn btn-default" id="addData">Add Value</button>
Problem is because you are passing a string in value, it expects a number.
in your code
adata.push({
label: num.toString(),
value: a //incorrect it has to be a number.
});
need to do
adata.push({
label: num.toString(),
value: +$("#first").val() //make it a number so + is appended.
});
working code here
I have a sample json data,which I need to add in to different collections in mongodb.But I dont want whole json data.For example,
jsondata=
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
}}
In this json I want window key in one collection,simillarly image key in another mongo collection.
So I was thinking if I can save that key value pair in one variable,then I can add that variable in to collection.For this I was trying for each
var jsondat=JSON.parse(jsondata);
for(var exKey in jsondat) {
console.log("entering");
var b=stringdata[exKey].image;
console.log(b);
}
But I was unable to get that image key data.Is this the right approach for this?can someone help me out in this.
My expected result would be:
In one variable,The value of window key should be saved in json format.
Simillarly image and text keyvalues in another variables.
Thanks.
Why aren't you fetching window and image simply from the object as key like:
var window= jsondata.widget.window;
var image = jsondata.widget.image;
and save them in mongo db
db.window.insert(window)
db.image.insert(image)
Tell me If I understand it right.
I don't see much problem.
var jsondat=JSON.parse(jsondata);
for(var exKey in jsondat.widget) {
console.log("entering");
console.log(exKey);
if(exKey === 'image'){
db.image.insert(jsondat.widget[exKey]);
}else if(exKey === 'window'){
db.window.insert(jsondat.widget[exKey]);
}
// or db.getCollection(exKey).insert(jsondat.widget[exKey]);
}
But I would also add that normalization is not desirable in MongoDB, you should use embedding more because you won't be able to join collections later on if you want to collate data. But that's a general idea, maybe in your requirement you want different collection.
You can do it in several ways.
Method#1
var arr = [];
for(var i in jsondata.widget){
if(typeof(jsondata.widget[i])==='object'){
arr.push(jsondata.widget[i]);
}
};
console.log(arr);
Method#2
You can use unserscore utility library to get in easy
var _=require('underscore');
var arr = [];
_.each(jsondata.widget,function(o){
if(typeof(o)==='object'){
arr.push(o);
}
});
console.log(arr);
Now you can access all the object by index
Output
[ { title: 'Sample Konfabulator Widget',
name: 'main_window',
width: 500,
height: 500 },
{ src: 'Images/Sun.png', name: 'sun1', hOffset: 250 },
{ data: 'Click Here', size: 36, style: 'bold' } ]
Method#3
Try to get separate value of each inner keys
var window= jsondata.widget.window;
var image= jsondata.widget.image;
var text= jsondata.widget.text;
Edit
var obj={
"json": {
"window": {
"title": "sample",
"name": "sam"
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250
}
}
}
console.log(obj.json.window)
result-> {title: "sample", name: "sam"}