Why is d appearing as undefined in my d3 script? - javascript

edited to include code where cell is defined
I am attempting to create a chart that pulls data from an XHR request, but d is undefined in certain functions in my script:
var svg = d3.select("svg"),
margin = {top: 30, right: 40, bottom: 60, left: 40},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom;
var formatValue = d3.format(",d");
var x = d3.scaleTime()
//var x = d3.scaleLinear()
.domain([new Date(2017, 0, 1), new Date(2020, 11, 31)])
//.rangeRound([0, width]);
.range([0, width-300]);
/*var xScale = d3.scaleTime()
.domain([new Date(2018, 0, 1), new Date(2020, 11, 31)])
.range([50, 1150]);*/
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
//variables for legends
var legendRectSize = 18;
var legendSpacing = 4;
d3.request("https://api.parliament.uk/sparql?query=PREFIX%20rdfs%3A%20%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0APREFIX%20%3A%20%3Chttps%3A%2F%2Fid.parliament.uk%2Fschema%2F%3E%0APREFIX%20id%3A%20%3Chttps%3A%2F%2Fid.parliament.uk%2F%3E%0Aselect%20%3FTreaty%20%3FTreatyname%20%3FLeadOrg%20%3FSeries%20%3FLink%20%3FworkPackage%20%3FprocStepName%20%3Fdate%20where%20%7B%0A%20%3FTreaty%20a%20%3ATreaty%20.%20%20%0A%20%20%20%20%20%3FTreaty%20rdfs%3Alabel%20%3FTreatyname%20.%0A%20%20OPTIONAL%7B%20%3FTreaty%20%3AtreatyHasLeadGovernmentOrganisation%2F%20rdfs%3Alabel%20%3FLeadOrg%20.%7D%20%0A%20%20OPTIONAL%20%7B%3FTreaty%20%3AtreatyHasSeriesMembership%2F%20%3AseriesItemCitation%20%3FSeries.%7D%0A%20%20OPTIONAL%20%7B%3FTreaty%20%3AworkPackagedThingHasWorkPackagedThingWebLink%20%3FLink.%7D%0A%09%3FTreaty%20%3AworkPackagedThingHasWorkPackage%20%3FworkPackage%20.%0A%20%20%09%3FworkPackage%20%3AworkPackageHasProcedure%2Frdfs%3Alabel%20%3Fproc%0A%20%20FILTER(%3Fproc%20IN%20(%22Treaties%20subject%20to%20the%20Constitutional%20Reform%20and%20Governance%20Act%202010%22))%0A%20%20%20%3FworkPackage%20%3AworkPackageHasBusinessItem%20%3FprocStep%20.%0A%20%20%20%20%20%3FprocStep%20%3AbusinessItemDate%20%3Fdate%20.%0A%20%20%3FprocStep%20%3AbusinessItemHasProcedureStep%20id%3Acspzmb6w%20.%0A%20%20%3FprocStep%20%3AbusinessItemHasProcedureStep%2Frdfs%3Alabel%20%3FprocStepName.%20%0A%20%20%20%20%0A%20%20%20%7D%0A")
.mimeType('application/sparql-results+json')
.response(function(xhr) { return JSON.parse(xhr.responseText); })
.get(function(data) {
console.log(data);
var data1 = data.results.bindings;
//if (error) alert(error);
data1.forEach(function(d){
d.datetrimmed = d.date.value.split('+')[0];
console.log(d.datetrimmed)
d.Date1 = Date.parse(d.datetrimmed)
console.log(d.Date1)
d.Date2 = d3.timeMonth(d.Date1)
console.log(d.Date2)
console.log(d.LeadOrg.value)
})
x.domain(d3.extent(data.results.bindings, function(d) { return d.Date2; }));
var myColor = d3.scaleOrdinal()
.range(['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', 'red', '#e6beff', '#9a6324', '#fffac8', '#800000']);
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) { return x(d.Date2); }).strength(1))
.force("y", d3.forceY(height / 2))
.force("collide", d3.forceCollide(14))
.stop();
for (var i = 0; i < 120; ++i) simulation.tick();
g.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 5))
.attr("text-anchor", "middle")
.style("font-size", "24px")
.style("font-family", "Tahoma")
.style("text-decoration", "underline")
.style("fill", "#f2f0f7")
.text("All Treaties Subject to CRAG 2010 by Lead Organisation");
g.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top - 45))
.attr("text-anchor", "middle")
.style("font-size", "12px")
.style("font-family", "Tahoma")
.style("fill", "#f2f0f7")
.text("Click a point on the chart or hover over a square on the legend to highlight all treaties from a given department");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(20));
g.append("text")
.attr("transform",
"translate(" + (width/2-100) + " ," +
(height + margin.top + 10) + ")")
.style("text-anchor", "middle")
.style("font-size", "14px")
.style("font-family", "Tahoma")
.style("fill", "#f2f0f7")
.text("Date the treaty was laid before the House of Commons");
var cell = g.append("g")
.attr("class", "cells")
.selectAll("g").data(d3.voronoi()
.extent([[-margin.left, -margin.top], [width + margin.right, height + margin.top]])
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.polygons(data1)).enter().append("g");
The error occurs at this point further in, where it says that it cannot read property data of undefined:
cell.append("circle")
.attr("class", function(d){
console.log(d)
org = d.data.results.bindings.LeadOrg.value;
return org.replace(/[\s,]/g,'') })
Is there a way I should be defining d further in to the code?
This part of the code is still within the get request from the d3.request function. Is this going to cause problems?
Any help would be appreciated.

