c3.js generate a stacked bar from JSON payload - json

I am attempting to generate a stacked bar chart with c3 when using a JSON payload (code below). However, when I group the data, instead of having a stacking behavior, they overlay instead. If I use the column structure, I get the intended behavior, but this means that I'd have different code generate for a stacked bar chart versus my other visuals (ie timeseries chart).
var chart = c3.generate({
data: {
x: "x-axis",
json:[
{ "x-axis": "0",
"data1": 30
},
{ "x-axis": "0",
"data2": 40
}],
keys: {
x: "x-axis",
value: ["data1", "data2"]
},
groups: [
['data1', 'data2']
],
type: 'bar'
}
});
Here is a fiddle: http://jsfiddle.net/cjrobinson/ozf4fzcb/

It's weird they overplot each other in your example, I'd report that as a bug to c3
If you don't want to use the columns[] format, you could do it like below, would still need some data wrangling though:
var chart = c3.generate({
data: {
x: "x-axis",
json:[
{ "x-axis": "0",
"data1": 30,
"data2": 40
},
{ "x-axis": "1",
"data1" :20,
"data2": 60
}],
// etc etc
keys: {
x: "x-axis",
value: ["data1", "data2"]
},
groups: [
['data1', 'data2']
],
type: 'bar'
}
});
http://jsfiddle.net/dhgujwy7/1/

Related

Why console.log does not show all levels of JSON after parsing?

I am practicing with simple APIs. I request data from OXFORD API. The data is received correctly and I can navigate through it and extract the definitions or etymologies I want. However when I print the complete response after the .json() the content of some arrays is shown as [Array]. Any Idea what I am missing?
My code looks like this:
let endpoint = "https://od-api.oxforddictionaries.com/api/v2/entries/en-gb/ace?fields=definitions&strictMatch=false";
const headers: {
'app_id': app_id,
'app_key': app_key
}
fetch(endpoint, {headers} )
.then(rawResponse=>rawResponse.json())
.then(response=>{
console.log(response);
console.log(response.results[0].lexicalEntries[0].entries[0].etymologies[0])
});
Result in the console looks like:
'''
{
id: 'ace',
metadata: {
operation: 'retrieve',
provider: 'Oxford University Press',
schema: 'RetrieveEntry'
},
results: [
{
id: 'ace',
language: 'en-gb',
lexicalEntries: [Array],
type: 'headword',
word: 'ace'
},
{
id: 'ace',
language: 'en-gb',
lexicalEntries: [Array],
type: 'headword',
word: 'ace'
}
],
word: 'ace'
}
Middle English (denoting the ‘one’ on dice): via Old French from Latin as ‘unity, a unit’
'''
I had tried with Apps Script, I got same result
'''
results:
[ { id: 'ace',
language: 'en-gb',
lexicalEntries: [Object],
type: 'headword',
word: 'ace' },
'''
Thanks in advance
The first comment here inspired my answer and further search. console.log() mainly prints string and when passing to it an array or an object, it interpret them as far as it can. So for the first level of [object, object] or {A:[],B:[]} it would print it without a problem.
When we go deeper to more nested arrays and objects within the JavaScript object parsed from an API response, it won't be able to interpret it properly and would return [object] or [Array]
e.g. The following can be printed by console.log easily
console.log([{A:1},{B:2},{C:3}])
and returns
[ { A: 1 }, { B: 2 }, { C: 3 } ]
Also,
console.log([{A:1},{B:2},{C:3,D:[1,2,3]}])
easily prints
[ { A: 1 }, { B: 2 }, { C: 3, D: [ 1, 2, 3 ] } ]
But,
console.log([{A:1},{B:2},{C:3,D:[{E:1},{F:2},{G:3}]}])
returns
[ { A: 1 },
{ B: 2 },
{ C: 3, D: [ [Object], [Object], [Object] ] } ]
So we need, to use JSON.stingify to convert it into a string
console.log(JSON.stringify([{A:1},{B:2},{C:3,D:[{E:1},{F:2},{G:3}]}]))
Successfully returns
[{"A":1},{"B":2},{"C":3,"D":[{"E":1},{"F":2},{"G":3}]}]
However, When the JSON object is bigger and deeper, you might need to prettify it using
console.log(JSON.stringify([{A:1},{B:2},{C:3,D:[{E:1},{F:2},{G:3}]}],null,2))
it returns
[
{
"A": 1
},
{
"B": 2
},
{
"C": 3,
"D": [
{
"E": 1
},
{
"F": 2
},
{
"G": 3
}
]
}
]
You can find a reference in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

