Plotly JS charts with dual category axis - bar-chart

I am trying to add second category to x axis so that it looks like a grouped by category.
The sample provided by plotly doesn't show this option. Has anyone tried the dual category
var trace1 = {
x: ['A12', 'BC2', 109, '12F', 215, 304],
y: [1, 6, 3, 5, 1, 4],
mode: 'markers',
type: 'bar',
name: 'Team A',
text: ['Apples', 'Pears', 'Peaches', 'Bananas', 'Pineapples', Cherries'],
};
var data = [ trace1 ];
var layout = {
xaxis: {
type: 'category',
title: 'Product Code',
},
yaxis: {
range: [0, 7],
title: 'Number of Items in Stock'
},
title:'Inventory'
};
Plotly.plot('myDiv', data, layout);
https://plot.ly/javascript/axes/
Desired result (Sample Image) -

Related

Quey Post and comments and User with MySql and knex [duplicate]

I have a heavy array like this:
[
{Id: 1, Name: 'Red', optionName: 'Color'},
{Id: 2, Name: 'Yellow', optionName: 'Color'},
{Id: 3, Name: 'Blue', optionName: 'Color'},
{Id: 4, Name: 'Green', optionName: 'Color'},
{Id: 7, Name: 'Black', optionName: 'Color'},
{Id: 8, Name: 'S', optionName: 'Size'},
{Id: 11, Name: 'M', optionName: 'Size'},
{Id: 12, Name: 'L', optionName: 'Size'},
{Id: 13, Name: 'XL', optionName: 'Size'},
{Id: 14, Name: 'XXL', optionName: 'Size'}
]
What I need to do is to group them by optionName and have two row in the main array like this:
[
{
Name: 'Color',
Data:[{Id: 1, Name: 'Red'},
{Id: 2, Name: 'Yellow'},
{Id: 3, Name: 'Blue'},
{Id: 4, Name: 'Green'},
{Id: 7, Name: 'Black'}]
}, {
Name: 'Size',
Data:[{Id: 8, Name: 'S'},
{Id: 11, Name: 'M'},
{Id: 12, Name: 'L'},
{Id: 13, Name: 'XL'},
{Id: 14, Name: 'XXL'}]
}
]
How to do it in javascript?
This is a snippet I wrote for these kind of situations. You can add this functionality to all of your arrays:
Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
var map = {};
this.forEach(function (e) {
var k = key(e);
map[k] = map[k] || [];
map[k].push(e);
});
return Object.keys(map).map(function (k) {
return {key: k, data: map[k]};
});
}
});
You can use it like this. You can just pass a function which defines how you want to group your data.
var newArray = arr.group(function (item) {
return item.optionName;
});
Working Fiddle
If you need, you can replace {key: k, data: map[k]} with {Name: k, Data: map[k]}.
This is also more compact ES6 version of the code above:
Object.defineProperty(Array.prototype, 'group', {
enumerable: false,
value: function (key) {
let map = {};
this.map(e => ({k: key(e), d: e})).forEach(e => {
map[e.k] = map[e.k] || [];
map[e.k].push(e.d);
});
return Object.keys(map).map(k => ({key: k, data: map[k]}));
}
});
Use it like this:
let newArray = arr.group(item => item.optionName))
An ES6 solution using Map object:
function groupBy(arr, key) {
return arr.reduce(
(sum, item) => {
const groupByVal = item[key];
groupedItems = sum.get(groupByVal) || [];
groupedItems.push(item);
return sum.set(groupByVal, groupedItems);
},
new Map()
);
}
var Data = [
{ Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
document.getElementById("showArray").innerHTML =JSON.stringify([...groupBy(Data, 'optionName')], null, 4);
<pre id="showArray"></pre>
You can use reduce to get the resultset you need:
var result = list.reduce(function(memo, item) {
if (item.optionName === 'Color') {
memo[0].Data.push(
Id: item.Id,
Name: item.Name
});
}
if (item.optionName === 'Size') {
memo[1].Data.push({
Id: item.Id,
Name: item.Name
});
}
return memo;
}, [{ Name: 'Color', Data: [] }, { Name: 'Size', Data: [] }]);
variable list is your first list.
Hope this helps.
This is a snippet I wrote for kind of my situation in my application functionality of all arrays. This snippet code is use in node js application. All the above is is given solution but I was finding some problem in server side in node js.
This snippet is user full me....
var Data= [
{ Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
function groupBy(arr, key) {
var newArr = [],
types = {},
newItem, i, j, cur;
for (i = 0, j = arr.length; i < j; i++) {
cur = arr[i];
if (!(cur[key] in types)) {
types[cur[key]] = { type: cur[key], data: [] };
newArr.push(types[cur[key]]);
}
types[cur[key]].data.push(cur);
}
return newArr;
}
I use it like this. I just pass a function which defines how you want to group our data.
filterData= groupBy(Data,'optionName');
Result of this snippet of code output.....
[
{"type":"Color","data":[{"Id":1,"Name":"Red","optionName":"Color"},
{"Id":2,"Name":"Yellow","optionName":"Color"},
{"Id":3,"Name":"Blue","optionName":"Color"},
{"Id":4,"Name":"Green","optionName":"Color"},
{"Id":7,"Name":"Black","optionName":"Color"}]},
{"type":"Size","data":[{"Id":8,"Name":"S","optionName":"Size"},
{"Id":11,"Name":"M","optionName":"Size"},
{"Id":12,"Name":"L","optionName":"Size"},
{"Id":13,"Name":"XL","optionName":"Size"},
{"Id":14,"Name":"XXL","optionName":"Size"}]}
]
Show on fiddle
var originalList = [ { Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
var output = [{ Name: "Color", Data: [] },{ Name: "Size", Data: [] }] ;
originalList.map(function(entry){
if ( entry.optionName === "Color") output[0].Data.push({ Id: entry.Id, Name: entry.Name });
if ( entry.optionName === "Size") output[1].Data.push({ Id: entry.Id, Name: entry.Name });
});
'use strict'
let l = [ { Id: 1, Name: 'Red', optionName: 'Color' },
{ Id: 2, Name: 'Yellow', optionName: 'Color' },
{ Id: 3, Name: 'Blue', optionName: 'Color' },
{ Id: 4, Name: 'Green', optionName: 'Color' },
{ Id: 7, Name: 'Black', optionName: 'Color' },
{ Id: 8, Name: 'S', optionName: 'Size' },
{ Id: 11, Name: 'M', optionName: 'Size' },
{ Id: 12, Name: 'L', optionName: 'Size' },
{ Id: 13, Name: 'XL', optionName: 'Size' },
{ Id: 14, Name: 'XXL', optionName: 'Size' } ];
let color = [];
let size = [];
l.forEach(element => {
if (element['optionName'] === 'Color') {
color.push({'Id': element.Id, 'Name': element.Name});
} else {
size.push({'Id': element.Id, 'Name': element.Name});
}
});
console.log(color);
console.log(size);
You can try this method.
All of the answers lead to the same result, so it all comes down to a personal preference (or company guidelines) on how to tackle this.
// ES5 (traditional javascript) version
function groupByOptionName(list, optionName) {
return list
// filter out any item whose optionName does not match the desired name
.filter(function(item) {
return item.optionName === optionName;
})
// map the item into the desired shape
// (appears to be everything except optionName itself
.map(function(item) {
return {
Id: item.Id,
Name: item.Name
};
})
}
// ES2015/ES6 version
function groupByOptionName(list, optionName) {
return list
// filter out any item whose optionName does not match the desired name
.filter(item => item.optionName === optionName)
// map the item into the desired shape
// (appears to be everything except optionName itself
.map(item => {
Id: item.Id,
Name: item.Name
});
}
This function would let you program the desired result as follows:
var output = [
{Name: 'Color', Data: groupByOptionName(list, 'Color')},
{Name: 'Size', Data: groupByOptionName(list, 'Size')},
];
// the ES2015/ES6 version of this code would replace var with let
While the code itself differs, it is much like the other answers, with only a variation on the steps needed.
One could also opt to leave out any hardcoded option names (Color and Size) by extracting those aswel, this would allow for a more dynamic input, but could also introduce more processing that actually needed.
// ES5 (traditional javascript) version
function getOptionNames(list) {
return list
// map the array into a list of optionNames
.map(function(item) {
return item.optionName;
})
// remove duplicates
.filter(function(item, index, all) {
return all.indexOf(item) === index;
});
}
// ES2015/ES6 version (does exactly the same as the one above)
function getOptionNames(list) {
return list
// map the array into a list of optionNames
.map(item => item.optionName)
// remove duplicates
.filter((item, index, all) => all.indexOf(item) === index);
}
Which allows the result to be fully based on the input data:
// ES5 (traditional javascript) version
var output = getOptionNames(list)
// map the names into the desired structure
.map(function(buffer, name) {
return {
Name: name,
Data: groupByOptionName(list, name)
};
});
// ES2015/ES6 version (does exactly the same as the one above)
var output = getOptionNames(list)
// map the names into the desired structure
.map((buffer, name) => {
Name: name,
Data: groupByOptionName(list, name)
});
By writing all of the data-mangling steps in short consice steps you'd do yourself (especially your future self) a favor if this code ever needs to be adjusted.
If the data set really is heavy (in terms of a lot of data), you must also make sure to keep the number of copies you keep in memory limited. For example, if you never need the original dataset, make sure it can be garbage collected (by not having a variable containing it outside the scope where you receive the data)
Usage:
groupValues([
{ color: 'blue', value: 100 },
{ color: 'blue', value: 75 },
{ color: 'yellow', value: 50 },
{ color: 'yellow', value: 25 }
], 'color')
Result:
[
[{ color: 'blue', value: 100 }, { color: 'blue', value: 75 }],
[{ color: 'yellow', value: 50 }, { color: 'yellow', value: 25 }]
]
Function:
const groupValues = function(arr, key) {
const mapped = {}
arr.forEach(el => {
const actualKey = el[key]
if(!mapped.hasOwnProperty(actualKey)) mapped[actualKey] = []
mapped[actualKey].push(el)
})
return Object.keys(mapped).map(el => mapped[el])
}

Data aggregation in c3js

Is there an option to aggregate the data in C3 charts? When the JSON contains multiple data elements with the same category, data is plotted as multiple points in the charts, where as it should be aggregated and shown as a single point in the chart.
Attached are the C3 charts and expected chart format.
In the example: "name 1" show a single point at 300 as upload, where as ion C3 it show one point at 200 and the other at 100 for the same.
Code Used:
var chart = c3.generate({
bindto:'#png-container',
data: {
json: [
{name: 'name1', upload: 200, download: 200, total: 400},
{name: 'name1', upload: 100, download: 300, total: 400},
{name: 'name2', upload: 300, download: 200, total: 500},
{name: 'name3', upload: 400, download: 100, total: 500},
],
keys: {
x: 'name', // it's possible to specify 'x' when category axis
value: ['upload', 'download'],
},
groups: [
['name']
]
},
axis: {
x: {
type: 'category'
}
}
});
Output of the above code:
Expected Output:
Not built into c3 as far as i'm aware. You can use d3's nest operator to aggregate the json data before passing it to c3 though.
var json = [
{name: 'name1', upload: 200, download: 200, total: 400},
{name: 'name1', upload: 100, download: 300, total: 400},
{name: 'name2', upload: 300, download: 200, total: 500},
{name: 'name3', upload: 400, download: 100, total: 500},
];
var agg = function (json, nestField) {
var nested_data = d3.nest()
.key(function(d) { return d[nestField]; })
.rollup(function(leaves) {
// Work out the fields we're not nesting by
var keys = d3.merge (leaves.map (function(leaf) { return d3.keys(leaf); }));
var keySet = d3.set(keys);
keySet.remove (nestField);
var dataFields = keySet.values();
// total these fields up
// console.log(leaves, dataFields); // just for testing
var obj = {};
dataFields.forEach (function (dfield) {
obj[dfield] = d3.sum(leaves, function(d) {return d[dfield];});
});
return obj;
})
.entries(json);
// return to original json format
var final_data = nested_data.map (function(nestd) {
nestd.values[nestField] = nestd.key;
return nestd.values;
});
return final_data;
};
var chart = c3.generate({
bindto:'#png-container',
data: {
json: agg(json, "name"),
keys: {
x: 'name', // it's possible to specify 'x' when category axis
value: ['upload', 'download'],
},
groups: [
['name']
]
},
axis: {
x: {
type: 'category'
}
}
});
https://jsfiddle.net/8uofn7pL/2/
whoops, linked to the wrong fiddle there

Highcharts stacked bar data from CSV

I'm trying to implement a stacked bar chart with data coming from a CSV.
I need to update series: with the data from the CSV file which contains, for example "John,10,5,3,4,1".
Help please!
$(function () {
$('#container').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Stacked bar chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
}
},
legend: {
reversed: true
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
});
});
UPDT
I finally got it working, but still there's a problem. The bars are inverted and I need them to be exactly in the same order as in the CSV file.
Here's my parser:
$.get('chart.csv', function(data) {
var lines=data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo == 0) {
series.name = item;
} else {
series.data.push(parseFloat(item));
}
});
options.series.push(series);
});
var chart = new Highcharts.Chart(options);
The contents of the CSV file:
Disconnection,30,30
Site Care,12,12
Documentation,35,35
Lining,22,22
Connection,70,52
I need the stacked bars in the same order as in the legend:
http://i.stack.imgur.com/6EkHg.png
You could try to custom setting the series indices before you render the chart to fix the inversion of the bars.
Something like this might do the trick:
for (var i = 0; i < options.series.length; i++) {
options.series[i].index = options.series.length - 1 - i;
options.series[i].legendIndex = i;
}

