Visually displaying JSON data in a grouped bar chart with d3.js - javascript

I need help with visually displaying JSON data using D3.JS. I can get the graphs to show but my problem is that the bars stack up ontop of each other instead of being translated into groups based on the categories they are displaying. Below you can find my code as well as a link to a screengrab of my current output as well as the JSON file im using.
link to screengrab:
http://tinypic.com/view.php?pic=15x6anl&s=8#.VH3C5HWSw8o
and here is my code:
$(document).ready(function(){
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"));
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 + ")");
d3.json("ronaldo.json", function(error, data) {
console.log(data);
var playerNames = []
data.forEach(function(d){playerNames.push(d.name)})
var attr = [];
data[0]['statistics']['2005'].forEach(function(d){return attr.push(d.attr)})
console.log(attr)
x0.domain(attr.map(function(d){return d}));
//x0.domain(data.map(function(d){return d['statistics']['2005']['attr']}));
x1.domain(playerNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d["statistics"]["2005"], function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Units");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(+d['statistics']['2005']['attr']) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d['statistics']['2005']; })
.enter().append("rect")
.attr("class","bars")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d['attr']); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d['value']); })
.style("fill", function(d) { return color(d.attr);});
var legend = svg.selectAll(".legend")
.data(playerNames.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
});
JSON Data:
[
{
"name": "Cristiano Ronaldo",
"age" : 28,
"team": "Real Madrid",
"statistics" : {
"2005" : [
{"attr" :"Appearances",
"value": 100},
{"attr" :"Goals",
"value": 92},
{"attr" :"Yellow Cards",
"value": 10},
{"attr" :"Red Cards",
"value": 1}
]
}
},
{
"name": "Lionel Messi",
"age" : 29,
"team": "Barcelona",
"statistics" : {
"2005" : [
{"attr" :"Appearances",
"value": 90},
{"attr" :"Goals",
"value": 87},
{"attr" :"Yellow Cards",
"value": 13},
{"attr" :"Red Cards",
"value": 43}
]
}
}
]

I don't understand why you have a x0 and a x1 scales but your issue is here.
You should have only one scale that you use in:
xAxis (be careful to override the scale of xAxis after you defined x1)
.attr("x", function(d) { return x1(d['attr']); })
I have made a small jsFiddle with the solution I suggested but since I don't know what you wanted to see exactly, I'm not sure it's perfect: http://jsfiddle.net/chrisJamesC/uzmur5kb/
All I did was: change the .attr("x", ...) line to:
.attr("x", function(d) { return x0(d['attr']); })

Related

d3.js: Stacked Bar Chart with low values

I faced with a problem when some values in a bar very small when at the same time most of the other values are big enough. As the result these chunks with low values are almost not visible. I did not find any solution hot to correctly round chunks(not manually because I now that I can round them to more higher values via scale + invert(in order to determine what values I needed to show them more or less visible)). As an example below: as you see the last bar with low values is almost not visible. So can you suggest how to fix it? It would be great to have an opportunity to be able to specify the min size of stacked bar chart chunk. Thank you in advance.
http://jsfiddle.net/vhcdt13x/
// Setup svg using Bostock's margin convention
var margin = {top: 20, right: 160, bottom: 35, left: 30};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
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 + ")");
/* Data in strings like it would be if imported from a csv */
var data = [
{ year: "2006", redDelicious: "100", mcintosh: "150", oranges: "90", pears: "60" },
{ year: "2012", redDelicious: "1", mcintosh: "1", oranges: "1", pears: "1" }
];
var parse = d3.time.format("%Y").parse;
// Transpose the data into layers
var dataset = d3.layout.stack()(["redDelicious", "mcintosh", "oranges", "pears"].map(function(fruit) {
return data.map(function(d) {
return {x: parse(d.year), y: +d[fruit]};
});
}));
// Set x, y and colors
var x = d3.scale.ordinal()
.domain(dataset[0].map(function(d) { return d.x; }))
.rangeRoundBands([10, width-10], 0.02);
var y = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) { return d3.max(d, function(d) { return d.y0 + d.y; }); })])
.range([height, 0]);
var colors = ["b33040", "#d25c4d", "#f2b447", "#d9d574"];
// Define and draw axes
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width, 0, 0)
.tickFormat( function(d) { return d } );
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%Y"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Create groups for each series, rects for each segment
var groups = svg.selectAll("g.cost")
.data(dataset)
.enter().append("g")
.attr("class", "cost")
.style("fill", function(d, i) { return colors[i]; });
var rect = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y0 + d.y); })
.attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
.attr("width", x.rangeBand())
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
// Draw legend
var legend = svg.selectAll(".legend")
.data(colors)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {return colors.slice().reverse()[i];});
legend.append("text")
.attr("x", width + 5)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
switch (i) {
case 0: return "Anjou pears";
case 1: return "Naval oranges";
case 2: return "McIntosh apples";
case 3: return "Red Delicious apples";
}
});
// Prep the tooltip bits, initial display is hidden
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");