You never pass the data from cell to "circle". To do that, consider the following:
cell.append("circle")
.datum(function(d) { return d; })
.attr("class", function(d){
console.log(d)
org = d.data.results.bindings.LeadOrg.value;
return org.replace(/[\s,]/g,'') })
This takes the object d you assigned to cell, and returns it as the data object to assign to the circle as well.
Note that .datum is very related to .data, except that it expects one singular value, not an array of values.

Related

d3 bar chart from multiple arrays

I'm making a barchart, but I cannot resolve its secondary function; updating with secondary data.
I make the bars with primary data from 2 separate arrays into an array like this;
labes = [label1, label2];
primarydata = [1,2]
data = [];
data = $.map(labels, function(v, i) {
return [[" " + v, " " + primaryData[i]]];
});
which gives output:
[["label1", "1"], ["label2", "2"]]
I then insert the data into an d3 bar chart.
var svg = d3.select($(svgobject).get(0)),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = $(svgobject).width() - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]),
y1 = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain(data.map(function (d) {
return d[0];
}));
y.domain([0, d3.max(data, function (d) {
// parseInt needed here, or the scaling is wrong. Still scales though for some reason
return parseInt(d[1]);
})]);
// Inserts the x-axis line text
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height) + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("y", 0)
.attr("x", 8)
.attr("dy", "1.75em")
.attr("transform", "rotate(340)")
.style("text-anchor", "end");
// Inserts the y-axis line
// d3.format(".2s"), formats the line fx from 1300 to 1.3 thousand
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(10).tickFormat(d3.format("2.2s")))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "0.71em")
.attr("text-anchor", "end");
// Insert all the bars
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function (d) {
return x(d[0]);
})
.attr("y", function (d) {
return y(d[1]);
})
.attr("width", x.bandwidth())
.attr("height", function (d) {
return height - y(d[1]);
});
and this produces the barchart
However I want to with a push of a button put in comparable data like this;
secondaryData = [];
data = primaryData.concat(secondaryData).map(function(a, i) {
return [labels[i % 2], a.toString()];
});
And then I am at a loss as how to proceed. My bar does not even show the full data from the array with primary and secondary data. How do I insert the secondaryData but differentiate it? So I can style it differently.
I have also tried making a y1 taking data from d[2], but have failed in doing so.

D3.js: Line chart - tooltip and vertical line of hover

