Sort JSON by names and not values - javascript

I'm running a query in java to get the quantity of calls in a time interval, the result of this query is:
Date(dd/mm/yyyy) | calls
_____________________|___________
17/05/18 | 30
16/05/18 | 36
10/05/18 | 14
27/04/18 | 12
26/04/18 | 90
But when I plot the result using chart js, data is displayed in the order as belows
Date(dd/mm/yyyy) | calls
_____________________|___________
10/05/18 | 14
26/04/18 | 90
27/04/18 | 12
16/05/18 | 36
17/05/18 | 30
¿How do I sort this JSON by date using javascript?
{2018-05-10: "14", 2018-04-26: "90", 2018-04-27: "12", 2018-05-16: "36", 2018-05-17: "30"}

First of all, your JSON is not valid. Those property names (the dates) must be quoted as strings for it to be valid.
Now, the best way to approach this is to actually change the JSON you're producing to an array:
data = [
{ "date": "2018-05-10", "hits": "14" },
{ "date": "2018-04-26", "hits": "90" },
// etc
];
If you produce this on the server, which should be easy to change, then processing it in the client should be a lot easier. In fact, if you can format your dates on the server as YYYY-MM-DD then, given the above, Chart.js should automatically understand it as a date and you can simply map it to the x axis with something like...
let data = ... // The array above
let chartData = data.map(function(p) {
return { x: p.date, y: p.hits };
});
var chart = new Chart(ctx, {
type: '...',
data: chartData,
// etc
});
If for whatever reason you cannot change the format of the JSON produced (but, of course, you still quote the dates to make the JSON valid), then you could try something like this:
let data = ... // Your JSON corrected to be valid
let chartData = Object.keys(data).map(function(k) {
let date = k.split('/').reverse().join('-');
return { x: date, y: data[k] };
});
var chart = new Chart({
type: '...',
data: chartData,
// etc
});

Related

How to combine a single array of objects based on multiple properties

Utilizing javascript, I have an array of objects that looks like this:
id | date | store | type | txn | failed
------------------------------------------------
1 | 10-02-18 | 32 | short | 4 | false
2 | 10-02-18 | 32 | long | null | true
3 | 10-03-18 | 32 | short | 7 | false
4 | 10-03-18 | 32 | long | 10 | false
I want to be able to transform this array into something that looks like this:
[
{
date: 10-02-18,
store: 32,
short: {
txn: 4,
failed: false,
},
long: {
txn: null,
failed: true,
},
},
{
date: 10-03-18,
store: 32,
short: {
txn: 7,
failed: false,
},
long: {
txn: 10,
failed: true,
},
}
]
You can see I would like to combine the "type", "txn" and "failed" properties with row that have the same "date" and "storeId", adding the "type" as a property and "txn" and "failed" as child properties of the "type". The "id" property could be ignored in the new array.
I use lodash quite a bit but that isn't a requirement for this. I'm just struggling to wrap my head around how to do this transformation.
You basically just need to create an object with keys that represent something unique to the groups you want. You could make keys that are concatenations of store_date for example and the object will only have one of those and it will be quick to get if you have the store and date. You can build an object like this with reduce. Once you have the object, you can simply call Object.values to get the array of values. For example:
let arr = [
{id:1, date: "10-02-18",store: 32, type: "short", tx: 4, failed: false},
{id:2, date: "10-02-18",store: 32, type: "long", tx: null, failed: true},
{id:3, date: "10-03-18",store: 32, type: "short", tx: 7, failed: false},
{id:4, date: "10-03-18",store: 32, type: "long ", tx: 10, failed: false}
]
let obj = arr.reduce((obj, {id, date, store, type, tx, failed}) => {
// make a unique key
key = `${date}_${store}`
// if we haven't seen this key add it with the outline of the object
if(!obj[key]) obj[key] = {date, store}
// add specific type to either the found obj or the new one
obj[key][type] = {tx, failed}
return obj
}, {})
// obj is an object keyed to date_store
// get just the values
console.log(Object.values(obj))