Google Embed API: GEO chart - show specific country

I'm using Google Embed API to show data from google analytics visually.
I was trying to display only a specific country to show users from each of its regions.
I create a "DataChart" which has a "query" and "chart" object. In the chart object, you specify a type of chart, and some extra options.
If I choose "GEO", then it will use the "Geocoding" api, as I've understood it.
I am not able to show the country (Sweden) with its regions however, I don't know what to specify in the chart "options" object.
var location = new gapi.analytics.googleCharts.DataChart({
query: {
'ids': viewId,
'start-date': '90daysAgo',
'end-date': 'today',
'metrics': 'ga:users',
'sort': '-ga:users',
'dimensions': 'ga:region',
'max-results': 10
},
chart: {
'container': 'location',
'type': 'GEO',
'options': {
region: 150, // <-- Europe
country: 'SE', // <-- just guessing
}
}
});
This shows the whole world. If I remove "country", it shows Europe, with the top part cropped away. So I haven't specified "country" in the correct way (I am only guessing since there is no info).
The only info I can find on the GEO chart is here Visualization: GeoChart, but it's not specific for the Embed API.
So does anyone have a solution for this case, and is there info on different properties for the chart object? ( For the query object, there is Dimensions & Metrics Explorer )
Update:
The main question was solved with a below answer:
'options': {
region: 'SE',
resolution: 'provinces'
}
, but the data is not displayed in the regions, so if you have any clues around that, you could perhaps mention it as a comment.
Here is part of the data response from the query (with regions):
"dataTable": {
"cols": [
{
"id": "ga:region",
"label": "ga:region",
"type": "string"
},
{
"id": "ga:users",
"label": "ga:users",
"type": "number"
}
],
"rows": [
{
"c": [
{
"v": "Stockholm County"
},
{
"v": "15"
}
]
},
{
"c": [
{
"v": "Vastra Gotaland County"
},
{
"v": "6"
}
]
},
here are the only configuration options for the GeoChart that I'm aware of...
to display only sweden...
var options = {
region: 'SE'
};
(remove the country option)
see following working snippet...
google.charts.load('current', {
'packages':['geochart'],
'mapsApiKey': 'AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY'
});
google.charts.setOnLoadCallback(drawRegionsMap);
function drawRegionsMap() {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
]);
var options = {
region: 'SE',
resolution: 'provinces'
};
var chart = new google.visualization.GeoChart(document.getElementById('chart'));
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>

jqGrid: formatter: "actions" doesn't work for remote json url

I tried to use jqGrid formatter: "actions" for remote json url but it shifts rows because number of column names and actual returned data doesn't match (act column is extra one in column names). I did search online and it looks like all examples are for local data (on page) where json is used as key/value, while url:somepage.php returns a csv kind-of-format of columns(no keys, just values). Also I use id as hidden field, while all examples show id. I use one more hidden column as well.
here is my colmodel:
url: "manager_json",
editurl: "manager_edit",
datatype: "json",
//data: mydata,
width:1000,
//jsonReader: {
// repeatitems : false,
// },
colNames: ["","Id","Uid","Custom Id","Image Name","Coord. X","Coord. Y","Gender","Progress","Status","Created","Updated"],
colModel: [{"name":"act","template":"actions","formatoptions":{"editformbutton":true}},{"name":"id","align":"center","width":33,"editable":false,"hidden":true},{"name":"uid","align":"center","width":33,"editable":true,"hidden":true,"editrules":{"edithidden":false,"required":false}},{"name":"ta_id","align":"center","width":100,"editrules":{"required":true}},{"name":"image","width":150,"template":"text","editrules":{"required":true}},{"name":"x","width":100,"align":"center","template":"integer","editrules":{"required":true}},{"name":"y","width":100,"align":"center","template":"integer","editrules":{"required":true}},{"name":"gender","width":100,"align":"center","formatter":"select","stype":"select","editrules":{"required":true},"edittype":"select","editoptions":{"value":"f:Female;m:Male","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;f:Female;m:Male"}},{"name":"progress","width":120,"align":"center","formatter":"select","stype":"select","editrules":{"required":true},"editable":false,"edittype":"select","editoptions":{"value":"-:New;pf:Process Failed;ps:Process Scheduled;pss:Process Success;p:Processing...;s:Staging;tf:Test Failed;ts:Test Scheduled;tss:Test Success;t:Testing...","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;-:New;pf:Process Failed;ps:Process Scheduled;pss:Process Success;p:Processing...;s:Staging;tf:Test Failed;ts:Test Scheduled;tss:Test Success;t:Testing..."}},{"name":"status","width":100,"align":"center","formatter":"select","stype":"select","edittype":"select","editoptions":{"value":"a:Active;n:New","defaultValue":"m"},"searchoptions":{"sopt":["eq","ne"],"value":":Any;a:Active;n:New"}},{"name":"date_created","width":150,"template":"text","editable":false},{"name":"last_updated","width":150,"template":"text","editable":false}]
And here is my actual data from my server (db) as per jqgrid specification:
{"page":1,"total":1,"records":7,"rows":[{"id":32,"cell":[32,"889daf31ff3e49544f52850258439600","2uu","2ok",2,2,"m","-","a","2017-02-10 18:57:05","2017-02-10 23:37:12"]},{"id":30,"cell":[30,"","11","11",1,1,"m","-","a","2017-02-10 18:01:52","2017-02-10 18:01:52"]},{"id":29,"cell":[29,"aaa","ww222111uu","11",1,1,"m","-","a","2017-02-10 18:00:36","2017-02-10 23:37:08"]},{"id":27,"cell":[27,"","11","1",1,1,"m","-","a","2017-02-10 17:57:41","2017-02-10 17:57:41"]},{"id":25,"cell":[25,"","4tt","4img",4,4,"f","-","n","2017-02-10 17:50:21","2017-02-11 00:26:03"]},{"id":24,"cell":[24,"","1","1",1,1,"m","-","a","2017-02-10 17:49:38","2017-02-10 17:49:38"]},{"id":22,"cell":[22,"","bbb","imam 222",2,22,"f","p","n","2017-02-08 20:14:55","2017-02-10 13:27:57"]}]}
As you can see cell row has less columns than colNames and colModel. Also id and uid columns are hidden. I added on extra fake column from db, but it did not help
i am using jqGrid 4.13.7-pre
I'd recommend you to return objects like
{
"id": 32,
"uid": "889daf31ff3e49544f52850258439600",
"ta_id": "2uu",
"image": "2ok",
"x": 2,
"y": 2,
"gender": "m",
"progress": "-",
"status": "a",
"date_created": "2017-02-10 18:57:05",
"last_updated": "2017-02-10 23:37:12"
}
instead of
{
"id": 32,
"cell": [
32, "889daf31ff3e49544f52850258439600", "2uu", "2ok", 2, 2, "m", "-", "a",
"2017-02-10 18:57:05", "2017-02-10 23:37:12"
]
}
as the server response. It will simplify your code.
If you do need to process the current format of the data, then you will have to force repeatitems: false mode by usage the option
jsonReader: {
repeatitems: false
}
and to use jsonmap property of colModel to inform jqGrid from which element of the item one should read the column data. The jsonmap could be either in the string form like
jsonmap: "cell.1"
or in the function form:
jsonmap: function (item) {
return item.cell[1];
}
To make the code better maintainable you can define an object like
var columnOrder = {
id: 0,
uid: 1,
ta_id: 2,
image: 3,
x: 4,
y: 5,
gender: 6,
progress: 7,
status: 8,
date_created: 9,
last_updated: 10
};
which provides the index in cell array by the column name and to use jsonmap like
jsonmap: function (item) {
return item.cell[columnOrder.uid];
}
The demo https://jsfiddle.net/OlegKi/ozzgnaeh/2/ demonstrates the approach.

C3 - Timeseries chart with JSON and categories

I am using C3 library for the first time and I think it's a good alternative to D3 for designing simple and reusable charts with no pain.
However, I have some issues in designing a timeseries chart.
Here is an example of the JSON file I will use to generate my chart:
data: {
json: [
{
"city": "Paris",
"date": "2016-09-01",
"event": 234
},
{
"city": "Paris",
"date": "2016-09-02",
"event": 891
},
{
"city": "Paris",
"date": "2016-09-03",
"event": 877
},
{
"city": "Berlin",
"date": "2016-09-01",
"event": 190
},
{
"city": "Berlin",
"date": "2016-09-02",
"event": 234
},
{
"city": "Berlin",
"date": "2016-09-03",
"event": 231
},
{
"city": "London",
"date": "2016-09-01",
"event": 23
},
{
"city": "London",
"date": "2016-09-02",
"event": 12
},
{
"city": "London",
"date": "2016-09-03",
"event": 89
},
],
The problem is that I can not set both my axis x: as a timeseries type and the key "city" as a category type.
For now I have:
keys: {
x: 'period',
value: ['event'],
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d'
}
}
},
type: 'spline'
And the corresponding Plunker: http://plnkr.co/edit/T1aLWQpaFwdu2zsWCa3d
I would like to have 3 splines, corresponding to the 3 cities that are retrieved from the JSON file.
Can you help me achieve this ?
Thank you very much :)
You need to wrangle your data into a format that c3 finds acceptable, which is akin to the example here -->https://jsfiddle.net/maxklenk/k9Dbf/
For yours we'd need an array of entries like
[{
date = val
London = val
Paris = val
Berlin = val
},
...
]
To do that we need to manipulate the original json:
var json = <defined here>
// group json by date
var nestedData = d3.nest().key(function(d) { return d.date; }).entries(json);
var cities = d3.set(); // this keeps a record of the cities mentioned so we don't need to hard-code them later on
// run through the dates and make new objects of city=entry pairs (and the date=whatever)
// all stored in a new array (formattedData) which we can feed to the chart json argument
var formattedData = nestedData.map (function (entry) {
var values = entry.values;
var obj = {};
values.forEach (function (value) {
obj[value.city] = value.event;
cities.add(value.city);
})
obj.date = entry.key;
return obj;
});
var chart = c3.generate({
data: {json: formattedData,
keys: {
x: 'date', // it's possible to specify 'x' when category axis
value: cities.values(),
}
},
...
See the edited plunkr at http://plnkr.co/edit/5xa4z27HbHQbjcfpRLpQ?p=preview

extJS: reading a nested JSON

I have a pretty nested JSON coming from a ldap_search() call. I would like to use this information to populate an ExtJS ComboBox, but I am facing some troubles with the reader. Apparently, I am not able to read the information that I need in the ComboBox, that is the mail address of the people, the uid and the cn
I think the whole problem lies in the store. I was trying the following code:
var store= new Ext.data.JsonStore({
url:'search.php',
root: '',
totalProperty: 'count',
fields: [
{name:'cn', type: 'string', mapping:'cn.0'},
{name:'mail', type: 'string', mapping:'mail.0'},
{name:'uid', type: 'string', mapping:'uid.0'}
]
});
but FireBug told me missing ; before statement return obj.cn.0 in ext-all.js (line 7). I tried with another, easier JSON array and it works, that is why I really think the problem lies in this part of code, especially in the mapping.
an example of JSON returned by search.php is:
{
"count": 2,
"0": {
"mail": {
"count": 1,
"0": "Mail address not registered."
},
"0": "mail",
"uid": {
"count": 1,
"0": "name0.surname0#domain.com"
},
"1": "uid",
"cn": {
"count": 1,
"0": "Surname0 Name0"
},
"2": "cn",
"count": 3,
"dn": "cn=Surname0 Name0,ou=personal,dc=domain,dc=com"
},
"1": {
"mail": {
"count": 1,
"0": "name1.surname1#domain.com"
},
"0": "mail",
"uid": {
"count": 1,
"0": "name1.surname1"
},
"1": "uid",
"cn": {
"count": 1,
"0": "Surname 1 Name 1"
},
"2": "cn",
"count": 3,
"dn": "cn=Surname1 Name1,ou=personal,dc=domain,dc=com"
}
}
Thanks for your time.
Yep, that JSON structure is not going to work straight away with standard ExtJS JSONReader. Take a look at this example taken from the ExtJS API documentation on how the JSON should look like.
{
results: 2000, // Reader's configured totalProperty
rows: [ // Reader's configured root
// record data objects:
{ id: 1, firstname: 'Bill', occupation: 'Gardener' },
{ id: 2, firstname: 'Ben' , occupation: 'Horticulturalist' },
...
]
}
Also, the root config option is required, you cannot leave it empty. In the above example your root would be "rows".
You are probably going to need to parse that JSON of yours into a simpler format at first, before feeding it to the JSONReader.
I was looking to do the same thing, but have one of the nested items be a field in my chart. This post kept coming up, so I thought it might be helpful to see what I did to solve the chart issue. The key to solving it is knowing that the label config exists: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.chart.Label. Using that you can override the default render of what you pass in. In this example the field is "key" (Not shown here, but my model is using the default type for 'key' (ie., not string)). The key object gets passed to renderer. Using function(t), I can now access that object like javascript and pass back the name under the object.
json
key : {
wholePath : "c:/.../fileName.txt",
fileName : "fileName.txt",
}
code:
axes: [
{
title: 'Values',
type: 'Numeric',
position: 'left',
fields: ['value'],
minimum: 0,
maximum: 100,
minorTickSteps: 1
},
{
title: 'File Name',
type: 'Category',
position: 'bottom',
fields: ['key'],
label: {
renderer: function(t) {
var fileName = t.name;
return fileName;
}
}
}