D3 x-Axis not showing correctly

I'm trying to create a bar chart with data achieved from JSON.
This was working properly in my test drive, that had data from csv, but I'm having problem showing the x-axis in my graph.
Here is how it's currently displayed:
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleOrdinal().range([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json(urljson, function(error, data) {
data = data.results;
data.forEach(function(d) {
d.result = +d.result;
});
console.log(data);
x.domain(data.map(function(d) {return d.date } ));
y.domain([0, d3.max(data, function(d) {return d.result; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height) + ")")
.call(d3.axisBottom(x));
console.log(x.domain());
console.log(y.domain());
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Value");
g.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) {return x(d.date); })
.attr("y", function(d) {return y(d.result); })
.attr("height", function(d) {return height - y(d.result);})
});
and the JSON I am using looks like this:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"date": "2017-09-22",
"result": 35.9
},
{
"date": "2017-09-23",
"result": 65.12
},
{
"date": "2017-09-24",
"result": 11.23
},
{
"date": "2017-09-25",
"result": 77.8
},
{
"date": "2017-09-26",
"result": 108.98
}
]
}
Since x is an ordinal scale, you have to set a range with the same number of elements of the domain. According to the API:
If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. (emphasis mine)
This is a demo, that shows the behaviour of your code: all the values in the domain will be printed at 0 or width:
var svg = d3.select("svg");
var scale = d3.scaleOrdinal()
.domain(["foo", "bar", "baz", "foobar", "foobaz"])
.range([10, 290])
var xAxis = d3.axisBottom(scale);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Solution: An easy alternative is using a band scale (or a point scale, depending on your goals). So, it should be:
var x = d3.scaleBand().range([0, width]);
This is the same code using a band scale:
var svg = d3.select("svg");
var scale = d3.scaleBand()
.domain(["foo", "bar", "baz", "foobar", "foobaz"])
.range([10, 290])
var xAxis = d3.axisBottom(scale);
svg.append("g")
.attr("transform", "translate(0,50)")
.call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
PS: I see that in your code your rectangles have no width. If you decide to use the band scale, you can do:
.attr("width", x.bandwidth())

Maintain highest and lowest values only in Y axis of d3.js Bar graph