Load javascript array into Chartist.js as serie

I decided it would be a fun project to see if i could take data from Google Analytics and display that in a custom dashboard, and hopefully learn a thing or two about using json, and javascript.
after a lot of debugging i now managed to pull the data from the Google Analytics server with their php api, and save the output into data.json on the server.
below the data.json, it's valid as per JSONLint.com:
{
"0": {
"date": "20160113",
"pageviews": "46",
"sessions": "21"
},
"1": {
"date": "20160114",
"pageviews": "66",
"sessions": "18"
},
"2": {
"date": "20160112",
"pageviews": "50",
"sessions": "14"
},
"3": {
"date": "20160116",
"pageviews": "19",
"sessions": "14"
},
"4": {
"date": "20160117",
"pageviews": "23",
"sessions": "14"
},
"5": {
"date": "20160115",
"pageviews": "38",
"sessions": "11"
},
"6": {
"date": "20160118",
"pageviews": "35",
"sessions": "9"
},
"7": {
"date": "20160119",
"pageviews": "15",
"sessions": "7"
}
}
Now i've tried to use the data from data.json and feed it into chartist's labels/series in order to draw a graph.
var labelArray = [];
var seriesArray = [];
var labelOutput = [];
$.getJSON("data.json", function(json) {
//var jsonObj = JSON.parse(json);
for (var i in json){
labelArray.push(json[i].date);
};
for (var i in json){
seriesArray.push(json[i].sessions);
};
// var myData = {
// labels:
// }
// labelOutput = labelArray.join(',')
// seriesOutput = serieArray.join(',')
console.log(labelArray);
console.log(seriesArray);
// this will show the info it in firebug console
});
new Chartist.Line('.ct-chart', {
labels: [labelArray],
series: [[seriesArray]]
});
However I'm currently out of ideas why this would not work, the labels on X and Y axis are correctly shown, but no graph shows up.
I've tried using .join to see if that makes a difference, but using labelOutput instead of labelArray also doesn't change anything.
In the console the array that is being fed into chartist seems all right to me, if I copy paste it from the console into the script everything works.
Current output for labelArray and seriesArray:
labelArray
Array [ "20160113", "20160114", "20160112", "20160116", "20160117", "20160115", "20160118", "20160119" ]
seriesArray
Array [ "21", "18", "14", "14", "14", "11", "9", "7" ]
Anyone knows why chartist.js does manage to add the correct labels along the axes but fails to read the same data and draw the chart?
Although the answer by #mnutsch works, there is an easier way to add dynamic content into the chart.
You can simply add the arrays directly as parameters, which I think is what the OP was trying to do.
response object would be the ajax data
var seriesVals = [];
var labelsVals = [];
for (var i = 0; i < response.length; i++) {
seriesVals.push(response[i].total);
labelsVals.push(response[i].response_code);
}
var pieData = {
series: seriesVals,
labels: labelsVals
};
In case anyone comes across this later, you can also do it like this:
//Create javascript arrays with the values and labels, replace this with code to read from the database/API/etc.
var array_1_values = [100, 120, 180, 200, 90]; //these are the values of the first line
var array_2_values = [20, 35, 65, 125, 245]; //these are the values of the second line
var array_labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']; //these are the labels that will appear at the bottom of the chart
//create a prototype multi-dimensional array
var data_chart1 = {
labels: [],
series: [
[],
[]
]
};
//populate the multi-dimensional array
for (var i = 0; i < array_1_values.length; i += 1)
{
data_chart1.series[0].push(array_1_values[i])
data_chart1.series[1].push(array_2_values[i])
data_chart1.labels.push(array_labels[i])
}
//set the size of chart 1
var options_chart1 = {
width: '300px',
height: '200px'
};
//create chart 1
new Chartist.Line('#chart1', data_chart1, options_chart1);
In case anyone else stumbles upon the problem, below is what I came up with to get it to work.
After another day of trail and error i managed to pinpoint the problem.
The problem was:
In the original situation I tried to use a plain array as input for both labels and series. However, Chartist requires objects to render the labels/series as well as the graph.
The below works for me pulling the data from the data.json, adding it to an object and provide it to chartist.
var labelArray = {};
var seriesArray = {};
var labelOutput = [];
var Output
// $.getJSON("data.json", function(json) {
$.ajax({
url: 'data.json',
async: false,
dataType: 'text',
success: function(json) {
labelArray = JSON.parse(json);
data = {
labels:
[
labelArray[0].date,
labelArray[1].date,
labelArray[2].date,
labelArray[3].date,
labelArray[4].date,
labelArray[5].date,
labelArray[6].date
],
series: [[
labelArray[0].sessions,
labelArray[1].sessions,
labelArray[2].sessions,
labelArray[3].sessions,
labelArray[4].sessions,
labelArray[5].sessions,
labelArray[6].sessions
]]
}
}
});
new Chartist.Line('.ct-chart', data);
Decided to go with $.ajax to get the json file rather than getJSON as this allows me to disable asynchronous loading, ensuring the data is available when the graph is drawn.
Also, it is possible to set the dataType to Json rather than text, but this gives error in the JSON.parse line. Assuming that is because it tries to parse json as json, and fails to do so. But this is the only way i managed to get it to work, and add the json to an object.
Most likely the whole labelArray[0].date, labelArray[1].date is rather inefficient and should be improved but it works for now.