I have been working on an interactive line chart built using D3.js. One hover I would like a tool tip to be displayed with a vertical line. The vertical line comes out fine, however, I have problems related to the tool tip. The tool tip position is not on the graph and I am only getting the first data element.
Here is my code:
margin = {
top: 20,
right: 20,
bottom: 20,
left: 50
};
var width = Math.max(250, Math.min(700, d3.select("#content").width- margin.left - margin.right)),
height = 500;
var vis = d3.select("#line_chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
max_x = 0, max_y = 0, min = 100;
d3.csv("line.csv", function(error, data) {
for(i=0; i < data.length; i++){
max_y = Math.max(max_y, data[i].number);
max_x = Math.max(max_x, data[i].class);
min = Math.min(min, data[i].class);
}
xScale = d3.scale.linear().range([margin.left, width - margin.right]).domain([min, max_x]),
yScale = d3.scale.linear().range([height - margin.top, margin.bottom]).domain([0, max_y]),
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (margin.left) + ",0)")
.call(yAxis);
var lineGen = d3.svg.line()
.x(function(d) {
return xScale(d.class);
})
.y(function(d) {
return yScale(d.number);
})
.interpolate("basis");
var pth = vis.append('svg:path')
.attr('d', lineGen(data))
.attr('stroke', '#000')
.attr('stroke-width', 3.5)
.attr('fill', 'none');
var totalLength = pth.node().getTotalLength();
pth
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2400)
.ease("linear")
.attr("stroke-dashoffset", 0);
//Line chart mouse over
var hoverLineGroup = vis.append("g")
.attr("class", "hover-line");
var hoverLine = hoverLineGroup
.append("line")
.attr("stroke", "#000")
.attr("x1", 10).attr("x2", 10)
.attr("y1", 0).attr("y2", height);
var hoverTT = hoverLineGroup.append('text')
.attr("class", "hover-tex capo")
.attr('dy', "0.35em");
var cle = hoverLineGroup.append("circle")
.attr("r", 4.5);
var hoverTT2 = hoverLineGroup.append('text')
.attr("class", "hover-text capo")
.attr('dy', "0.35em");
hoverLineGroup.style("opacity", 1e-6);
var rectHover = vis.append("rect")
.data(data)
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
rectHover
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
function hoverMouseOn(d) {
var mouse_x = d3.mouse(this)[0];
var mouse_y = d3.mouse(this)[1];
var graph_y = yScale.invert(mouse_y);
var graph_x = xScale.invert(mouse_x);
hoverTT.text("Marks: " + Math.round(graph_x * 100)/100);
hoverTT.attr('x', mouse_x + 10);
hoverTT.attr('y', yScale(d.class));
hoverTT2.text("Frequency: " + Math.round(d.number * 100)/100)
.attr('x', mouse_x + 10)
.attr('y', yScale(d.class) +15);
cle
.attr('x', mouse_x)
.attr('y', mouse_y);
hoverLine.attr("x1", mouse_x).attr("x2", mouse_x)
hoverLineGroup.style("opacity", 1);
}
function hoverMouseOff() {
hoverLineGroup.style("opacity", 1e-6);
};
});
}
The data:
class,number
25,1
30,7
35,11
45,13
50,21
55,23
60,30
65,41
75,39
80,24
85,14
90,4
95,8
100,2
I am not able to figure out what the issue is.
How can I solve this?
Thanks in advance.
EDIT: Here is the working code: https://jsfiddle.net/kan83q0m/1/
In your hoverMouseOn method, the variable d is undefined. You'll need to use d3.bisector to find the closest data point, like this:
var bisectDate = d3.bisector(function(d) { return d.class; }).left;
var mouseDate = xScale.invert(mouse_x);
var i = bisectDate(data, mouseDate);
var d0 = data[i - 1]
var d1 = data[i];
var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
Also, I put the mousemove listener on 'vis' instead of 'rectHover':
vis
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
and used d.number instead of d.class for the y values. If you want the tooltip to always be on the line it gets a bit more complicated. Here's a working fiddle.
Might be easier to just put the tooltip at your mouse coordinates like in this fiddle.

How to create vertically grouped bar chart in d3.js using json data?

