If I have a JSON result that has many rows, sometimes up to 100
Label:Part1 Value:1000
Label:Part2 Value:700
Label:Part3 Value:600
Label:Part4 Value:500
... and so on
I would like to change the data so that it lists the top 5 results as normal, but instead of listing the rest, it sums the value and changes the label to 'others'.
Example
Label:Part1 Value:1000
Label:Part2 Value:700
Label:Part3 Value:600
Label:Part4 Value:500
Label:Part5 Value:500
Label:other Value:25650
Is this possible to do in javascript, before I pass to a chart.js pie? Or is there a better method to achieve this?
Current code for pie
function chart1(branch, apitime){
$.ajax({
url: jsonpath' + apitime + branch,
dataType: 'jsonp',
success: function (response) {
console.log (response);
var datachart = response;
var ctx2 = document.getElementById("chart-area2").getContext("2d");
var myChart = new Chart(ctx2).Pie(datachart);
}
});
}
Data is sorted and I could change the SQL on the server to do this also, I just don't know what the correct method is to do that.
JSON example here http://pastebin.com/p3Y9mSX3
You can modify your data just before creating the chart.
var top6 = datachart.slice(0,5)
top6[5] = {
label: 'other',
value: datachart.slice(5).reduce(function(sum, data) {
return sum + data.value
}, 0)
}
var ctx2 = document.getElementById("chart-area2").getContext("2d");
var myChart = new Chart(ctx2).Pie(top6);
This can be made more general to get the top N entries
var getTopN = function(dataArray, n)
var tops = dataArray.slice(0, n)
tops[n] = {
label: 'other',
value: dataArray.slice(n).reduce(function(sum, data) {
return sum + data.value
}, 0)
}
return tops
}
var top5 = getTopN(datachart, 5)
var top10 = getTopN(datachart, 10)
Related
I am trying to convert a JSON string into an integer so that I can use this data in a google chart. As of right now I can only get one set of data to be displayed in my chart.
Here is my JQUERY code:
$("#shotsandbigcc").click(function(){
//alert("Button works");
$("#shotsandbigcc_popup").toggle();
var integer = $("#shotsandbigcc").attr("name");
//alert("integer: " + integer);
$.ajax('includes/test.php', {
type: 'POST', // http method
data: {myData: integer},// data to submit
dataType: 'json',
success: function(response){
google.charts.load('current', {packages: ['corechart', 'bar']});
google.charts.setOnLoadCallback(drawMultSeries);
function drawMultSeries() {
var len = response.length;
for(var i=0; i<len; i++){
var year = response[i].Year;
var ontarget = parseInt(response[i].Shots_on_Target);
var offtarget = parseInt(response[i].Shots_off_Target);
alert(ontarget);
}
alert(year);
var data = google.visualization.arrayToDataTable([
['Year', 'Shots on Target', 'Shots off Target'],
[year, ontarget, offtarget],
[year, ontarget, offtarget]
]);
var options = {
title: 'Shooting Accuracy',
chartArea: {width: '50%'},
hAxis: {
title: 'Amount of Shots',
minValue: 0
},
vAxis: {
title: 'Year'
}
};
var chart = new google.visualization.BarChart(document.getElementById('shotsandbigcc_chart'));
chart.draw(data, options);
}
}
});
});
The JSON data is in an array which has this format [{"Year":"2019/2020","Shots_on_Target":"302","Shots_off_Target":"578","Accuracy":"0.34"},{"Year":"2020/2021","Shots_on_Target":"74","Shots_off_Target":"93","Accuracy":"0.44"}]
If someone could tell me how I can display both 2019/2020 and 2020/2021 data to be displayed. I would be most grateful as right now only the 2020/2021 data is being displayed. Thank you.
For integet value part:
var ontarget = parseInt(response[i].Shots_on_Target);
For your data part:
var vizData = [];
vizData.push(['Year', 'Shots on Target', 'Shots off Target']);
for(var i=0; i<len; i++){
var year = response[i].Year;
var ontarget = parseInt(response[i].Shots_on_Target);
var offtarget = parseInt(response[i].Shots_off_Target);
vizData.push([year, ontarget, offtarget]);
alert(ontarget);
}
alert(year);
var data = google.visualization.arrayToDataTable(vizData);
explaination: since in the loop the values are getting updated in every iteration so, the 'year', 'ontarget' and 'offtarget' will have the latest values only. So on every iteration you have to store values so that they do not get overwritten. For that now this code is pushing in array in every iteration preserving the previous values. Which now you can use in the google.visualization function.
Happy Coding!
I am using the following code to render an OHLC chart in CanvasJS:
<script>
var candleData = [];
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: 'Demo Stacker Candlestick Chart (Realtime)'
},
zoomEnabled: true,
axisY: {
includeZero: false,
title: 'Price',
prefix: '$'
},
axisX: {
interval: 1,
},
data: [{
type: 'ohlc',
dataPoints: candleData
}
]
});
function mapDataToPointObject(data) {
var dataPoints = [];
for(var i = 0; i < data.length; i++) {
var obj = data[i];
var newObj = {
x: new Date(obj.time),
y: [
obj.open,
obj.high,
obj.low,
obj.close
]
}
dataPoints.push(newObj);
}
return dataPoints;
}
function updateChart() {
$.ajax({
url: 'http://localhost:8080',
success: function(data) {
candleData = JSON.parse(data);
candleData = mapDataToPointObject(candleData);
chart.render();
}
});
}
$(function(){
setInterval(() => {
updateChart();
}, 500);
});
The data properly loads, parses into the correct format, and render() is called on the interval like it should. The problem is, while the chart axes and titles all render properly, no data shows up. The chart is empty.
What DOES work is setting the data directly to the chart using
chart.options.data[0].dataPoints = candleData;
Why does my above solution not work then? Is there a way I can update the chart's dataPoints without having to hardcode a direct accessor to the chart's dataPoints?
It's related to JavaScript pass by value and pass by reference.
After execution of the following line.
dataPoints: candleData
dataPoints will refer to the current value of candleData. ie. dataPoints = [];
Now if you redefine candleData to any other value.
candleData = JSON.parse(data);
candleData = mapDataToPointObject(candleData);
Then dataPoints won't be aware of this update and will still refer to the empty array (that you pointed earlier).
The following snippet will make it easy to understand
//pass by value
var a = "string1";
var b = a;
a = "string2";
alert("b is: " + b); //this will alert "string1"
//pass by reference
var c = { s: "string1" };
var d = c;
c.s = "string2";
alert("d.s is: " + d.s); //this will alert "string2"
For more, you can read about pass by value and pass by reference.
Javascript by reference vs. by value
Explaining Value vs. Reference in Javascript
I would like to have the gauge chart update live dweet data, which is success.
The problem is that every time a new data is pushed to the array humidityData, a new pointer is added in the gauge chart as shown here:
guage chart Though I'd like to have one live-updating-pointer instead.
Could this be done by pop() the prev data?
<script language="JavaScript">
//Array to store sensor data
var humidityData = []
<!--START-->
$(document).ready(function() {
//My Dweet thing's name
var name = 'dweetThingName'
//Humidity chart
var setupSecondChart = function() {
var chart2 = {
type: 'gauge'
};
var title = {...};
var pane = {...};
var yAxis = {...};
var tooltip = {
formatter: function () {
return '<b>' + "Humidity: " + Highcharts.numberFormat(this.y, 2) + "%";
}
};
//Series_Humidity
humiditySeries = [{
name: 'Humidity %',
data: humidityData,
tooltip: {
valueSuffix: '%'
}
}]
//Json_Humidity
var humJson = {};
humJson.chart = chart2;
humJson.title = title;
humJson.tooltip = tooltip;
humJson.xAxis = xAxis;
humJson.yAxis = yAxis;
humJson.legend = legend;
humJson.exporting = exporting;
humJson.series = humiditySeries;
humJson.plotOptions = plotOptions;
console.log("Sereies: : " +humJson)
//Container_Humidity
$('#containerHumidity').highcharts(humJson);
}
var humiditySeries = [] ....
dweetio.get_all_dweets_for(name, function(err, dweets){
for(theDweet in dweets.reverse())
{
var dweet = dweets[theDweet];
//Dweet's variables' names
val2 = dweet.content["Humidity"]
//Add the vals into created arrayDatas
humidityData.push(val2)
console.log("HumidityData: " + humidityData)
}
//Call other charts
setupSecondChart()
});
When you initialize/update your chart make sure that data array contains only one element. The dial is created for every point in this array (to visualize it on the plot).
I am developing an web app in which the user will be able to identify the location from map by clicking on the map (I use jquery 3.1). The problem is that I have to make some ajax calls, one depend on other, and on the last call the result it's not returned as a whole (full array) and I received only a part of array.
The problem survives from var a4.
How I can make that a4 result to be send as a full array because I tried with deferred but with no expecting result?
var getLocDetails = function () {
// Parse a web api based on user lat & lon
var a1 = $.ajax({
method: 'GET',
url: 'http://nominatim.openstreetmap.org/reverse?lat=44.43588&lon=26.04745&accept-language=ro&format=json'
});
// Get osm_type & osm_id and parse another web service to get a XML document (Ex.: https://www.openstreetmap.org/api/0.6/way/28240583)
var a2 = a1.then(function (data) {
return $.ajax({
method: 'GET',
url: 'https://www.openstreetmap.org/api/0.6/' + data.osm_type + '/' + data.osm_id
})
});
// Get all 'ref' attribute from every 'nd' node from XML and make an array with this values
var a3 = a2.then(function (data) {
var osmChildren = data.documentElement.childNodes;
var out = [];
for (var i = 0; i < osmChildren.length; i++) {
if (osmChildren[i].nodeName == 'way') {
var wayChildren = osmChildren[i].childNodes;
for (var j = 0; j < wayChildren.length; j++) {
if (wayChildren[j].nodeName == 'nd') {
var ndRef = Number.parseInt(wayChildren[j].getAttribute('ref'));
out.push(ndRef);
}
}
}
}
return out;
});
// HERE IS THE PROBLEM
// Based on array returned from a3, I am parsing every link like 'https://www.openstreetmap.org/api/0.6/node/ + nodeRef' to extract every lat and lon values for extreme points
var a4 = a3.then(function (data) {
var defer = $.Deferred();
var out = [];
for (var i = 0; i < data.length; i++) {
var nodeRef = data[i];
var nodeUrl = 'https://www.openstreetmap.org/api/0.6/node/' + nodeRef;
$.ajax({
method: 'GET',
url: nodeUrl
}).done(function (response) {
var node = response.documentElement.firstElementChild;
var lat = Number.parseFloat(node.getAttribute('lat'));
var lng = Number.parseFloat(node.getAttribute('lon'));
out.push([lat, lng]);
defer.resolve(out);
});
}
return defer.promise();
});
// When a4 is done, based his result, I have to have an array of lat & lon coordonates, but I recived only 1-2 coordonates even I have 10.
a4.done(function (data) {
console.log(data);
// Here I have to draw a polygon
});
}
you need to handle the requests in an array, as what you are doing tends to resolve the callback for a4 before all are complete.
To do this we can use $.when function
var req = [];
// Based on array returned from a3, I am parsing every link like 'https://www.openstreetmap.org/api/0.6/node/ + nodeRef' to extract every lat and lon values for extreme points
var a4 = a3.then(function (data) {
var defer = $.Deferred();
var out = [];
for (var i = 0; i < data.length; i++) {
var nodeRef = data[i];
var nodeUrl = 'https://www.openstreetmap.org/api/0.6/node/' + nodeRef;
req.push(
$.ajax({
method: 'GET',
url: nodeUrl
}).done(function (response) {
var node = response.documentElement.firstElementChild;
var lat = Number.parseFloat(node.getAttribute('lat'));
var lng = Number.parseFloat(node.getAttribute('lon'));
out.push([lat, lng]);
})
);
}
$.when.apply($, req).done(function(){
return defer.resolve(out);
});
return defer.promise();
});
I need to know how I can easily add another series to an existing plot using Flot.
Here is how I currently plot a single series:
function sendQuery() {
var host_name = $('#hostNameInput').val();
var objectName = $('#objectNameSelect option:selected').text();
var instanceName = $('#instanceNameSelect option:selected').text();
var counterName = $('#counterNameSelect option:selected').text();
$.ajax({
beforeSend: function () {
$('#loading').show();
},
type: "GET",
url: "http://okcmondev102/cgi-bin/itor_PerfQuery.pl?machine=" + host_name + "&objectName=" + objectName + "&instanceName=" + instanceName + "&counterName=" + counterName,
dataType: "XML",
success: function (xml) {
var results = new Array();
var counter = 0;
var $xml = $.xmlDOM(xml);
$xml.find('DATA').each(function () {
results[counter] = new Array(2);
results[counter][0] = $(this).find('TIMESTAMP').text();
results[counter][1] = $(this).find('VALUE').text();
counter++;
});
plot = $.plot($("#resultsArea"), [{
data: results,
label: host_name
}], {
series: {
lines: {
show: true
}
},
xaxis: {
mode: "time",
timeformat: "%m/%d/%y %h:%S%P"
},
colors: ["#000099"],
crosshair: {
mode: "x"
},
grid: {
hoverable: true,
clickable: true
}
});
You can just add another results set:
// build two data sets
var dataset1 = new Array();
var dataset2 = new Array();
var $xml = $.xmlDOM(xml);
$xml.find('DATA').each(function(){
// use the time stamp for the x axis of both data sets
dataset1[counter][0] = $(this).find('TIMESTAMP').text();
dataset2[counter][0] = $(this).find('TIMESTAMP').text();
// use the different data values for the y axis
dataset1[counter][1] = $(this).find('VALUE1').text();
dataset2[counter][2] = $(this).find('VALUE2').text();
counter++;
});
// build the result array and push the two data sets in it
var results = new Array();
results.push({label: "label1", data: dataset1});
results.push({label: "label2", data: dataset2});
// display the results as before
plot = $.plot($("#resultsArea"), results, {
// your display options
});
At a high-level, the result of your call into itor_PerfQuery.pl will need to be extended to include the additional series data. You'll then want to make your "results" variable a multi-dimensional array to support the additional data and you'll need to update the current xml "find" loop which populates results accordingly. The remainder of the code should stay the same as flot should be able to plot the extended dataset. I think a review of the flot example will help you out. Best of luck.