Highstock - Pulling data from JSON file

I understand there are many similar questions related to this topic on SO however, I was unsuccessful at implementing what I am trying to do so I am writing a question here. Please understand that I am very new.
So, basically, using the Highstock - the basic graph which can be found here http://www.highcharts.com/stock/demo/basic-line, I want to import the data from an JSON file named Json1.json. How would I do this? http://jsfiddle.net/x0g8hL0e/1/
In the JavaScript, I have written
$(function () {
$.getJSON('Json1.json', function (data) {
// Create the chart
$('#container').highcharts('StockChart', {
rangeSelector : {
selected : 1
},
title : {
text : 'Pressure'
},
});
});
});
Also, is it possible to just see the 24 hour format instead of a year-long?
P.S, Json data is formatted in this way
[
{"Pressure": 1},
{"Pressure": 5},
{"Pressure": 3},
{"Pressure": 2},
{"Pressure": 4}
}]
You should process your data, so it will be in a format that is accepted by Highcharts. It can be (as described in API reference):
An array of numerical values.
An array of arrays with 2 values.
An array of objects with named values.
Other option is to use an array with keys defined.
If you want to use e.g. 1st data fromat, then you could go through your JSON and create an array of numerical values with values taken out of each object, from Pressure property.
$(function () {
//$.getJSON('Json1.json', function (data) {
// simulate JSON data
var data = [{
"Pressure": 1
}, {
"Pressure": 5
}, {
"Pressure": 3
}, {
"Pressure": 2
}, {
"Pressure": 4
}],
processedData = [];
// process the data to match one of formats required by Highcharts - an array of numberical values
// see: http://api.highcharts.com/highstock#series<line>.data
Highcharts.each(data, function(d) {
processedData.push(d.Pressure);
});
// Create the chart
$('#container').highcharts('StockChart', {
rangeSelector: {
selected: 1
},
title: {
text: 'Pressure'
},
series: [{
data: processedData
}]
});
//});
});
JSFiddle
For basic information about Highcharts you could see General Documentation

Flatten D3.js Nested Data or Map it to new Dataset