In a web application I was supposed to create a vertically grouped bar chart using d3.js using json data. Previously I create a horizontal grouped bar using the following code. Can anyone help me out? Thanks in advance.
var data = {
labels: [
'resilience', 'maintainability', 'accessibility',
'uptime', 'functionality', 'impact'
],
series: [
{
label: '2012',
values: [4, 8, 15, 16, 23, 42]
},
{
label: '2013',
values: [12, 43, 22, 11, 73, 25]
},
{
label: '2014',
values: [31, 28, 14, 8, 15, 21]
},]
};
var chartWidth = 300,
barHeight = 20,
groupHeight = barHeight * data.series.length,
gapBetweenGroups = 10,
spaceForLabels = 150,
spaceForLegend = 150;
// Zip the series data together (first values, second values, etc.)
var zippedData = [];
for (var i=0; i<data.labels.length; i++) {
for (var j=0; j<data.series.length; j++) {
zippedData.push(data.series[j].values[i]);
}
}
// Color scale
var color = d3.scale.category20();
var chartHeight = barHeight * zippedData.length + gapBetweenGroups * data.labels.length;
var x = d3.scale.linear()
.domain([0, d3.max(zippedData)])
.range([0, chartWidth]);
var y = d3.scale.linear()
.range([chartHeight + gapBetweenGroups, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.tickFormat('')
.tickSize(0)
.orient("left");
// Specify the chart area and dimensions
var chart = d3.select(".chart")
.attr("width", spaceForLabels + chartWidth + spaceForLegend)
.attr("height", chartHeight);
// Create bars
var bar = chart.selectAll("g")
.data(zippedData)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(" + spaceForLabels + "," + (i * barHeight + gapBetweenGroups * (0.5 + Math.floor(i/data.series.length))) + ")";
});
// Create rectangles of the correct width
bar.append("rect")
.attr("fill", function(d,i) { return color(i % data.series.length); })
.attr("class", "bar")
.attr("width", x)
.attr("height", barHeight - 1);
// Add text label in bar
bar.append("text")
.attr("x", function(d) { return x(d) - 3; })
.attr("y", barHeight / 2)
.attr("fill", "red")
.attr("dy", ".35em")
.text(function(d) { return d; });
// Draw labels
bar.append("text")
.attr("class", "label")
.attr("x", function(d) { return - 10; })
.attr("y", groupHeight / 2)
.attr("dy", ".35em")
.text(function(d,i) {
if (i % data.series.length === 0)
return data.labels[Math.floor(i/data.series.length)];
else
return ""});
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + spaceForLabels + ", " + -gapBetweenGroups/2 + ")")
.call(yAxis);
// Draw legend
var legendRectSize = 18,
legendSpacing = 4;
var legend = chart.selectAll('.legend')
.data(data.series)
.enter()
.append('g')
.attr('transform', function (d, i) {
var height = legendRectSize + legendSpacing;
var offset = -gapBetweenGroups/2;
var horz = spaceForLabels + chartWidth + 40 - legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', function (d, i) { return color(i); })
.style('stroke', function (d, i) { return color(i); });
legend.append('text')
.attr('class', 'legend')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function (d) { return d.label; });
After continuous digging I found the correct way of doing this. Thanks to Mike Bostock for the example he provided in here. In here you can also find out the elaborate discussion of that example. Thanks for your support :)
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
//console.log(margin.left);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
/*Our json object is [{letter: "A", frequency: .08167,depth:.32},{letter: "B", frequency: .01492,depth:.69}]
To use csv file you just need to follow the link I provided
*/
var data = [
{letter: "A", frequency: .08167,depth:.32},
{letter: "B", frequency: .01492,depth:.69}
];
var groupNames=d3.keys(data[0]).filter(function(key){return key!="letter";})
data.forEach(function(d){
d.groups=groupNames.map(function(name){return {name:name,value:+d[name]};})
});
x0.domain(data.map(function(d){return d.letter;}));
x1.domain(groupNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0,d3.max(data,function(d){
return d3.max(d.groups,function(d){
return d.value;
});
})]);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Letter Fun");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.letter) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.groups; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
Please let me know if you have anything to know about the code.

D3 update data on the wrong bars

