Ok, I've been looking for something similar to what I'm experiencing online but I can't so I decided to ask around here for some advise to solve my issue.
I'm using Angular Google chart and trying to create a column chart to display historical values for portfolio totals.
Code to create chart
$scope.createPortfolioBalanceChart = function(){
var data = JSON.parse($scope.portfolioChartData.rows.toJSON());
console.log(JSON.stringify($scope.portfolioChartData).replace(/\\/g,''));
var minValue = _.reduce(data.rows, function(memo, bal){
var value = bal.c[1].v;
return (value !== null && value < memo) ? value : memo;
}, Number.MAX_SAFE_INTEGER);
var maxValue = _.reduce(data.rows, function(memo, bal){
var value = bal.c[1].v;
return value > memo ? value : memo;
}, Number.MIN_SAFE_INTEGER);
var rangeBleed = (maxValue - minValue) * PortfolioBalanceChartConfig.rangeBleedPadding;
var chart = {};
chart.type = 'ColumnChart';
chart.data = data;
chart.options = {
'height': 300,
'fill': 20,
isStacked: false,
'vAxis':{
'baselineColor': 'none',
'gridlineColor': 'none',
'format': '$#,###',
'position': 'right',
'viewWindow' : {
'min': rangeBleed > 0 ? minValue - rangeBleed : 0, // if the range is 0 then start the graph from 0
'max': maxValue + rangeBleed
}
},
'displayExactValues': true,
'tooltip' : {
'trigger': true
},
'legend': {
'position': 'none'
},
'bar': {
'groupWidth': 30
},
'colors': ['#33b4e6', '#0675c2'],
};
chart.formatters = {
number : [{
columnNum: 1,
pattern: '$ #,##0.00'
},
{
columnNum: 2,
pattern: '$ #,##0.00'
}]
};
$scope.portfolioBalanceChart = chart;
};
Note:
minValue and maxValue above was calculated to add padding to the chart data.
$scope.portfolioChartData
{
"rows": {
"cols": [
{
"label": "Period",
"type": "string"
},
{
"label": "Balance",
"type": "number"
},
{
"role": "style",
"type": "string",
"p": {
"role": "style"
}
}
],
"rows": [
{
"c": [
{
"v": "Mar 2015"
},
{
"v": 68484.43
},
{
"v": ""
}
]
},
{
"c": [
{
"v": "Apr 2015"
},
{
"v": 68484.43
},
{
"v": ""
}
]
},
{
"c": [
{
"v": "May 2015"
},
{
"v": 68484.43
},
{
"v": ""
}
]
},
{
"c": [
{
"v": "Jun 2015"
},
{
"v": 68484.43
},
{
"v": ""
}
]
},
{
"c": [
{
"v": "Jul 2015"
},
{
"v": 68484.43
},
{
"v": ""
}
]
},
{
"c": [
{
"v": "Today"
},
{
"v": 600000
},
{
"v": ""
}
]
}
]
},
"cols": [
{
"label": "axis",
"type": "string"
},
{
"label": "Portfolio",
"type": "number"
}
]
}
stackoverflow is preventing me to post image so here's a sample image of the chart constructed above:
http://postimg.org/image/gtnq81au3/
OK, I've solved the issue at last. There seems to be some property hiding in the google chart docs that enables you to set what should be the baseline. This is different from what the viewWindow.min is. I added it below the viewWindow property.
$scope.createPortfolioBalanceChart = function(){
var data = JSON.parse($scope.portfolioChartData.rows.toJSON());
var minValue = _.reduce(data.rows, function(memo, bal){
var value = bal.c[1].v;
return (value !== null && value < memo) ? value : memo;
}, Number.MAX_SAFE_INTEGER);
var maxValue = _.reduce(data.rows, function(memo, bal){
var value = bal.c[1].v;
return value > memo ? value : memo;
}, Number.MIN_SAFE_INTEGER);
var rangeBleed = (maxValue - minValue) * PortfolioBalanceChartConfig.rangeBleedPadding;
var chart = {};
chart.type = 'ColumnChart';
chart.data = data;
chart.options = {
'height': 300,
'fill': 20,
isStacked: false,
'vAxis':{
'baselineColor': 'none',
'gridlineColor': 'none',
'format': '$#,###',
'position': 'right',
'viewWindow' : {
'min': rangeBleed > 0 ? minValue - rangeBleed : 0, // if the range is 0 then start the graph from 0
'max': maxValue + rangeBleed
},
'baseline': rangeBleed > 0 ? minValue - rangeBleed : 0 // set to be the same as min to prevent bar overlapping label below it
},
'displayExactValues': true,
'tooltip' : {
'trigger': true
},
'legend': {
'position': 'none'
},
'bar': {
'groupWidth': 30
},
'colors': ['#33b4e6', '#0675c2'],
};
chart.formatters = {
number : [{
columnNum: 1,
pattern: '$ #,##0.00'
},
{
columnNum: 2,
pattern: '$ #,##0.00'
}]
};
$scope.portfolioBalanceChart = chart;
};
Related
here is my associative array data for chart.js
i try to add line chart inside bar chart.
but i'm confuse how to add new chart inside it.
since my datasets is Array
const tmp_orders = [
{
"type": "import",
"year": 2020,
"total": 1
},
{
"type": "import",
"year": 2019,
"total": 0
},
{
"type": "import",
"year": 2018,
"total": 0
},
{
"type": "export",
"year": 2020,
"total": 0
},
{
"type": "export",
"year": 2019,
"total": 0
},
{
"type": "export",
"year": 2018,
"total": 0
}
],
const res = [];
const result = tmp_orders[0].map(function(obj) {
var tmp = []
Object.entries(obj).map(function([key, value]) {
tmp[key] = value
})
res.push(tmp)
});
console.log(res)
// get order type and sort
const types =[...new Set(res.map(v => v['type']))].sort();
// get order year and sort
const years =[...new Set(res.map(v =>v['year']))].sort();
// set order color and sort
const colors = ['#ff0000', '#6383ff'];
// data for target order chart
const target_data = types.map(type => ({
label: type,
data: years.map(year => {
const value = res.find(v => v['type'] == type && v['year'] == year );
return value['total'];
}),
backgroundColor: function(){
if(type === 'import'){
return '#ff0000'
}else if(type === 'export'){
return '#6383ff'
}
}
}))
const targetOrderCtx = $('#chart_target_order'),
optionOrder = {
maintainAspectRatio: false,
responsive: true,
title: {
display: true,
text: 'Target Order',
fontSize: 18,
fontColor: '#6383ff'
},
legend: {
display: true,
position: 'bottom'
},
animation: {
animateScale: true,
animateRotate: true
}
}
// create Target Order Chart
var chart_target_order = new Chart(targetOrderCtx, {
type: 'bar',
data: {
labels: years,
datasets: target_data
},
options: optionOrder
});
if you look inside my datasets
you will find out that's Array.
mostly i find some solution like add line chart insie datasets, but it seems impossible for me.
EDIT 1
here is the result that i want.
I am working on angularjs googlecharts. when user click on legend, corresponding data on the chart is hidden. Issue is with the tooltip. When user click on legend Laptop(blue color) and mouseover on the any of the bar in the chart,the data on the tooltip which shows Laptop should be hidden, but the tooltip is showing information of Laptop also. The same is working when user click on Desktop Legend and mouseover on the bar, the data on the tooltip which shows Desktop is hidden.
Could not able to trace the issue, any suggestion on how to hide the tooltip information displaying Laptop information when user selects the Legend Laptop to hide laptop information.
Please find the demo here
js code:
angular.module('myApp', ['googlechart'])
.controller('myController', function($scope) {
var colorIndex = 0,
chart1 = {};
chart1.type = "ColumnChart";
chart1.displayed = false;
chart1.data = {
"cols": [{
id: "month",
label: "Month",
type: "string"
}, {
id: "laptop-id",
label: "Laptop",
type: "number",
colorIndex: colorIndex++
}, {
role: "tooltip",
type: "string",
p: {
'html': true
}
}, {
id: "desktop-id",
label: "Desktop",
type: "number",
colorIndex: colorIndex++
}],
"rows": [ {
c: [{
v: "Jan"
}, {
v: 13
},{
v: "laptop tooltip bar1"
}, {
v: 1,
f: "1 unit (Out of stock this month)"
}]
} ,{
c: [{
v: "February"
}, {
v: 13
},{
v: "laptop tooltip bar2"
}, {
v: 1,
f: "1 unit (Out of stock this month)"
}]
}, {
c: [{
v: "March"
}, {
v: 24
},{
v: "laptop tooltip bar3"
}, {
v: 5
}]
}]
};
chart1.options = {
"title": "Sales per month",
"colors": ['#0000FF', '#009900'],
"defaultColors": ['#0000FF', '#009900'],
focusTarget: 'category',
"isStacked": "true",
"fill": 20,
"displayExactValues": true,
tooltip: {textStyle: {fontName: '"Arial"', bold: "true", fontSize: "14"}},
"vAxis": {
"title": "Sales unit",
"gridlines": {
"count": 10
}
},
"hAxis": {
"title": "Date"
}
};
chart1.view = {
columns: [0, 1, 2,3]
};
$scope.myChart = chart1;
var hidden = [];
$scope.reset = function() {
for (var i = 0; i < hidden.length; i++) {
var hiddenCol = hidden[i];
$scope.myChart.view.columns[hiddenCol] = hiddenCol;
$scope.myChart.options.colors[hiddenCol - 1] = $scope.myChart.options.defaultColors[hiddenCol - 1];
}
hidden = [];
};
$scope.seriesSelected = function(selectedItem) {
if (selectedItem.row === null) {
var col = selectedItem.column,
colIndex = hidden.indexOf(col),
colorIndex = chart1.data.cols[col].colorIndex;
if (hidden.length === ($scope.myChart.view.columns.length - 3) && colIndex == -1) {
window.alert("One seies of data should be available all time");
}
else{
if(colIndex == -1){
hidden.push(col);
}
else{
hidden.splice(colIndex, 1);
}
if ($scope.myChart.view.columns[col] == col) {
$scope.myChart.view.columns[col] = $scope.myChart.data.cols[col];
$scope.myChart.options.colors[colorIndex] = '#CCCCCC';
}
else {
$scope.myChart.view.columns[col] = col;
$scope.myChart.options.colors[colorIndex] = $scope.myChart.options.defaultColors[colorIndex];
}
}
}
};
});
This is my JSON data:
{
"EF": [
{
"OP": "op1",
"pound": 2000,
"Date": "2012-1-13T00:00:00.000Z"
},
{
"OP": "op1",
"pound": 1800,
"Date": "2014-12-6T00:00:00.000Z"
},
{
"OP": "op2",
"pound": 300,
"Date": "2013-6-1T00:00:00.000Z"
}
]
}
I want to Count each parameter value and Sort them from largest to smallest to have a table like this:
OP : op1 (2), OP2 (1) Pound: 2000, 1800, 300 Date:
2014-12-6T00:00:00.000Z, 2013-6-1T00:00:00.000Z,
2012-1-13T00:00:00.000Z
I tried to use d3.nest() but I didnot have much success with it. Any thoughts?
//JSON from db?
var json = {
"EF": [{
"OP": "op1",
"pound": 2000,
"Date": "2012-1-13T00:00:00.000Z"
}, {
"OP": "op1",
"pound": 1800,
"Date": "2014-12-6T00:00:00.000Z"
}, {
"OP": "op2",
"pound": 300,
"Date": "2013-6-1T00:00:00.000Z"
}]
};
//Sort based on pound
json.EF.sort(function(a, b) {
if (a.pound < b.pound) return 1;
if (a.pound > b.pound) return -1;
return 0;
});
var hash = {}; //Keep track of counts
//Count the values
for (var i in json.EF) {
var obj = json.EF[i];
if (hash[obj.OP]) {
hash[obj.OP] += 1;
} else {
hash[obj.OP] = 1;
}
}
//Sorted
console.log("SORTED:", json);
console.log("COUNTS:", hash);
//Now, when you loop through the json to display the values, just check the counts and display them
I have this js object
{
"2015": {
"11": {
"10": {
"Family & Friends\nGames": {
"c": 2
},
"Collectible\nGames": {
"c": 1
},
"Logic Games\n": {
"c": 1
},
"Kids Games\n": {
"c": 1
}
},
},
"Family & Friends\nGames": {
"c": 9
},
"Collectible\nGames": {
"c": 2
},
"Logic Games\n": {
"c": 4
},
"Kids Games\n": {
"c": 6
},
"Classic Games\n": {
"c": 3
},
"Preschool\nGames": {
"c": 5
}
},
"meta": {
"id": [
"[CLY]2",
"[CLY]7",
"[CLY]6",
"[CLY]1",
"[CLY]4",
"[CLY]3"
],
"segments": [
"id",
"title"
],
"title": [
"Family & Friends\nGames",
"Collectible\nGames",
"Logic Games\n",
"Kids Games\n",
"Classic Games\n",
"Preschool\nGames"
]
}
}
Im trying to subtract the same objects right above "meta" that match the keys under "title". I accomplished this using ruby with the following code
results = JSON.parse(resp.body)
data = results["2015"]
title = results["meta"]["title"]
alg = data.slice(*title).to_a
info = alg.sort_by { |k,v| v["c"] }
So I tried to convert the object into an array and from there slice all the content that matches the other array name title and finally sort the information based on their "c" value.
none of this seems to work for me so I have tried to get the data from the object using [] and the name of the key inside, but since each name under the array "title" has \n makes me has to add an extra \ to access it. I want this to be dynamic and not have to modify it every time I have different names under "title"
I need something like this https://jsfiddle.net/7chntms2/6/
Thank you for the help
Is this what you are trying to achieve?
var obj = {
"2015": {
"11": {
"10": {
"Family & Friends\nGames": {
"c": 2
},
"Collectible\nGames": {
"c": 1
},
"Logic Games\n": {
"c": 1
},
"Kids Games\n": {
"c": 1
}
},
},
"Family & Friends\nGames": {
"c": 9
},
"Collectible\nGames": {
"c": 2
},
"Logic Games\n": {
"c": 4
},
"Kids Games\n": {
"c": 6
},
"Classic Games\n": {
"c": 3
},
"Preschool\nGames": {
"c": 5
}
},
"meta": {
"id": [
"[CLY]2",
"[CLY]7",
"[CLY]6",
"[CLY]1",
"[CLY]4",
"[CLY]3"
],
"segments": [
"id",
"title"
],
"title": [
"Family & Friends\nGames",
"Collectible\nGames",
"Logic Games\n",
"Kids Games\n",
"Classic Games\n",
"Preschool\nGames"
]
}
}
var keys = obj["meta"]["title"];
var newObj = [];
for (var i = 0; i < keys.length; i++) {
newObj.push({
name: keys[i],
content: obj["2015"][keys[i]]
});
}
newObj.sort(function(a, b) {
if (a.content.c < b.content.c) return -1;
if (a.content.c > b.content.c) return 1;
return 0;
});
console.log(newObj);
Example fiddle: https://jsfiddle.net/wv2kbcyn/
Basically, if the name of that JSON object is data:
var meta = data["meta"];
var titles = meta["title"];
var logicgames = titles[2];
You can also loop the titles:
for(var key in titles)
{
var title = titles[key];
console.log(title); // "Family & Friends\nGames", ...
}
So titles is an array now.
I have a data coming from a VM that has several block devices. Every block device is represented with a a line charts that where created using c3.js that read Bytes_Read and Bytes_Written in the dataset and chart it in realtime. But I am struggling with the issue when there are new block devices introduced in dataset it does not create a new chart. What would be the best way to achieve this using JavaScript.
Sample of my dataset
{
"devices": [
{
"Name": "bdev0",
"output": {
"IO_Operations": 0,
"Bytes_Read": 0,
"Bytes_Written": 0
}
},
{
"Name": "bdev0",
"output": {
"IO_Operations": 1,
"Bytes_Read": 2,
"Bytes_Written": 3
}
},
{
"Name": "bdev0",
"output": {
"IO_Operations": 5,
"Bytes_Read": 7,
"Bytes_Written": 8
}
},
{
"Name": "bdev1",
"output": {
"IO_Operations": 10,
"Bytes_Read": 20,
"Bytes_Written": 30
}
}
]
}
Updated dataset with a new device
{
"devices": [
{
"Name": "bdev0",
"output": {
"IO_Operations": 0,
"Bytes_Read": 0,
"Bytes_Written": 0
}
},
{
"Name": "bdev0",
"output": {
"IO_Operations": 1,
"Bytes_Read": 2,
"Bytes_Written": 3
}
},
{
"Name": "bdev0",
"output": {
"IO_Operations": 5,
"Bytes_Read": 7,
"Bytes_Written": 8
}
},
{
"Name": "bdev1",
"output": {
"IO_Operations": 10,
"Bytes_Read": 20,
"Bytes_Written": 30
},
{
"Name": "bdev2",
"output": {
"IO_Operations": 40,
"Bytes_Read": 50,
"Bytes_Written": 90
}
}
]
}
chart code
eon.chart({
pubnub : pubnub,
history : false,
channel : 'orbit5_volume',
flow : true,
debug: true,
generate : {
bindto : '#chart',
size: {
height: 180,
width: 500
},
data : {
x : 'x',
labels : true
},
axis : {
x : {
type : 'timeseries',
tick : {
format : '%H:%M:%S'
},
zoom: {
enabled: true
}
}
}
},
transform : function(m) {
for (var i in m.devices){
return { columns : [
['x', new Date().getTime()],
['Bytes Written', m.devices[i].output.Bytes_Read],
['Bytes Read', m.devices[i].output.Bytes_Written]
]
}
}
}
});
You're chart code transform loop is overwriting every data's key which is why you're only getting a couple values. If you use the i variable to give each piece of data a new key, it'll show up on the chart.
Try this transform function:
eon.chart({
transform : function(m) {
var obj = {columns: [
['x', new Date().getTime()]
]};
for (var i in m.devices) {
obj.columns.push(['Bytes Read ' + i, m.devices[i].output.Bytes_Read]);
obj.columns.push(['Bytes Written ' + i, m.devices[i].output.Bytes_Written]]);
}
}
return obj;
}
});