NVD3 multi bar chart with json? - json

I'm trying to load json into NVD3's multi bar chart, but can't get it to render the values that I'm including. I'm not sure what "stream_layers" is doing, either.
It is similar to this (http://nvd3.org/ghpages/multiBar.html), but should render a series of "mini" graphs next to each other, rather than one large graph of all the combined values. NVD3 calls this multiBarChart.html in their example files. I can get a blank graph to show up, but I can't get it to pull the values.
var test_data = [{
"key" : "MT_ATTEMPTED",
//"bar": true,
"values" : [4505891, 20130620, 6636631]
}, {
"key" : "MT_SUCCESS",
"values" : [4505891, 20130620, 6636631]
}, {
"key" : "MO_ATTEMPTED",
"values" : [4505891, 20130620, 6636631]
}].map(function(series) {
series.values = series.values.map(function(d) {
return {
x : stream_layers(3, 3, .1),
y : d[1]
}
});
return series;
});

Need to have key/value pairs within a top level key.
Also:
.map(function(series) {
series.values = series.values.map(function(d) { return {x: d.label, y: d.value } });
return series;

Related

Group bar chart data not working as expected

Have an array set of the type json object.
Var data has an array object like:
0: Object
letter : A
frequency : .08167
1: Object
letter : B
frequency : .01492
2: Object
letter : C
frequency : .02780
3: Object
letter : A
frequency : .06167
4: Object
letter : D
frequency : .02492
5: Object
letter : C
frequency : .03780
The field letter has more than one set of data(for ex: letter A is having two sets of frequency or more). I need to create a group chart for the same.
var frequency= d3.keys(data[0]).filter(function (key) {
return (key !== "letter");
});
data.forEach(function (d) {
d.val = frequency.map(function (name) { return { name: name, value: +d[name] }; });
});
This doesn't seem to work. Is there anything wrong in the structure of Json data?
From the question and comment, it seems like you have your data in a format like this:
data = [
{ "letter": "A", "frequency": .08167, "year": 2015},
{ "letter": "B", "frequency": .01492, "year": 2015},
{ "letter": "C", "frequency": .02780, "year": 2015}...
In which case, the best way to group by letter for your grouped bar chart would be to use d3.nest:
var nested_data = d3.nest()
.key(function (d) {
return d.letter;
})
.entries(data);
which will structure your data with multiple values under each letter key.
Here's a working fiddle with your data: http://jsfiddle.net/henbox/jc0nohhb/1/, that borrows a lot from this example: http://bl.ocks.org/mbostock/3887051
Note - This is a good resource to read more about nest in d3: http://bl.ocks.org/phoebebright/raw/3176159/

sorting json arrays in json array using angular js

I have json array in the following format,
$scope.data = [{
"values" : [["2 Day", 103.89], ["NextDay", 107.41], ["Ground", 428.75]],
"key" : "FedEx"
}, {
"values" : [["Ground", 117.8], ["NextDay", 10], ["2 Day", 15]],
"key" : "UPS"
}]
I need to sort it in to the following format :
$scope.data = [{
"values" : [["2 Day", 103.89], ["NextDay", 107.41], ["Ground", 428.75]],
"key" : "FedEx"
}, {
"values" : [["2 Day", 15], ["NextDay", 10], ["Ground", 117.8]],
"key" : "UPS"
}]
How can I do it using Angularjs?
A similar data set for which I want similar sorting to be applied, but here I have time (in long format) instead strings.
$scope.data1 = [{
"values" : [[1359072000000, 103.89], [1365116400000, 107.41], [1357516800000, 428.75]],
"key" : "FedEx"
}, {
"values" : [[1357516800000, 117.8], [1359072000000, 100], [1365116400000, 15]],
"key" : "UPS"
}];
To be formatted as
$scope.data1 = [{
"values" : [[1359072000000, 103.89], [1365116400000, 107.41], [1357516800000, 428.75]],
"key" : "FedEx"
}, {
"values" : [[1359072000000, 100],[1365116400000, 15], [1357516800000, 117.8], ],
"key" : "UPS"
}];
Natural sorting can be applied in js like this. Natural sorting is required since strings in your array contains numbers.
function strcmp(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
}
function natcmp(a, b) {
var x = [], y = [];
a[0].replace(/(\d+)|(\D+)/g, function($0, $1, $2) { x.push([$1 || 0, $2]) })
b[0].replace(/(\d+)|(\D+)/g, function($0, $1, $2) { y.push([$1 || 0, $2]) })
while(x.length && y.length) {
var xx = x.shift();
var yy = y.shift();
var nn = (yy[0]-xx[0]) || strcmp(yy[1],xx[1]);
if(nn) return nn;
}
if(x.length) return -1;
if(y.length) return +1;
return 0;
}
Apply sorting in your array using javascript sort function as shown below.
$scope.data = $scope.data.map(function(d){ d.values = d.values.sort(natcmp); return d; });
Natural sorting is not needed for the second dataset. To sort the array in descending order by time, try this.
$scope.data1 = $scope.data1.map(function(d) {
d.values = d.values.sort(function(a, b) {
return new Date(b[0]) - new Date(a[0])
});
return d;
});
for displaying the array with some ng-repeat, you could use a filter
https://docs.angularjs.org/api/ng/filter/filter
There is orderBy filter but you can create your own filters.
for the data model to be sorted and not only for presentation, you could use the javascript sort function for arrays and give it a sorting implementation which compares 2 elements.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

AngularJS change property value based on another array

I have a json data structured as:
$scope.items = [{"Color" : "Red", "Size": "Small" }, { "Color" : "Orange" "Size": "Small"}, {"Color" : "Green" "Size": "Extra-Large"}];
then I have a properties json data:
$scope.properties = [{"PropertyName" : "Color", "FilteredAs" : "AllColors"}, {"PropertyName" : "Size", "FilteredAs" : "AllSizes"}]
I am doing a server-side filtering that's why there's a FilteredAs property in my properties json data. What I want to happen is:
If (items.key = properties.PropertyName)
example: "Color" (which is the first property in the items array) == "PropertyName" : "Color"
then that corresponding object's FilteredAs property in the properties array is "FilteredAs" : "AllColors", AllColors will be changed to "Red".
Any ideas on how to achieve this? Thanks!
EDIT: This is what I have for now:
angular.forEach($scope.items, function (value, key) {
for (var i = 0; i<= $scope.properties.length; i++) {
if ($scope.properties[i].PropertyName == $scope.items[value]) {
$scope.properties[i].SearchText = $scope.items[key];
}
}
If I understand it correctly as $scope.properties is an array you would need to foreach through the objects and identify the property that is for Color. Below should do what your looking for.
$scope.properties.forEach(function (property) {
if (property.PropertyName === "Color") {
property.FilteredAs = "Red" // Or whatever value or variable you have got back from webservice
}
});
Hope I have understood correctly and that this helps.
EDIT:
Because $scope.items is an array angular.forEach doesn't work that same way as it does for an object. You would need to change the code to be something like below.
angular.forEach($scope.items, function (item) {
for (var i = 0; i<= $scope.properties.length; i++) {
if ($scope.properties[i].PropertyName == "Color") {
$scope.properties[i].SearchText = item.Color;
}
}
With this though the value of $scope.properties[i].SearchText will always be the last Color in the $scope.items array. You might need to add some checked to ensure the right color is selected from the array with what your WebService says.

kendoAutoComplete expects that JSON reponse contains the same propertyname as the search filter

Datasource is defined as:
var KendoDataSource_EmployeeAutoCompleteByFirstName = {
serverFiltering: true,
serverPaging: true,
serverSorting: true,
pageSize: 10,
transport: {
read: {
url: '#Url.Action("GetEmployeesByFirstName", "Employee")',
dataType: "json"
}
}
};
AutoComplete is defined as:
function KendoGridFilterAutoComplete(element, kendoDataSource, textField) {
element.kendoAutoComplete({
minLength: 3,
filter: "startswith",
dataSource: kendoDataSource,
dataTextField: textField
});
}
When using a kendoAutoComplete widget, the filter which is send by the datasource is like:
filter[logic]=and&
filter[filters][0][value]=smith&
filter[filters][0][operator]=startswith&
filter[filters][0][field]=LastName&
filter[filters][0][ignoreCase]=true
The JSON response from the server looks like:
[
{"First":"Bill","LastName":"Smith"},
{"First":"Jack","LastName":"Smith"},
{"First":"ABC","LastName":"Smithy"}
]
This works fine, however as you can see I return multiple entries, so the kendoAutoComplete shows two the same entries (Smith) because the first-name differs.
So what I actually want is do distinct on the server, and return only the possible LastName, as an array of strings like this:
[
"Smith",
"Smithy"
]
However the kendoAutoComplete cannot handle this. It shows "undefined" or an error.
How to solve this ?
I've create the following code:
#region AutoComplete
public virtual IQueryable GetAutoComplete(KendoGridRequest request)
{
// Get filter from KendoGridRequest (in case of kendoAutoComplete there is only 1 filter)
var filter = request.FilterObjectWrapper.FilterObjects.First();
// Change the field-name in the filter from ViewModel to Entity
string fieldOriginal = filter.Field1;
filter.Field1 = MapFieldfromViewModeltoEntity(filter.Field1);
// Query the database with the filter
var query = Service.AsQueryable().Where(filter.GetExpression1<TEntity>());
// Apply paging if needed
if (request.PageSize != null)
{
query = query.Take(request.PageSize.Value);
}
// Do a linq dynamic query GroupBy to get only unique results
var groupingQuery = query.GroupBy(string.Format("it.{0}", filter.Field1), string.Format("new (it.{0} as Key)", filter.Field1));
// Make sure to return new objects which are defined as { "FieldName" : "Value" }, { "FieldName" : "Value" } else the kendoAutoComplete will not display search results.
return groupingQuery.Select(string.Format("new (Key as {0})", fieldOriginal));
}
public virtual JsonResult GetAutoCompleteAsJson(KendoGridRequest request)
{
var results = GetAutoComplete(request);
return Json(results, JsonRequestBehavior.AllowGet);
}
#endregion
Which returns a unique list of anonymous objects which look like { "LastName" : "a" }.

Cannot bind JSON to d3

I've search far and wide, but cannot bind JSON data to a simple scatterplot for the life of me. I've looked at posts and examples, but I can only manage to bind arrays and not JSON. Below, I've tried to simply display JSON data as text and still can't make it work. Please let me know if you have any idea why!
d3_attempt.js
var data;
d3.json("json_data.json",function(error, dataset) {
if (error) return console.warn(error);
data = dataset;
var myscatter = d3.select("#somediv").append("svg")
.attr("width", 700)
.attr("height", 400);
myscatter.selectAll("text")
.data(data.data)
.enter()
.append("text")
.text(function(d){return d)})
});
json_data.json
{
"data":
{
"john": {"name": "john", "age": "13"},
"matt": {"name": "matt", "age":"14"}
}
}
Yup, you can only bind arrays, so you probably want to convert your data to an array:
myscatter.selectAll("text")
.data(d3.values(data.data));
This will give each of your text nodes the { name, age } object as data. If you need the keys too (looks like it's not required in this case), you could use d3.entries, which gives you an array of objects like { key: "john", value: { name: "John", age: "13" }}.