I am trying to create a stacked area chart and running into an issue with the stack function. The x axis is date, the y axis is count and the area is buildResult.
Here is the code:
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.count; });
// Loop through the data and add elements
data.result.forEach(function(d) {
d.date = new Date(d._id.year, d._id.month-1, d._id.day);
});
// Nest by name aka status
var nested = d3.nest()
.key(function(d) { return d._id.buildResult; });
// Create the layers
var layers = stack(nested.entries(data.result));
The raw data looks like:
{
"result" : [
{
"_id" : {
"month" : 1,
"day" : 20,
"year" : 2014,
"buildResult" : "FAILURE"
},
"count" : 27
},
{
"_id" : {
"month" : 1,
"day" : 20,
"year" : 2014,
"buildResult" : "SUCCESS"
},
"count" : 93
}
],
"ok" : 1
}
The error I am getting is from the layers object:
Cannot read property 1 of undefined
The nested.entries(data.result) object is not null so I'm not sure what is going on. Thanks for the help!
I figured out the issue - my data was not formatted correctly, specifically the 2D array I was passing to stack() was not all the same length.
Related
I have tried using the code below to display the top 3 values based on the count of the val in the json provided below.
yearRingChart.width(300).height(300).dimension(yearDim).group(
spendPertime).innerRadius(50).controlsUseVisibility(true)
.data(function(d) {
return d.order(
function(d) {
return d.val;
}).top(3);
}).ordering(function(d) {
return -d.val;
});
But this is getting sorted based on alphabetical order and not based on val.
I need to display the top 3 names with highest val in the json provided.
The code snippet is provided below -
var yearRingChart = dc.pieChart("#chart-ring-year"),
spendHistChart = dc.barChart("#chart-hist-spend"),
spenderRowChart = dc.rowChart("#chart-row-spenders");
var table = dc.dataTable('#table');
// use static or load via d3.csv("spendData.csv", function(error, spendData) {/* do stuff */});
var spendData = [{
Name : 'A',
val : '100',
time : 9,
place : 'Kolkata'
}, {
Name : 'B',
val : '40',
time : 10,
place : 'Angalore'
}, {
Name : 'C',
val : '5',
time : 11,
place : 'Raipur'
}, {
Name : 'A',
val : '70',
time : 12,
place : 'Chennai'
}, {
Name : 'B',
val : '20',
time : 10,
place : 'Mumbai'
}];
// normalize/parse data
spendData.forEach(function(d) {
d.val = d.val.match(/\d+/)[0];
});
// set crossfilter
var ndx = crossfilter(spendData), yearDim =
ndx.dimension(function(
d) {
return d.place;
}), spendDim = ndx.dimension(function(d) {
return Math.floor(d.val / 10);
}), nameDim = ndx.dimension(function(d) {
return d.Name;
}), spendPertime = yearDim.group().reduceSum(function(d) {
return +d.val;
})
, spendPerSev = yearDim.group().reduceSum(function(d) {
return +d.val;
}), spendPerName = nameDim.group().reduceSum(function(d) {
return +d.val;
}), spendHist = spendDim.group().reduceCount();
yearRingChart.width(300).height(300).dimension(yearDim).group(
spendPertime).innerRadius(50).controlsUseVisibility(true)
.data(function(d) {
return d.order(
function(d) {
return d.val;
}).top(3);
}).ordering(function(d) {
return -d.ue;
});
I am a newbie in dc.js. Any help will be appreciated.
Thankyou
I suspect that the big problem you are running into is that .ordering() - which is the right way to do this - takes group data, not raw data. Once you have aggregated your data using a group, you are going to have an array of {key,value} pairs, not your original array of data.
So I think when you attempt to read d.val or d.ue, you're just getting undefined, which results in no sorting. You could verify this by putting a breakpoint or console.log in your ordering callbacks. That's how I usually debug these kinds of things, when I have a running example.
group.order isn't going to have much effect, so I would suggest removing that.
I'd also suggest using .cap() instead of that complicated data-order-top thing you have, which looks complicated / delicate. Capping is built-in functionality for pie charts and row charts.
I've got some problems with nvd3 pie chart.
I tried this example:
Example http://jsfiddle.net/shabeer90/30rm9qk7/
I've added nv.d3.min and nv.d3.css to my application.
This example looks fine, but there are two problems.
1) No tooltips are shown.
Also the content of the tooltips is not added in DOM.
2) Click on the legend does not filter. Nothing happend.
What am I doing wrong? Perhaps missing .js?
This is my code:
private native void createTestPieChart()/*-{
function pieSectorData() {
return [ {
"key" : "Technology",
y : 298.85,
"symbols" : "DOV",
"color" : "#3182bd",
},
{
"key" : "Health Care",
y : 477.80,
"symbols" : "JNJ",
"color" : "#6baed6",
},
{
"key" : "Consumer Services",
y : 485.65,
"symbols" : "MCD",
"color" : "#9ecae1",
},
{
"key" : "Energy",
y : 739.45,
"symbols" : "XOM, CVX",
"color" : "#A52A2A",
} ];
}
//Regular pie chart example
$wnd.nv.addGraph(function() {
var chart = $wnd.nv.models.pieChart().x(function(d) {
return d.key
}).y(function(d) {
return d.y
}).showLabels(true).color(function(d) {
return d.color;
}).showLegend(true);
chart.tooltip.keyFormatter(function(d, i) {
var symbol = '';
pieSectorData().forEach(function(entry) {
// Search data for key and return the symbols
if (entry.key == d) {
symbol = entry.symbols
}
});
return d + '(' + symbol + ')'
});
$wnd.d3.select("#piechart svg").datum(pieSectorData()).transition()
.duration(350).call(chart);
return chart;
});
}-*/;
Thank you in advance.
Is there a setting that I'm missing to highlight major axis grid lines? I've mocked up an example of what I'm trying to do below. The arrows point to what I want, the circle shows what I have. The axis value highlights the day of the week, but not the grid line. I have a feeling that it is considering the 12 pm's as major axis grid lines too.
Here is what I have for the categoryAxis:
"categoryAxis" :
{
"equalSpacing" : true,
"minPeriod" : "hh",
"parseDates" : true,
"fontSize" : 24,
"dateFormats" : [
{
period : 'fff',
format : 'JJ:NN:SS'
},
{
period : 'ss',
format : 'JJ:NN:SS'
},
{
period : 'mm',
format : 'JJ:NN'
},
{
period : 'hh',
format : 'L A'
},
{
period : 'DD',
format : 'MMM DD\n L A'
},
{
period : 'WW',
format : 'MMM DD\n L A'
},
{
period : 'MM',
format : 'MMM DD\n L A'
},
{
period : 'YYYY',
format : 'MMM DD\n L A'
}]
},
No, there isn't a setting that highlights those lines automatically. You can use a guide to highlight those times by drawing a darker line.
Typically, this is done manually, however you can use the init event to automatically do this by having it read the category axis' internal start and end dates and placing the guides as needed:
var chart = AmCharts.makeChart("chartdiv", {
// ...
"listeners": [{
"event": "init",
"method": function(e) {
//get the start and end date objects from the categoryAxis' internal data array
var startDate = new Date(e.chart.categoryAxis.data[0].category);
var endDate = new Date(e.chart.categoryAxis.data[e.chart.categoryAxis.data.length - 1].category);
var guides = [];
var guideDate;
//start at midnight
startDate.setHours(0, 0, 0, 0);
while (startDate.getTime() <= endDate.getTime()) {
guideDate = new Date(startDate);
guides.push({
"lineAlpha": 1,
"lineColor": "#000",
"date": guideDate
});
startDate.setDate(startDate.getDate() + 1);
}
//remove the first guide if it falls outside of the full date range of the axis
if (guides[0].date.getTime() < e.chart.categoryAxis.data[0].category.getTime()) {
guides.shift();
}
e.chart.categoryAxis.guides = guides;
e.chart.validateNow(); //draw the guides
}
}]
});
Demo
Updated fiddle, courtesy of echonax.
I am trying to apply color coding to segments of a line plot in dimple.js, similar to this example. Specifically, I have some categorical data (the "status" field), where I want each status to correspond to a specific color.
I've tried all variations of addColorAxis that I can think of, but the solution eludes me.
Here's what I have so far:
var svg = dimple.newSvg("#chartContainer", 1000, 1000);
chart = new dimple.chart(svg);
chart.setBounds(100, 100, 500, 300);
x = chart.addCategoryAxis("x", "project");
y = chart.addTimeAxis("y", "date", "%Y-%m-%d", "%Y-%m-%d");
y.addOrderRule("date");
var lines = chart.addSeries(["project"], dimple.plot.line, [x, y]);
lines.data = [
{ "date" : '2016-01-01', "project" : "Grape", "status" : 1 },
{ "date" : '2016-01-08', "project" : "Grape", "status" : -2 },
{ "date" : '2016-01-07', "project" : "Apple", "status" : 3 },
{ "date" : '2016-01-08', "project" : "Apple", "status" : 1 },
{ "date" : '2016-01-02', "project" : "Banana", "status" : -2 },
{ "date" : '2016-01-15', "project" : "Banana", "status" : 2 },
];
lines.lineWeight = 5;
lines.lineMarkers = true;
Related: It seems like y.addGroupOrderRule("date", false); does have no effect at all for reversing the dates. I'd like the oldest dates at top, and newest dates at the bottom. Can't figure it out.
Edit
My latest attempt was to replicate the colorAxis example for a single category, save for swapping the x and y axes.
var grape = [
{ "date" : '2016-01-01', "status" : 0, "fake_x" : 1},
{ "date" : '2016-01-08', "status" : 1, "fake_x" : 1}];
var svg = dimple.newSvg("#chartContainer", 590, 400);
var myChart = new dimple.chart(svg, grape);
myChart.setBounds(60, 30, 500, 300);
var x = myChart.addCategoryAxis("x", "fake_x");
var y = myChart.addTimeAxis("y", "date");
// Order the x axis by date
y.addOrderRule("date");
// Min price will be green, middle price yellow and max red
myChart.addColorAxis("status", ["green", "yellow", "red"]);
// Add a thick line with markers
var lines = myChart.addSeries(null, dimple.plot.line);
lines.lineWeight = 5;
lines.lineMarkers = true;
// Draw the chart
myChart.draw();
The result has the same problems though:
var chart = new dimple.chart(svg);
is the line that breaks your code
I've changed it to
var chart = new dimple.chart(svg,data);
and now it works.
Here is an updated fiddle
http://jsfiddle.net/1hotquwf/8/
Got it to work for a single axis, will post an update if/when I get it to work for the category axis as well.
var grape = [
{ "date" : '2016-01-01', "status" : 0, "fake_x" : 1},
{ "date" : '2016-01-15', "status" : 3, "fake_x" : 1},
{ "date" : '2016-01-08', "status" : 1, "fake_x" : 1}];
var svg = dimple.newSvg("#chartContainer", 590, 400);
// Create and Position a Chart
var chart = new dimple.chart(svg, grape);
chart.setBounds(60, 30, 500, 300);
var x = chart.addCategoryAxis("y", "date")
chart.addMeasureAxis("x", "fake_x");
// Order the x axis by date
x.addOrderRule("date");
// Min price will be green, middle price yellow and max red
chart.addColorAxis("status", ["green", "yellow", "red"]);
// Add a thick line with markers
var lines = chart.addSeries(null, dimple.plot.line);
lines.lineWeight = 5;
lines.lineMarkers = true;
//take this code as an example
Here i have specified yvalue[0],yvalue[1] in groups..
But i need a general design ,where I dont know the number of groups that i have to create(i.e the number of segments) this varies according to the json data.
Consider this example here I have total,total1 therefore i have only 2 values.But if a third variable say total2 is specified in json, I should have a segment for it in my bar chart and so on.This has to be done without altering the groups everytime a field is added.Is there any way to achieve this??
Thanks
var datajson = [ {
country : "china",
total : 20,
total1 : 10
}, {
country : "India",
total : 40,
total1 : 20
}, {
country : "aus",
total : 10,
total1 : 30
}, {
country : "nxz",
total : 50,
total1 : 40
}
];
var xvalue;
var yvalue = [];
var i = 0;
var obj = datajson[0]
for ( var key in obj) {
if (xvalue === undefined)
xvalue = key;
else {
yvalue[i] = key;
i++;
}
}
var chart = c3.generate({
bindto : '#chart',
data : {
json : datajson,
type : 'bar',
keys : {
x : xvalue, // it's possible to specify 'x' when category axis
value : [yvalue[0],yvalue[1]],
},
groups : [ [yvalue[0],yvalue[1]] ]
},
bar : {
width : {
ratio : 0.3
// this makes bar width 50% of length between ticks
}
},
axis : {
x : {
type : 'category'
},
}
});
Your question seems to have most of the answer (you are already generating the yvalue array from the object properties).
You just don't have to specify the elements one by one, instead you can just pass in the array directly and you are done.
groups: [yvalue]