Does anyone know how I would go making a multi bar graph to be single series? In a working example that i've seen of how i want my graph to look, this function was being used for the data.
function dataFactory(seriesNum, perSeries) {
return new d3.range(0,seriesNum).map(function(d,i) { return {
key: 'Stream ' + i,
values: new d3.range(0,perSeries).map( function(f,j) {
return {
y: 10 + Math.random()*100,
x: j
}
})
};
});
}
Below is the code i'm currently using and I will also upload a picture so you can see that my labels are off position because it isn't single series.
function loadBar(){
$.getJSON('data5.json', function (json) {
var data1 = [];
for (var key in json) {
if (json.hasOwnProperty(key)) {
var item = json[key];
data1.push({
key: item.key,
values: item.values
});
}
}
var chart;
nv.addGraph(function() {
chart = nv.models.multiBarChart()
.color(d3.scale.category10().range())
.margin({bottom: 100})
.transitionDuration(300)
.delay(0)
//.rotateLabels(45)
;
chart.multibar
.hideable(true);
chart.reduceXTicks(false).staggerLabels(true).groupSpacing(0.2);
chart.xAxis
.axisLabel("Players")
.showMaxMin(false);
chart.yAxis
.axisLabel('Hours Played')
.tickFormat(d3.format('d'));
d3.select('#chart1 svg')
.datum(data1)
.call(chart);
nv.utils.windowResize(chart.update);
chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });
return chart;
});
});
}
$(document).ready(function(){
loadBar();
});
data5.json(just in case someone needs to see it)
{
"Member1": {
"key":"test10",
"values": [
{
"x": "test10",
"y": 20
}
]
},
"Member2":{
"key":"test9",
"values": [
{
"x": "test9",
"y": 10
}
]
},
"Member3":{
"key":"test8",
"values": [
{
"x": "test8",
"y": 4
}
]
},
"Member4":{
"key":"test7",
"values": [
{
"x": "test7",
"y": 12
}
]
},
"Member5":{
"key":"test6",
"values": [
{
"x": "test6",
"y": 30
}
]
},
"Member6":{
"key":"test5",
"values": [
{
"x": "test5",
"y": 8
}
]
}
,
"Member7":{
"key":"test4",
"values": [
{
"x": "test4",
"y": 27
}
]
},
"Member8":{
"key":"test3",
"values": [
{
"x": "test3",
"y": 17
}
]
},
"Member9":{
"key":"test2",
"values": [
{
"x": "test2",
"y": 2
}
]
},
"Member10":{
"key":"test1",
"values": [
{
"x": "test1",
"y": 55
}
]
}
![enter image description here][2]}
The expected data format for the multi-bar chart is an array of object, each of which represent a data series. Within each series object, there should be a key property naming that series, and a values array with the data points. The values array should have an object for each bar, with a categorical x value and a numerical y value.
For example, if I "stringify" the results of their data-generating function (after reducing the parameters so I only get two data series with five bars each), it looks like this:
[{
"key": "Stream0",
"values": [{
"x": 0,
"y": 0.16284738584101344
}, {
"x": 1,
"y": 2.370283172738109
}, {
"x": 2,
"y": 0.1631208266452718
}, {
"x": 3,
"y": 0.24609871793543797
}, {
"x": 4,
"y": 1.5096133160633776
}]
}, {
"key": "Stream1",
"values": [{
"x": 0,
"y": 0.12566330679904006
}, {
"x": 1,
"y": 0.1321859413211272
}, {
"x": 2,
"y": 1.4798247902549135
}, {
"x": 3,
"y": 0.10870538273358979
}, {
"x": 4,
"y": 0.16155091711225184
}]
}]
The graph looks like this:
Each series is graphed in a different colour. The bars are grouped according to their x value, side-by-side or you can switch to stacked.
The reason you were getting one narrow bar for each of your categories is because you have 11 different data series, each with one bar that has a different x-value. So for each x-value, the graph leaves room for all the data series to be plotted side-by-side, even though it doesn't have data for them.
You either need to group all your bars into one data series, with the test identified via the x-value, or you need to give them all the same x-value, with the test identified via the series key.
I know you've already got the first option pretty much working, based your other question on the discrete bar chart function.
The easiest way to modify this code to see what it looks like the other way (11 series, each with only one bar), is to tell the chart function to just use a constant value for x:
chart.x(function(d){return "test";})
With that, and data similar to yours (many series, each with only one data point), you get a chart that switches from a bar chart to a stacked area chart, like this:
(P.S., You'll of course want to remove the number-formatting tickFormat function so that you don't get "NaN" like in these pictures!)
Related
I have this array, and I want to sum property (y) of the array elements when x matches certain criteria. For example, if "x" has the same string value between "/" and "?" as another object then add their "y" property together.
const data = [
{
"x": "/shop.html",
"y": 3
},
{
"x": "/",
"y": 2
},
{
"x": "/?test324",
"y": 1
},
{
"x": "/account.html",
"y": 1
},
{
"x": "/account.html?test1",
"y": 1
},
{
"x": "/shop.html?test543",
"y": 1
}
]
And it should be like this at the end
const expectedResult = [
{
"x": "/shop.html",
"y": 4
},
{
"x": "/",
"y": 3
},
{
"x": "/account.html",
"y": 2
},
]
So as you can see the 2nd array doesn't have the "?xxx" thing, they are all "merged" based on string value between last "/" and "?"
Tried to do something like this
let output = res.data.data.reduce(function (accumulator, cur) {
let x = cur.x,
found = accumulator.find(function (elem) {
elem.x = elem.x.split("?")[0];
return elem.x == x;
});
if (found) found.y += cur.y;
else accumulator.push(cur);
return accumulator;
}, []);
But duplicated values doesn't add themselves.
It returns me this
[
{
"x": "/shop.html",
"y": 3
},
{
"x": "/",
"y": 2
},
{
"x": "/",
"y": 1
},
{
"x": "/account.html",
"y": 1
},
{
"x": "/account.html",
"y": 1
},
{
"x": "/shop.html?test543",
"y": 1
}
]
Any idea?
The below may be one possible solution to achieve the desired objective.
Code Snippet
// a small helper method to convert key by leaving out the z-s in: '/xxxx?zzz'
const convertKey = x => (x.split('?')[0]);
// use reduce to iterate thru the array & obtain a result-object
// destructure to get 'x', 'y'
// if 'x' already present, add 'y'
// else create an object with 'x', 'y' props
// return the `Object.values` of the result-object
const transform = arr => (
Object.values(
arr.reduce(
(acc, {x, y}) => ({
...acc,
[convertKey(x)]: {
...(acc[convertKey(x)] || {x}),
y: (acc[convertKey(x)]?.y || 0) + y
}
}),
{}
)
)
);
const data = [
{
"x": "/shop.html",
"y": 3
},
{
"x": "/",
"y": 2
},
{
"x": "/?test324",
"y": 1
},
{
"x": "/account.html",
"y": 1
},
{
"x": "/account.html?test1",
"y": 1
},
{
"x": "/shop.html?test543",
"y": 1
}
];
console.log(transform(data));
Explanation
The above code-snippet has inline comments describing the steps. For further description, please post specific questions on comments below, if required.
I have an object like this in my NodeJS backend:
{
"x": "2021",
"y": {
"Kumada, K": 2,
"Wu, XY": 4,
"da Silva, BJP": 2
}
}
And i would need it to become like this:
{
"x": "2021",
"Kumada, K": 2
"Wu, XY": 4,
"da Silva, BJP": 2
}
EDIT: The "y" is dynamic which means it can have any number of different names, for example:
{
"x": "2021",
"y": {
"Josh, K": 2,
"Bob": 4,
"Joseph": 2,
"John": 0
}
}
Any tips? Appreciate any help!
Below approach first creates an object based on a.y and then add all properties from a one by one using Object.keys(). Then it removes the y key, since it is not required.
let a = {
"w" : "Hello",
"x": "2021",
"y": {
"Kumada, K": 2,
"Wu, XY": 4,
"da Silva, BJP": 2
}
}
let b = a.y;
Object.keys(a).forEach((x)=>{
b[x] = a[x];
})
delete b.y
This will be a shallow copy
For eg : If you have a["x"] as { 'prop1' : 22, 'prop2' : 33 }. And you modify a["x"]["prop1"] = 22; This will be reflected in your final object too.
Get to know spread syntax. It's magic sauce for this kind of thing
let o = {
"x": "2021", "y": { "Kumada, K": 2, "Wu, XY": 4, "da Silva, BJP": 2 }
}
let newobj = { ...o, ...o.y };
delete newobj.y;
console.log(newobj)
I am making an API call from Angular 5, the response is coming in below format.
let ob = { "metadata":{
"lastSyncTime":"2000-11-21T16:07:53",
"dataFromDB":true
},
"allocationReports":[
{
"allocatedUserCount":130,
"healthGoalName":"Feel Happier"
},
{
"allocatedUserCount":150,
"healthGoalName":"Quit Smoking"
},
{
"allocatedUserCount":100,
"healthGoalName":"Eat Healthier"
}
],
"overall":{
"usersWithGoalCount":0,
"registeredCount":500,
"eligibleCount":280
}
}
I need to transform this data into a list of lists(or Array of Arrays) so that I can plot multiple donut charts on this data. I have tried with multiple methods like using .map, but getting all the values in single list. How can I build the data in below format.
The required format is : [Array should be sorted.]
[
[
{ "x": "Eat Healthier", "y": 100 },
{ "x": "Total registered", "y": 500 }
],
[
{ "x": "Feel Happier", "y": 130 },
{ "x": "Total registered", "y": 500 }
],
[
{ "x": "Quit Smoking", "y": 150 },
{ "x": "Total registered", "y": 500 }
]
]
I have written below code.
r=ob.allocationReports.map(o=>{return [{x:o.healthGoalName,y:o.allocatedUserCount},{x: "Total registered", y: ob.overall.registeredCount }]})
But the result I am getting is not sorted. How can I sort this.
Try this it will sort them in ascending order
ob={"metadata":{ "lastSyncTime":"2000-11-21T16:07:53", "dataFromDB":true }, "allocationReports":[ { "allocatedUserCount":130, "healthGoalName":"Feel Happier" }, { "allocatedUserCount":100, "healthGoalName":"Eat Healthier" },{ "allocatedUserCount":150, "healthGoalName":"Quit Smoking" } ], "overall":{ "usersWithGoalCount":0, "registeredCount":500, "eligibleCount":280 } }
r=ob.allocationReports.map(o=>{return [{x:o.healthGoalName,y:o.allocatedUserCount},{x: "Total registered", y: ob.overall.registeredCount }]}).sort((a,b)=>a[0].y-b[0].y)
console.log(r)
I have variable data having json data as below:
[
{
"BillingMonth":"11",
"BillingYear":"2016",
"Volume":"72",
"BillingMonthName":"November",
"BillingProduct":"Product1"
},
{
"BillingMonth":"11",
"BillingYear":"2016",
"Volume":"617",
"BillingMonthName":"November",
"BillingProduct":"Product2"
},
{
"BillingMonth":"12",
"BillingYear":"2016",
"Volume":"72",
"BillingMonthName":"December",
"BillingProduct":"Product1"
},
{
"BillingMonth":"12",
"BillingYear":"2016",
"Volume":"72",
"BillingMonthName":"December",
"BillingProduct":"Product2"
}
]
What I want to split above json data using javascript/jquery and get them stored in two variables data1, data2 having json data as below as result:
{
type: "stackedBar",
legendText: "Product1",
showInLegend: "true",
data1: [
{ x: November, y: 72 },
{ x: December, y: 72 },
]
}
and
{
type: "stackedBar",
legendText: "Product2",
showInLegend: "true",
data2: [
{ x: November, y: 617 },
{ x: December, y: 72 },
]
}
The above will bind in canvas js stackedbar chart.
Thanks!
Hey here's a solution I had a lot of fun working on I hope it works well for you. I wasn't sure if you would always have 2 products product1, product2 so I went with a more general approach for n amount of products. The result is in an array format, but you can use es6 destructuring to get the two variables data1 and data2 like I did below:
/*
* helper function to restructure json in the desired format
*/
function format(obj) {
var formatted = {
"type": "stackedBar",
"legendText": obj.BillingProduct,
"showInLegend": "true",
"data": [{
"x": obj.BillingMonthName,
"y": obj.Volume
}]
}
return formatted;
}
/*
* returns an array of unique products with corresponding BillingMonth/Volume data
*/
function getStackedBarData(data) {
// transform each obj in orignal array to desired structure
var formattedData = data.map(format);
// remove duplicate products and aggregate the data fields
var stackedBarData =
formattedData.reduce(function(acc, val){
var getProduct = acc.filter(function(item){
return item.legendText == val.legendText
});
if (getProduct.length != 0) {
getProduct[0].data.push(val.data[0]);
return acc;
}
acc.push(val);
return acc;
}, []);
return stackedBarData;
}
var data = [{
"BillingMonth": "11",
"BillingYear": "2016",
"Volume": "72",
"BillingMonthName": "November",
"BillingProduct": "Product1"
}, {
"BillingMonth": "11",
"BillingYear": "2016",
"Volume": "617",
"BillingMonthName": "November",
"BillingProduct": "Product2"
}, {
"BillingMonth": "12",
"BillingYear": "2016",
"Volume": "72",
"BillingMonthName": "December",
"BillingProduct": "Product1"
}, {
"BillingMonth": "12",
"BillingYear": "2016",
"Volume": "72",
"BillingMonthName": "December",
"BillingProduct": "Product2"
}]
var dataVars = getStackedBarData(data);
var data1 = dataVars[0];
var data2 = dataVars[1];
console.log(data1);
console.log(data2);
Hope this helps you!
I'm new using highcharts and JSON.
My javascript code is this:
$(document).ready(function() {
var options = {
chart: {
renderTo: 'grafica',
type: 'spline'
},
series: [{}]
};
$.getJSON('ajax/gettipomov.aspx', function(data) {
options.series[0].data = data;
var chart = new Highcharts.Chart(options);
});
});
And the data returned by the server and received by JavaScript is this:
[{"tipoMov":"Ajuste negativo","valorTipoMov":5},{"tipoMov":"Ajuste positivo","valorTipoMov":5},{"tipoMov":"Compra","valorTipoMov":5}, {"tipoMov":"Transferencia","valorTipoMov":5},{"tipoMov":"Venta","valorTipoMov":5}]
The problem is that chart is not showing any data, the chart is blank: image
The JSON Encoding that I use is:
var encoder = new JavaScriptSerializer();
return encoder.Serialize(obj);
That's the format expected:
{ "name": "Ajuste negativo", "y": 5 },
{ "name": "Ajuste positivo", "y": 5 },
{ "name": "Compra", "y": 5},
{ "name": "Transferencia", "y": 5},
{ "name": "Venta", "y": 5}
tipoMov and valorTipoMov mean nothing to Highcharts, so change your Object to return the properties named accordingly.