How to make a Pie Chart Aggregate the Data Source? - javascript

Using Kendo UI Complete for ASP.NET MVC, version: 2013.3 1119 (Nov 20, 2013)...
If I have this bit of code:
$("#status-chart").kendoChart({
dataSource: {
data: [
{Status: 10},
{Status: 20},
{Status: 200},
{Status: 200}
]
},
series: [{
field: 'Status',
categoryField: "Status",
aggregate: 'count'
}]
});
I get this chart:
As you can see - Status 10 and 20 have got a value of 1 and Status 200 a value of 2.
Great, but what I actually want is exactly the same thing in a pie chart (so, a chart with 3 pie slices, 2 of which are exactly the same size and one that is 2 times as big as the rest).
I therefore thought to myself, all I need to do is just set type: "pie" like so:
$("#status-chart").kendoChart({
dataSource: {
data: [
{Status: 10},
{Status: 20},
{Status: 200},
{Status: 200}
]
},
series: [{
field: 'Status',
categoryField: "Status",
aggregate: 'count',
type: "pie"
}]
});
But that produced this chart:
You can see that Status 200 is repeated and the value is determining the size of the slices.
So, here is my question:
How can I create a pie chart that looks like the picture below but which is bound to the data source in the first code snippet above?
Incidentally, the reason I do not want to change the data source is that I wish to share it with a grid.