i was using the d3.js v4 for making bar graph . i just want only the highest and lowest values as ticks in bar graph
The above graph shows several ticks for given data. it should be only 0 and 7 printed on yaxis removing other values.
Also how can we maintain the data value on each bar.
below is the d3.js code being used
var margin = {top: 20, right: 20, bottom: 70, left: 40}
var data =[
{
"Type_Miss":"High",
"Value_Miss":"5"
},
{
"Type_Miss":"Medium",
"Value_Miss":"1"
},
{
"Type_Miss":"Ignore",
"Value_Miss":"2"
},
{
"Type_Miss":"High",
"Value_Miss":"4"
},
{
"Type_Miss":"High",
"Value_Miss":"7"
},
{
"Type_Miss":"High",
"Value_Miss":"1"
},
{
"Type_Miss":"High",
"Value_Miss":"3"
}];
var width = 650 - margin.left - margin.right
var height = 300 - margin.top - margin.bottom;
var height1 = 400-margin.top - margin.bottom;
var svg = d3.select("#bardiv").append("svg")
.attr("width", width + margin.left + margin.right+60)
.attr("height", height1 + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
.data([data]) ;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = 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.Type_Miss; }));
y.domain([0, d3.max(data, function(d) { return d.Value_Miss; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("dx","0.81em")
.attr("text-anchor", "end");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Type_Miss); })
.attr("y", function(d) { return y(d.Value_Miss); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.Value_Miss); });
Since you want to show only the minimum and the maximum ticks, you can simply use the domain as a getter...
y.domain()
...to set the ticks in the tickValues function. Check this demo:
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
};
var data = [{
"Type_Miss": "High",
"Value_Miss": "5"
}, {
"Type_Miss": "Medium",
"Value_Miss": "1"
}, {
"Type_Miss": "Ignore",
"Value_Miss": "2"
}, {
"Type_Miss": "High",
"Value_Miss": "4"
}, {
"Type_Miss": "High",
"Value_Miss": "7"
}, {
"Type_Miss": "High",
"Value_Miss": "1"
}, {
"Type_Miss": "High",
"Value_Miss": "3"
}];
var width = 650 - margin.left - margin.right
var height = 300 - margin.top - margin.bottom;
var height1 = 400 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right + 60)
.attr("height", height1 + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
.data([data]);
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = 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.Type_Miss;
}));
y.domain([0, d3.max(data, function(d) {
return d.Value_Miss;
})]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).tickValues(y.domain()))
.append("text")
.attr("transform", "rotate(90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("dx", "0.81em")
.attr("text-anchor", "end");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.Type_Miss);
})
.attr("y", function(d) {
return y(d.Value_Miss);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d.Value_Miss);
});
<script src="//d3js.org/d3.v4.min.js"></script>
As an additional information, if you want to show the minimum and the maximum in the data, excluding the zero baseline, just use d3.min and d3.max:
.tickValues([d3.min(data, d => d.Value_Miss), d3.max(data, d => d.Value_Miss)])
Here is the demo:
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
};
var data = [{
"Type_Miss": "High",
"Value_Miss": "5"
}, {
"Type_Miss": "Medium",
"Value_Miss": "1"
}, {
"Type_Miss": "Ignore",
"Value_Miss": "2"
}, {
"Type_Miss": "High",
"Value_Miss": "4"
}, {
"Type_Miss": "High",
"Value_Miss": "7"
}, {
"Type_Miss": "High",
"Value_Miss": "1"
}, {
"Type_Miss": "High",
"Value_Miss": "3"
}];
var width = 650 - margin.left - margin.right
var height = 300 - margin.top - margin.bottom;
var height1 = 400 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right + 60)
.attr("height", height1 + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
.data([data]);
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = 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.Type_Miss;
}));
y.domain([0, d3.max(data, function(d) {
return d.Value_Miss;
})]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).tickValues([d3.min(data, d=>d.Value_Miss),d3.max(data, d=>d.Value_Miss)]))
.append("text")
.attr("transform", "rotate(90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("dx", "0.81em")
.attr("text-anchor", "end");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.Type_Miss);
})
.attr("y", function(d) {
return y(d.Value_Miss);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d.Value_Miss);
});
<script src="//d3js.org/d3.v4.min.js"></script>
One way to do this is to use .tickValues() on your y-axis to explicitly define the tick values. Right now, I have directly added 0 and 7 but you can calculate that outside based on your data.
We can do it like the following when we are appending our y-axis:
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).tickValues([0, 7]))
.append("text")
.attr("transform", "rotate(90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("dx","0.81em")
.attr("text-anchor", "end");
JSFiddle - https://jsfiddle.net/fbus9062/

Rotated x-axis labels cut off in d3.js barchart

I have a bar chart in d3.js. The text of the x-axis labels were too long and overlapping each other so I rotated the x-axis text by adding the following 4 attributes to x axis text:
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)" );
The problem is that the height of the space allocated to the x-axis labels did not expand so now I am only seeing the last few characters of the labels. How can I expand the space allocated to the x-axis labels so that it extends to show all the rotated text?
Here's is the complete d3.js code:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("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 + ")");
d3.csv("segmentcount.csv", type, function(error, data) {
if (error) throw error;
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)" );
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("Count");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.count); })
.attr("height", function(d) { return height - y(d.count); })
.style('fill', function(d) { return '#' + d.colour } );
});
Thanks very much!
Find the maximum label height, and translate the x axis accordingly. (Because the labels are rotated we compare the label widths).
Code snippet to illustrate:
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var data = [
{name: "long name", count: 20},
{name: "name", count: 30},
{name: "even longer name", count: 10},
{name: "long name 4", count: 6},
{name: "long name 5", count: 17},
{name: "long name 6", count: 30},
{name: "long name 7", count: 45}];
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 + ")");
x.domain(data.map(function (d) {
return d.name;
}));
var gXAxis = svg.append("g")
.attr("class", "x axis")
.call(xAxis);
gXAxis.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// Find the maxLabel height, adjust the height accordingly and transform the x axis.
var maxWidth = 0;
gXAxis.selectAll("text").each(function () {
var boxWidth = this.getBBox().width;
if (boxWidth > maxWidth) maxWidth = boxWidth;
});
height = height - maxWidth;
gXAxis.attr("transform", "translate(0," + height + ")");
var y = d3.scale.linear()
.range([height, 0]);
y.domain([0, d3.max(data, function (d) {
return d.count;
})]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
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("Count");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function (d) {
return x(d.name);
})
.attr("width", x.rangeBand())
.attr("y", function (d) {
return y(d.count);
})
.attr("height", function (d) {
return height - y(d.count);
})
.style('fill', "blue");
</script>
</body>
</html>

D3 graph lines overlap when using interpolate in focus+context graph sample

I tried the D3 focus + context graph with some sorted data but the path line overlaps itself. It works properly if I use linear interpolation but when I try to smoothen the graph using monotone or cardinal interpolation, it overlaps. Any clues??
Code:
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = function(d){return new Date(d);};
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
function check(data) {
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
};
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.time);
d.price = +d.count;
return d;
}
data = [
{
"count": 1,
"time": 1387152000000
},
{
"count": 1,
"time": 1390780800000
},
{
"count": 5,
"time": 1390867200000
},
{
"count": 2,
"time": 1390953600000
},
{
"count": 1,
"time": 1391040000000
}];
check(data.map(function(r){return type(r);}));
JSFiddle:
http://jsfiddle.net/v6G8J/4/

Categories