Total noob to D3.js and working on creating my first grouped bar chart. However I'm having trouble making my data fit with the examples online. I am trying to use this example here, with my data that has been nested JSON with D3.
My problem is i cant use the d3.keys method to retrieve keys because my keys are not the state names. They are just Key.
Not to mention the second half forEach wont work because again the keys are not the State names, they are just the term key. So +d[name] will try d[MAPLE] when really my value is inside a key of d.values[(Get the Value where the key = name)]. Just really confused how to do this once the data has been nested in JSON
How would I go about getting all possible Key Values, and then mapping the keys with the next level of keys and values? Using a similar example as below but with my JSON nested data.
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
My data is as so
{
"key": "1/10/2014",
"values": [
{
"key": "Texas",
"values": 200
},
{
"key": "Colorado",
"values": 300
},
{
"key": "Utah",
"values": 227
}
]
},{
"key": "2/10/2014",
"values": [
{
"key": "Texas",
"values": 225
},
{
"key": "Colorado",
"values": 241
},
{
"key": "Utah",
"values": 500
}
]
}
It's not clear from the question if the aim is to group by state ("Texas", "Colorado"...) or date ("1/10/2014", "2/10/2014"...) along the x-axis.
Assuming date (because that's how the data is currently structured), here's a working plunk: http://plnkr.co/edit/C8lkPMGanFY9BkTc6f1i?p=preview
The code that processes the data into a format that your existing D3 code for grouped bar chart can handle looks like this:
// Call the first mapping function on every 'date' in the data array
processed_data = data.map( function (d) {
var y0 = 0;
var total = 0;
return {
date: d.key,
// Call the second mapping function on every 'state' in the given date array
values: (d.values).map( function (d) {
return_object = {
state: d.key,
count: d.values,
y0: y0,
y1: y0 + d.values
};
// Calculate the updated y0 for each new state in a given date
y0 = y0 + d.values;
// Add the total for a given state to the sum total for that date
total = total + d.values;
return return_object;
}),
total: total
};
});
We use nested array.map transforms to manipulate your two-level nested data into the expected format and calculate y0, y1 and total values. Your processed_data object will then look like this:
The only other tricky bit will be to calculate your list of unique states, in order to define the color.domain. If you don't want to hard-code this (e.g. because the list may vary from dataset to dataset, you could use this approach:
// Define the color domain, by first building a list of states:
var states = [];
// Loop through each date
processed_data.forEach(
function (d) {
// Loop through each state in that date
d.values.forEach(
function(d) {
// add to the array if not already present
if (!(states.indexOf(d.state) > -1)) {
states.push(d.state)
}
}
)
}
);
color.domain(states);

Highcharts proper usage of datetime?

My current setup is somewhat static with xaxis categories and tickinterval(cant even see the graph without tickinterval).
If you change screen resolution it looks somewhat bad and I would like to have the x-axis to be dynamic.
What I've gathered you should use data like this http://www.highcharts.com/samples/data/usdeur.js and xAxis like below?
xAxis: { type: 'datetime' }
But that example only uses YYMMDD, I also use hh:mm:ss.
Currently looks like this: i.imgur.com/v649otj.png
xAxis: {
categories: getjson('Date'),
tickInterval: 20
},
series: [
{name:'Cars', data: getjson('Values')},
]
Data:
getjson('Date') equals:
Array [ "2014-11-09 02:36:00", "2014-11-07 07:35:00", "2014-11-08 20:29:00", "2014-11-08 20:30:00", "2014-11-10 11:06:00", "2014-11-08 08:12:00", "2014-11-08 20:31:00", "2014-11-08 20:23:00", "2014-11-08 20:24:00", "2014-11-08 20:25:00", 190 till… ]
getjson('Values') equals:
Array [ 13, 209, 209, 19, 0, 209, 15, 13, 13, 19, 190 till… ]
So how do I make use of this data and the datetime configuration.
Somehow push the 'Date'-data into same array as 'values' and convert it into right date format?
Edit: Current work: http://jsfiddle.net/tws8x0pd/4/
Datetime configuration uses UTC numbers not YYMMDD! You should pass your datetime data with Date.UTC(year,month,day,hour,minute,second) in Series data with the format:
series: [
{name:'...', data: [ [ Date.UTC(year,month,day,hour,minute,second), value ],
[ Date.UTC(year,month,day,hour,minute,second), value ],
...
]
}
]
so you should get the year,month,... out of your json date and put it with the corresponding value in json values. Each in one array, not apart in separate arrays.
The time require to be as timestamp (time in miliseconds) not strnig as you have. So you need to prepare correct data by Date.parse() / Date.UTC()

Categories