Generate a line chart over column chart using highcharts

I am new to Highcharts and i like it.I am trying to create a line graph over column graph.but i make only column graph [link]http://jsfiddle.net/sunman/S9ChJ/
But here is my problem is i could not create a line graph upon column chart .so please tell me how it is possible.i have already searched for this and in that code i want change for line graph. so please help me
Here this code i am trying .but not shows me any graph
$(function () {
var chart;
$(document).ready(function() {
$('#container').highcharts({
chart: {
zoomType: 'xy'
},
title: {
text: 'Project faclityv Rating'
},
subtitle: {
text: 'testing'
},
xAxis: [{
categories: [A,B,C,D,E]
}],
yAxis: [{ // Primary yAxis
labels: {
// format: '{value} Rs.',
style: {
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Bsp Cost',
style: {
color: Highcharts.getOptions().colors[1]
}
}
}, { // Secondary yAxis
title: {
text: 'facility rating',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
//format: '{value} out of 100',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 120,
verticalAlign: 'top',
y: 100,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
series: [{
name: 'Facility Rating',
type: 'column',
yAxis: 1,
data: [10,15,20,25,30],
tooltip: {
valueSuffix: ' out of 100'
}
}, {
name: 'Bsp Cost',
type: 'spline',
data: [5,10,15,20,25],
tooltip: {
valueSuffix: 'Rs.'
}
}]
});
$.getJSON("data.php", function(json) {
options.xAxis.categories = json[0]['data'];
options.series[0].data = json[1]['data'];
options.series[1].data = json[1]['data'];
chart = new Highcharts.Chart(options);
});
});
});
here is data.php
$query = mysql_query("SELECT projects_detail.Project_name,facility_rating.facilities_total,cost.bsp
FROM projects_detail LEFT OUTER JOIN facility_rating
ON projects_detail.project_id= facility_rating.project_id
LEFT OUTER JOIN cost ON facility_rating.project_id = cost.project_id");
$category = array();
$category['name'] = 'Project';
$series1 = array();
$series1['name'] = 'Facilities Rating';
$series2 = array();
$series2['name'] = 'BSP values';
while($r = mysql_fetch_array($query)) {
$category['data'][] = $r['Project_name'];
$series1['data'][] = $r['facilities_total'];
$series2['data'][] = $r['bsp'];
}
$result = array();
array_push($result,$category);
array_push($result,$series1);
array_push($result,$series2);
print json_encode($result, JSON_NUMERIC_CHECK);
You need to add extra line serie.
json = [{
data: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
}, {
data: [1, 2, 3, 1, 2, 3, 4, 1, 3, 3, 3, 3, 3, 3, 5, 1]
}];
options.xAxis.categories = json[0]['data'];
options.series[0].data = json[1]['data'];
options.series[1].data = json[1]['data'];
http://jsfiddle.net/S9ChJ/1/

json to load values into extjs checkboxgroup grid editor

I need to set up a CheckboxGroup checkboxes with values loaded with json from some url.
What is a correct format of JSON?
Many thanks for help!
Update: I'll clarify my problem.
I'm using EditorGridPanel. Rows are Periods. There are columns Start_at, Finish_at, Region. First and second are date and everything ok with them. Problem with Region which actually is a CheckboxGroup with a checkbox for each week day - Monday, Tuesday, etc. So:
First I'm loading data from server into store
function setupDataSource() {
row = Ext.data.Record.create([
{ name: 'start_at', type: 'string' },
{ name: 'finish_at', type: 'string' },
{ name: 'region', type: 'string' }
]);
store = new Ext.data.Store({
url: '/country/195/periods',
reader: new Ext.data.JsonReader(
{
root: 'rows',
id: 'id'
},
row
)
});
store.load();
}
URL url: '/country/195/periods' returns JSON:
{"rows": [{"region": {"cbvert_1": 1, "cbvert_2": 0, "cbvert_3": 1, "cbvert_4": 0, "cbvert_5": 1, "cbvert_6": 0, "cbvert_7": 1}, "start_at": "2010-10-17", "id": 1, "finish_at": "2010-10-28"}]}
Then I'm building a grid:
function buildGrid() {
sm = new Ext.grid.RowSelectionModel();
cm = new Ext.grid.ColumnModel([
// ... Start at and Finish at columns definition here ...
{ header: 'Region',
dataIndex: 'region',
width: 150,
editor: new Ext.form.CheckboxGroup({
xtype: 'checkboxgroup',
columns: 7,
vertical: true,
items: [
{boxLabel: 'M', name: 'cbvert_1', inputValue: 1},
{boxLabel: 'T', name: 'cbvert_2', inputValue: 1},
{boxLabel: 'W', name: 'cbvert_3', inputValue: 1},
{boxLabel: 'T', name: 'cbvert_4', inputValue: 1},
{boxLabel: 'F', name: 'cbvert_5', inputValue: 1},
{boxLabel: 'S', name: 'cbvert_6', inputValue: 1},
{boxLabel: 'S', name: 'cbvert_7', inputValue: 1},
]
}),
renderer: function(value) {}
}]);
// ...
}
So, when I'm clicking on a grid cell I need to get checkboxes preselected with values previously stored in database. Now all checkboxes are stay blank but should be 1010101 as its in JSON.
Please point me to errors or maybe a some kind of a solution. Any help will be greatly appreciated.
Many thanks!
Check this out:
http://www.sencha.com/forum/showthread.php?47243-Load-data-in-checkboxgroup
Updated:
Remove the type declaration of the region field. You do not need a string but an object (from JSON). It works just fine that way :)