I want to update data on a click but the bars that are changing are not the right ones. There is something I cant quite fix with the select. On click the grey bars, which should be bar2 are updating. It should be bar.
Example: https://jsfiddle.net/Monduiz/kaqv37gu/
D3 chart:
var values = feature.properties;
var data = [
{name:"Employment rate",value:values["ERate15P"]},
{name:"Participation rate",value:values["PR15P"]},
{name:"Unemployment rate",value:values["URate15P"]}
];
var margin = {top: 70, right: 50, bottom: 20, left: 50},
width = 400 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom,
barHeight = height / data.length;
// Scale for X axis
var x = d3.scale.linear()
.domain([0, 100]) //set input to a scale of 0 - 1. The index has a score scale of 0 to 1. makes the bars more accurate for comparison.
.range([0, width]);
var y = d3.scale.ordinal()
.domain(["Employment rate", "Participation rate", "Unemployment rate"])
.rangeRoundBands([0, height], 0.2);
var svg = d3.select(div).select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.classed("chartInd", true);
var bar2 = svg.selectAll("g.bar")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
var bar = svg.selectAll("g.bar")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar2.append("rect")
.attr("height", y.rangeBand()-15)
.attr("fill", "#EDEDED")
.attr("width", 300);
bar.append("rect")
.attr("height", y.rangeBand()-15)
.attr("fill", "#B44978")
.attr("width", function(d){return x(d.value);});
bar.append("text")
.attr("class", "text")
.attr("x", 298)
.attr("y", y.rangeBand() - 50)
.text(function(d) { return d.value + " %"; })
.attr("fill", "black")
.attr("text-anchor", "end");
bar.append("text")
.attr("class", "text")
.attr("x", function(d) { return x(d.name) -5 ; })
.attr("y", y.rangeBand()-50)
//.attr("dy", ".35em")
.text(function(d) { return d.name; });
d3.select("p")
.on("click", function() {
//New values for dataset
var values = feature.properties;
var dataset = [
{name:"Employment rate",value:values["ERate15_24"]},
{name:"Participation rate",value:values["PR15_24"]},
{name:"Unemployment rate",value:values["URate15_24"]}
];
//Update all rects
var bar = svg.selectAll("rect")
.data(dataset)
.attr("x", function(d){return x(d.value);})
.attr("width", function(d){return x(d.value);})
});
}
var bar2 = svg.selectAll("g.bar")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
var bar = svg.selectAll("g.bar")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
'bar2' above generates 3 new g elements (one for each datum)
Since you don't set attr("class","bar") for these then 'bar' will also generate 3 new g elements - (if you had set the class attribute bar would return empty as no new elements would be generated and you'd see missing stuff)
Further on you add rects to all these g elements for six rectangles in total and in the click function you select all these rectangles and re-attach 3 fresh bits of data
Since bar2 was added first the rectangles in its g elements are hoovering up the new data
You need to select and set different classes on the g elements, .selectAll("g.bar") and .attr("class", "bar") for bar, and .selectAll("g.bar2") and .attr("class", "bar2") for bar2 (use the same name to keep it simple)
then in the new data you need select only the rects belonging to g elements of the bar class: svg.selectAll(".bar rect")
Another way would be to have only one set of g elements and add two types of rectangle (differentiated by class attribute)

Drawing stacked-bar chart using d3

I'm trying to adapt this code:
http://bl.ocks.org/anupsavvy/9513382
To plot a stacked-bar chart using custom data. I don't need any transitions, just a simple plot.
I end up with this code:
data = jsonArr;
var margin = {
top: 40,
right: 40,
bottom: 40,
left: 40
},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var color = d3.scale.ordinal()
.range(colorrange);
var stack = d3.layout.stack();
stack(data);
var xScale = d3.time.scale()
.domain([new Date(0, 0, 0, data[0][0].label, 0, 0, 0), new Date(0, 0, 0, data[0][data[0].length - 1].label, 0, 0, 0)])
.rangeRound([0, width - margin.left - margin.right]);
var yScale = d3.scale.linear()
.domain([0,
d3.max(data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.value;
});
})
])
.range([height - margin.bottom - margin.top, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.ticks(d3.time.hour, 1)
.tickFormat(d3.time.format("%H"));
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
var svg = d3.select("#info")
.append("svg")
.attr("width", width)
.attr("height", height);
var groups = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("class", "rgroups")
.attr("transform", "translate(" + margin.left + "," + (height - margin.bottom) + ")")
.style("fill", function(d, i) {
return colorrange[i];
});
var rects = groups.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("width", 6)
.attr("height", function(d) {
return -yScale(d.value) + (height - margin.top - margin.bottom);
})
.attr("x", function(d) {
return xScale(new Date(0, 0, 0, d.label, 0, 0, 0));;
})
.attr("y", function(d) {
return -(-yScale(d.y0) - yScale(d.value) + (height - margin.top - margin.bottom) * 2);
});
console.log(rects);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(40," + (height - margin.bottom) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 5)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.text("Number of complaints");
svg.append("text")
.attr("class", "xtext")
.attr("x", width / 2 - margin.left)
.attr("y", height - 5)
.attr("text-anchor", "middle")
.text("Hour of day");
More specifically:
yScale(d.y0) is returning NaN.
If I comment this piece of code, I can see the axes:
After a while, I managed to see the and some data (among errors):
I guess I'm not understanding the properly way to plot the data itself.
Any help would be appreciated.
My json label attribute is related to the y coordinate, while value is related to the x coordinate.
EDIT:
It seems that the problem begins when I call stack. The first array has y0 values as 0, but the second and third ones have y0 = NaN. I don't know how to fix this.
This is the relative jsfiddle:
https://jsfiddle.net/rhzkz9gb/13/
You need to provide the accessor functions for the data (because it is not keyed with 'x' and 'y').
var stack = d3.layout.stack().x(function(d,i){return i;}).y(function(d){return d.value;});
https://jsfiddle.net/ermineia/rhzkz9gb/14/

Categories