What you are trying to do here is to group a shared DataSource and have it only affect one widget. Furthermore, Kendo UI will return a grouped object when you group it. The Pie chart is not interested in these objects, but rather the count of the items that each of these group objects contains. We just need to get the data in the right format.
So you have your original DataSource (which I have extracted since it's shared with another widget). When that DataSource changes, you want to populate a second one - one that you can group without affecting the grid.
var ds = new kendo.data.DataSource({
data: [
{Status: 10},
{Status: 20},
{Status: 200},
{Status: 200}
],
change: function() {
chartData.data(this.data());
}
});
The second DataSource (chartData) is grouped, and when it changes, it populates an array, constructing objects that the pie chart can actually understand.
var groupedData = [];
// populate the grouped data array by grouping this datasource
// and then populating an plain array
var chartData = new kendo.data.DataSource({
group: { field: 'Status' },
change: function() {
groupedData = [];
$.each(this.view(), function() {
groupedData.push({ field: this.value, value: this.items.length });
});
}
});
And then just bind your pie chart to that array
$("#status-chart").kendoChart({
dataSource: groupedData,
series: [{
type: 'pie',
field: 'value',
categoryField: 'field'
}]
});
Working example: http://jsbin.com/EKuxORA/1/edit

Related

Extjs 6 - How to use DataIndex in a Grid for Nested Data

I have created a fiddle here. My question is how to assign the DataIndex for the Aircraft Name and the Operator Name column.
https://fiddle.sencha.com/#view/editor&fiddle/2qs9
I do not want to do it this way
{name: 'operator', type: 'auto'},
{name: 'operatorId', type: 'string', mapping:'operator.id'},
{name: 'operatorName', type: 'string', mapping:'operator.name'}
then use operatorName as the DataIndex in the Grid because my original data is even more complicated with arrays and mode nested objects so that would be mean I need to flatten the entire Data structure.
You can use templatecolumn or renderer in grid to show what you need.
Using templatecolumn:
{
text: 'Aircraft Name',
tpl: '{aircraft.name}',
xtype: 'templatecolumn'
}
Using renderer:
{
text: 'Aircraft Name - Second Option',
renderer: function (v, record) {
return record.getAircraft() ? record.getAircraft().get('name') : null;
}
}
Example on fiddle:
https://fiddle.sencha.com/#view/editor&fiddle/2qsm

JSON error when calling chart.draw from Google GeoChart library

I'm trying to use Google GeoChart library to display a map, and if I do it on a local HTML file or somewhere like JSFiddle, it works perfectly.
However, when I embed it in a JSP on my project and deploy it (using JBoss), calling chart.draw results in a JSON error:
Invalid JSON string: {":",":",":{":[",","]},":",":{":true}}
My complete Javascript method is as follows:
var data2 = google.visualization.arrayToDataTable([
[{label: 'Country', type: 'string'},
{label: 'description', type: 'string'},
{label: 'consistency', type: 'number'},
{type: 'string', role: 'tooltip'}],
['Canada', "CANADA", 2, "OK"],
['France', "FRANCE", 0, "KO"],
['USA', "USA", 1, "Other"]
]);
var options = {
displayMode: 'region',
backgroundColor: '#81d4fa',
colorAxis: {
colors: ['red', 'orange', 'green']
},
legend: 'none',
tooltip: {
showColorCode: true
}
};
var chart = new google.visualization.GeoChart(document.getElementById('chart_div'));
chart.draw(data2, options);
So it's clearly picking up the "structure" of the JSON object (two simple objects, another object with an array inside, another simple object, another object with an array inside), but for some reason is not picking up the content, except for the 'true' value, so it looks like a problem with quotes...
In any case, I have tried simple and double quotes, removing the quotes from the identifiers, reducing the options object to a simple
var options = {
"legend": "none"
};
... but to no avail. Everything results in a Invalid JSON string error (in this last case, a Invalid JSON string: {":"} error, since there is only one object).
Last note: if I just use
var options = {};
it shows the map (but with the default options).
Any ideas as to why is this happening and/or how to solve it?
Thanks!

Slickgrid - Replacing all grid data from AJAX source

In the app I'm building, I have a data grid and some select boxes where the user can set filters and upon a selection it makes an AJAX call to get a new array of data from the server.
I have the grid initializing with default filters, but I can't figure out how to wipe the grid of all rows, and re-populate with a fresh array. I was trying dataView, but after reading some posts this seems to not be the answer. I find the official example-6 (ajax example) confusing.
I would like column sorting and column re-ordering to be retained when new data is loaded.
Here is the js I currently have which only initializes properly:
$(function(){
//update the grid when select values change
$('#qol_options :input').change(function(){
update_grid_data();
});
init_grid = function(){
// set grid options
var grid;
var columns = [
{id: "village", name: "Village", field: "village", sortable: true},
{id: "setting", name: "Setting", field: "setting", sortable: true},
{id: "hood", name: "N.hood", field: "hood", sortable: true},
{id: "timespan", name: "Time", field: "timespan", sortable: true},
{id: "count_0", name: "0", field: "count_0", sortable: true, width: 10},
{id: "count_1", name: "1", field: "count_1", sortable: true, width: 10},
{id: "count_2", name: "2", field: "count_2", sortable: true, width: 10},
{id: "count_3", name: "3", field: "count_3", sortable: true, width: 10},
{id: "count_4", name: "4", field: "count_4", sortable: true, width: 10},
{id: "count_6", name: "6", field: "count_6", sortable: true, width: 10},
{id: "count_7", name: "7", field: "count_7", sortable: true, width: 10},
{id: "count_8", name: "8", field: "count_8", sortable: true, width: 10},
{id: "count_total", name: "Total", field: "count_total", sortable: true},
{id: "pos_perc", name: "%", field: "pos_perc", sortable: true},
{id: "decile", name: "Decile", field: "decile", sortable: true},
];
var options = {
enableCellNavigation: true,
enableColumnReorder: true,
multiColumnSort: true
};
//get default grid data (all)
var grid_data = [{'village':0, 'setting':0, 'hood':0, 'timespan':0, 'count_0':0, 'count_1':0, 'count_2':0, 'count_3':0, 'count_4':0, 'count_6':0, 'count_7':0, 'count_8':0, 'count_total':0, 'pos_perc':0, 'decile':0}];
//create the grid instance
this_grid = new Slick.Grid("#data_table_container", grid_data, columns, options);
update_grid_data();
}
update_grid_data = function(){
var settingID = $('#settingID').val();
var villageID = $('#villageID').val();
var hoodID = $('#hoodID').val();
//init the grid
$.ajax({
type: "POST",
url: '<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm',
data: {'action': 'get_qol_report_data', 'villageID': villageID, 'settingID': settingID, 'hoodID': hoodID, 'itemID': 0, 'categoryID': 0},
dataType: 'json',
success: function(data) {
push_data_to_grid(data);
}
});
}
push_data_to_grid = function(data){
this_grid.setData(data);
this_grid.render();
}
//execute the grid init
init_grid();
});
I've faced the same problem. Please, try the below code.
function updateGridView(){
data_view.beginUpdate();
data_view.setItems(update_data);
data_view.endUpdate();
data_view.refresh();
grid.invalidate();
}
function grid_refresh(){
$.ajax("<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm",{
dataType : "json",
complete: function(xhr){
update_data = eval(xhr.responseText);
updateGridView();
}
})
}
Just call the grid_refresh() function.
I implemented something like this myself and here is how I have done it. I do use the dataview which will be wiped out every times and also the grid object which will be overwritten. I am not using your code, but instead I will show you the template which I use, I actually call the same function for loading & reloading but just make sure to empty() out the grid before you reload, see 1st line of code:
<div id="myGrid" style="width:100%;height:680px;"></div>
Then I made myself a button with an onclick event that looks something like this onclick=populateMyGrid() as a refresh button (it's actually a reload icon to make it nicer) and that event will call my function to reload the data through the $.getJSON() jQuery function, see the following code:
// Display some Market Indexes on a bar on top of the Grid
function populateMyGrid() {
// empty out the Grid before refreshing the data
$('#myGrid').empty();
// columns & options definition....
columns = [
{ id: "village", ............
];
options = {
enableCellNavigation: true,
editable: true,
............
};
ajaxURL = 'myPhpAjaxFileToPullData.php?action=getdata';
$.getJSON(ajaxURL, function (ServerResponse) {
dataView = new Slick.Data.DataView();
grid = new Slick.Grid('#myGrid', dataView, columns, options);
............
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
dataView.setItems(ServerResponse.data);
dataView.endUpdate();
// Refresh the data render, if user only clicked on the refresh button instead of refreshing the whole page from browser
grid.updateRowCount();
grid.render();
}); // end of getJSON
} // end of populateMyGrid
From this code, the important part of it is to empty out the grid at first and then the last 2 rows of code for refreshing your grid with new data and make sure to re-render at last. That is the way I have it working, works like a charm...oh and I also display a text showing last refresh date+time, so it's more obvious to the user of how old the data is!
Even though it's not your code sample, you should get the idea...hope it helps :)
Also if you want to repopulate the grid with some kind of filtering you send the filtering via the ajaxURL of the $.getJSON or you could also replace it with a $.post and send it via the data property as your started, if you do it that way then move all your code into the success function (or a function call). Here is a possible solution for replacing the $.getJSON call... but please note that I did not try it but it should work:
//init the grid
$.ajax({
type: "POST",
url: '<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm',
data: {'action': 'get_qol_report_data', 'villageID': villageID, 'settingID': settingID, 'hoodID': hoodID, 'itemID': 0, 'categoryID': 0},
dataType: 'json',
success : getData
});
function getData() {
dataView = new Slick.Data.DataView();
grid = new Slick.Grid('#myGrid', dataView, columns, options);
............
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
dataView.setItems(ServerResponse.data);
dataView.endUpdate();
// Refresh the data render, if user only clicked on the refresh button instead of refreshing the whole page from browser
grid.updateRowCount();
grid.render();
}

Json data not showing in extjs grid

Given data in the form:
var grid_data = [ {Hello: 'World'}, {Jesus:'Navas'} ]
I wish to draw a grid like so:
The grid shows with 2 rows but with no data, I can't find the problem in the following code:
var grid_store = Ext.create('Ext.data.Store', {
fields: [
{name: 'Property'},
{name: 'Value'}
],
data: grid_data
});
// create the Grid
var grid_view = Ext.create('Ext.grid.Panel', {
store: grid_store,
renderTo: 'info_panel',
stateful: true,
stateId: 'stateGrid',
columns: [
{
text : 'Property',
width : 100,
sortable : true,
dataIndex: 'Property'
},
{
text : 'Value',
width : 80,
sortable : false,
dataIndex: 'Value'
}
],
height: 350,
width: 600,
title: 'Array Grid',
viewConfig: {
stripeRows: true
}
});
Renders to:
<div id="info_panel"></div>
If you're wondering how I got the example image, I changed the store to an ArrayStore and re-formatted the data into arrays, but I'd prefer to miss out that step and insert the data as-is.
edit:
I think what I'm really asking for is a way to alert extjs to use the JSON keys as values, as opposed to most of the grid examples out there that take the form:
{value: 'Hello'}, {property: 'World'}
As one of the commenters and your edit suggested, your grid is built to consume a json with 'Property' and 'Value' being the keys for the json objects. I don't know if it's possible for you to change the source of the data to send in the reformatted json, but if not, you can always just run a quick loop to do so after receiving the data:
var new_data = [];
Ext.each(grid_data, function(obj) {
for (var prop in obj) {
new_data.push({
Property: prop,
Value: obj[prop]
});
}
}, this);

Array for Highcharts:

I just play around with Highcharts (http://www.highcharts.com) inside of a test app based on rails 3.1.1 and HAML. I'm still new to js and I try to accomplish a nice integration of highcharts.
In my controller I set up some json arrays for usage in highcharts.
#category_ids_json = Category.all(:conditions => { :income => false},:select => "id").to_json
#categories_json = Category.all(:conditions => { :income => false}, :select => "id,title,income").to_json
#transactions_json = Transaction.all(:select => "date,title,amount,category_id").to_json
Out of these instance variables, I filter some values and create a new array, which i use for the highcharts data array:
var category_transactions_sum = new Array();
category_transactions_sum.push({title:categories[c].title, amount: transactions_sum})
The content of the array looks somehting like this:
[{title: "Salary", amount: 50},{title: "Food", amount: 25},{title: "Recreation", amount: 10}]
Now I'm stuck when it is time to initialize Highcharts. This is how I initialize it right now:
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
series: [{
type: 'pie',
name: 'Expenses',
data: [
[category_transactions_sum[0].title, category_transactions_sum[0].amount],
[category_transactions_sum[1].title, category_transactions_sum[1].amount],
[category_transactions_sum[2].title, category_transactions_sum[2].amount],
[category_transactions_sum[3].title, category_transactions_sum[3].amount],
[category_transactions_sum[4].title, category_transactions_sum[4].amount],
[category_transactions_sum[5].title, category_transactions_sum[5].amount],
[category_transactions_sum[6].title, category_transactions_sum[6].amount],
[category_transactions_sum[7].title, category_transactions_sum[7].amount],
[category_transactions_sum[8].title, category_transactions_sum[8].amount],
[category_transactions_sum[9].title, category_transactions_sum[9].amount],
[category_transactions_sum[10].title, category_transactions_sum[10].amount],
[category_transactions_sum[11].title, category_transactions_sum[11].amount],
[category_transactions_sum[12].title, category_transactions_sum[12].amount],
[category_transactions_sum[13].title, category_transactions_sum[13].amount],
[category_transactions_sum[14].title, category_transactions_sum[14].amount],
[category_transactions_sum[15].title, category_transactions_sum[15].amount],
[category_transactions_sum[16].title, category_transactions_sum[16].amount],
[category_transactions_sum[17].title, category_transactions_sum[17].amount],
[category_transactions_sum[18].title, category_transactions_sum[18].amount],
[category_transactions_sum[19].title, category_transactions_sum[19].amount],
[category_transactions_sum[20].title, category_transactions_sum[20].amount],
[category_transactions_sum[21].title, category_transactions_sum[21].amount],
[category_transactions_sum[22].title, category_transactions_sum[22].amount],
[category_transactions_sum[23].title, category_transactions_sum[23].amount],
[category_transactions_sum[24].title, category_transactions_sum[24].amount],
[category_transactions_sum[25].title, category_transactions_sum[25].amount],
[category_transactions_sum[26].title, category_transactions_sum[26].amount],
]
}]
});
My Questions:
How would i iterate through the category_transactions_sum array to get rid of that bunch of lines inside of the "data" declaration of highcharts. I tried a for loop but it didn't work.
Is there a better way to insert the data into highcharts? Highcharts needs data in this format:
data: [
['Firefox', 45.0],
['IE', 26.8],
['Safari', 8.5],
['Opera', 6.2],
['Others', 0.7]
]
Is it possible to do something like this?
data: [
myArrayWithPreparedData
]
If yes, how would i build this array?
Many thanks for helping a newbie out.
I believe you want something like this:
data: $.map(category_transactions_sum, function(i, c) { return [c.title, c.amount]; })
you can try this (works for me):
temp = $.map(json, function(i) { return [[i.in_time, i.status]]; })
showData = JSON.parse(JSON.stringify(temp, null, ""));
and then use in the series as :
chart.addSeries({
data: showData
});
Alex almost has it.
Should be:
someVar = [{title: "Salary", amount: 50},{title: "Food", amount: 25},{title: "Recreation", amount: 10}]
data = $.map(someVar, function(i) { return [[i.title, i.amount]]; })
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
series: [{
type: 'pie',
name: 'Expenses',
data: data
}]
});

Categories