I am trying D3 to develop new barchart. This is my first try to d3
I followed one article Here and based on it I am trying to develop one barchart by writing below code.
My code look like
function get_data() {
console.log("create post is working!") // sanity check
return $.ajax({
url : "/group/guest/query/", // the endpoint
type : "GET", // http method
});
};
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")
.ticks(10, "");
var svg = d3.select("#chart").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 + ")");
var ajdata = get_data();
var k = [];
ajdata.success(function (data) {
var obj = jQuery.parseJSON(data);
obj.forEach(function(d) {
d.created_date = d.created_date;
d.jobs_fail = +d.jobs_fail;
k.push(d.created_date)
});
x.domain(obj.map(function(d) {
return d.date_created;
}));
y.domain([0, d3.max(obj, function(d) {
//alert(JSON.stringify(d.jobs_fail));
return d.jobs_fail;
})]);
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("Count");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.date_created);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.jobs_fail);
})
.attr("height", function(d) {
return height - y(d.jobs_fail);
});
function type(d) {
d.jobs_fail = +d.jobs_fail;
return d;
}
});
I am pulling the data form one ajax request and the ajax response looks like below.
[ { "date": "2017-12-28", "jobs_fail": 2, "jobs_resub": 7, "jobs_success": 18 }, { "date": "2017-12-27", "jobs_fail": 20, "jobs_resub": 31, "jobs_success": 50 }, { "date": "2017-12-26", "jobs_fail": 22, "jobs_resub": 27, "jobs_success": 49 }, { "date": "2017-12-25", "jobs_fail": 11, "jobs_resub": 8, "jobs_success": 18 }, { "date": "2017-12-24", "jobs_fail": 5, "jobs_resub": 2, "jobs_success": 4 }, { "date": "2017-12-23", "jobs_fail": 10, "jobs_resub": 16, "jobs_success": 23 }, { "date": "2017-12-22", "jobs_fail": 51, "jobs_resub": 54, "jobs_success": 97 } ]
When I ran this code I am getting the error.But my x axis dates (created_date) filed data is appearing on chart x axis.
Error: <rect> attribute y: Expected length, "NaN".
I understand this is something on y axis but I am not able to find any solution for it please guide me what might I am doing wrong here.
Hi All after spending lots of time and help from comment I am able to fix this issue.
So problem is in below piece of code.
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.date_created);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.jobs_fail);
})
.attr("height", function(d) {
return height - y(d.jobs_fail);
});
I am storing the parsed data into a variable called obj whereas I am using the data under .data since data has no value so it is not able to attach the values just replace data with obj and it works for me.
Thanks all for your support
Related
I'm working on a D3 data visualization and I'm trying to get my first bar chart to disappear and then have a new one appear exactly where the last one was. My problem is the second one is getting overlayed right above the first one so everything gets muddled up. Any help would be greatly appreciated.
Here is my code:
var data = [{
"name": "text",
"value": 2,
},
{
"name": "text",
"value": 44,
},
{
"name": "text",
"value": 20,
},
{
"name": "text",
"value": 18,
},
{
"name": "text",
"value": 12,
},
{
"name": "text",
"value": 9,
},
{
"name": "text",
"value": 7,
},
{
"name": "text",
"value": 6,
},
{
"name": "text",
"value": 5,
},
{
"name": "text",
"value": 4,
},
];
var margin = {
top: 15,
right: 35,
bottom: 15,
left: 115
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var startBar2010 =
startBarChart.append("g").attr("class","bar2010");
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//.attr("align","center")
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.top + ")");
//.attr("transform", "translate(" + 200 + "," + (-500) + ")");
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);
var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .1)
.domain(data.map(function (d) {
return d.name;
}));
//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("left");
var gy = svg.append("g")
.attr("class", "y axis")
.transition().delay(delay*1).ease(d3.easeLinear).duration(1000)
.call(yAxis);
var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g");
//append rects
bars.append("rect")
.attr("class", "bar")
.attr("x", -500)
.attr("y", -25)
.attr("width", 0)
.attr("height", 35)
.transition().delay(delay*1).ease(d3.easeLinear).duration(1000)
//.transition().delay(delay*1).duration(2500)
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
})
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Do I Work ?");
bars.append("text")
.attr("class", "label")
.attr("y", -42)
.attr("x", -520)
.transition().delay(delay*1).ease(d3.easeLinear).duration(1000)
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});
I thought the following code would clear everything for the follow up bar chart
bars.selectAll("g")
//.transition().delay(delay*3).duration(1000)
.transition().delay(delay*1.7).duration(1000)
.style("opacity",0)
.call(endall, function() {
bars.selectAll("g")
.remove();
});
Here is second bar chart data and chart:
var dataTwo = [{
"name": "text",
"value": 2,
},
{
"name": "text",
"value": 44,
},
{
"name": "text",
"value": 20,
},
{
"name": "text",
"value": 18,
},
{
"name": "text",
"value": 12,
},
{
"name": "text",
"value": 9,
},
{
"name": "text",
"value": 7,
},
{
"name": "text",
"value": 6,
},
{
"name": "text",
"value": 5,
},
{
"name": "text",
"value": 4,
},
];
var margin = {
top: 15,
right: 35,
bottom: 15,
left: 115
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var startBar2010 =
startBarChart.append("g").attr("class","bar2010");
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//.attr("align","center")
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.top + ")");
//.attr("transform", "translate(" + 200 + "," + (-500) + ")");
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(dataTwo, function (d) {
return d.value;
})]);
var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .1)
.domain(dataTwo.map(function (d) {
return d.name;
}));
//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("left");
var gy = svg.append("g")
.attr("class", "y axis")
.transition().delay(delay*2.1).ease(d3.easeLinear).duration(1000)
.call(yAxis);
// Update with new values
var bars = svg.selectAll(".bar")
.data(dataTwo)
.enter()
.append("g");
//append rects
bars.append("rect")
.attr("class", "bar")
.attr("x", -500)
.attr("y", -25)
.attr("width", 0)
.attr("height", 35)
.transition().delay(delay*2.1).ease(d3.easeLinear).duration(1000)
//.transition().delay(delay*1).duration(2500)
//.selection().delay(delay*1).duration(2500)
.attr("y", function (d) {
return y(d.name)
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value)
});
bars.append("text")
.attr("class", "label")
.attr("y", -42)
.attr("x", -520)
.transition().delay(delay*2.1).ease(d3.easeLinear).duration(1000)
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});
Just as the combination of enter().append() is used in D3.js to create DOM elements to reflect dataset elements that don't yet exist in the DOM, likewise the exit().remove() combination is used to remove those DOM elements.
What you will want to do, then, is to have a DOM element acting as a container which you use as the root of your D3 manipulations. Generally, we have a div to which we add the chart's SVG - but you should know which element this is, whether body, a div or something else. Everything that you add into that container, should be removed by 2 steps:
Implementing your exit().remove() as described below.
Clearing your entire dataset currently bound to that set of elements.
This is a useful description. Mike Bostock (D3.js's author) has a diagram clarifying exactly what enter, exit and update mean; "elements" here means "DOM elements", while "data" means "data array elements":
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())
This is my very first to d3js.I have use this d3js Line Chart Sample.But after feeding the data it doesn't draw the chart but i can see the data has been loaded by using the firebug.But the data doesn't print in the graph at all. Could n't figure out the problem.Any help will be really appreciated.
This is My code,
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b").parse;
var x = d3.time.scale()
.range([0, width]);
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 line = d3.svg.line()
.x(function(d) { return x(d.timeStamp);
})
.y(function(d) {return y(d.memberAverageLoadAverage); });
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 + ")");
var json1=[
{
"clusterId": "",
"timeStamp": 1437063744524,
"memberAverageLoadAverage": 20,
"memberId": ""
},
{
"clusterId": "",
"timeStamp": 1437069850060,
"memberAverageLoadAverage": 20,
"memberId": ""
},
{
"clusterId": "",
"timeStamp": 1437069910059,
"memberAverageLoadAverage": 20,
"memberId": ""
},
{
"clusterId": "",
"timeStamp": 1437069970060,
"memberAverageLoadAverage": 20,
"memberId": ""
},
{
"clusterId": "",
"timeStamp": 1437070030056,
"memberAverageLoadAverage": 20,
"memberId": ""
}
];
root = json1;
x.domain(d3.extent(root, function(d) { return d.timeStamp; }));
y.domain(d3.extent(root, function(d) { return d.memberAverageLoadAverage; }));
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("memberAverageLoadAverage");
svg.append("path")
.datum(root)
.attr("class", "line")
.attr("d", line);
After removing the JSON.parse for the JS object and changing the memberAverageLoadAverage to not all be the same value, I was able to display a graph. The reason I needed to change the memberAverageLoadAverage values is that the extent call was making the y axis go from 20 to 20 so the line was at the bottom of the screen and collided with the x axis line. I would suggest setting the y.domain to [0, d3.max(...)] instead of using d3.extent.
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b").parse;
var x = d3.time.scale()
.range([0, width]);
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 line = d3.svg.line()
.x(function(d) { return x(d.timeStamp);
})
.y(function(d) {return y(d.memberAverageLoadAverage); });
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 + ")");
var json1=[{"clusterId":"","timeStamp":1437063744524,"memberAverageLoadAverage":11,"memberId":""},{"clusterId":"","timeStamp":1437069850060,"memberAverageLoadAverage":5,"memberId":""},{"clusterId":"","timeStamp":1437069910059,"memberAverageLoadAverage":6,"memberId":""},{"clusterId":"","timeStamp":1437069970060,"memberAverageLoadAverage":15,"memberId":""},{"clusterId":"","timeStamp":1437070030056,"memberAverageLoadAverage":20,"memberId":""}];
var data = json1;
x.domain(d3.extent(data, function(d) { return d.timeStamp; }));
y.domain([0, d3.max(data, function(d) { return d.memberAverageLoadAverage; })]);
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("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Should be a comment, but I suggest a couple of things. 1. I suggest using externally loaded JSON data if you have a server you can use to get the http request. If not, then you can use local data, but either way you have to have a data.foreach function in which you create all of your values, similar to the oneseen below.
data.foreach(function(d) {
d.timeStamp = d.timeStamp;
d.memberAverageLoadAverage = +d.memberAverageLoadAverage;
});
I also strongly suggest you reformat your JSON because your keys are not done phenomenally well, so I suggest you take a look here and reformat the data. Let me know how you do and what else I can help you with.
I am not sure if you can parse this. It is an array. Anyways, even if you can, I don't think there is a need to parse it.
`var json1=`[{"clusterId":"","timeStamp":1437063744524,"memberAverageLoadAverage":20,"memberId":""},
I am working with Techan JS, with d3 tip plugin.
Callback function of D3-Tip is passed the whole data array instead of object in context. I am probably hooking it on the wrong place.
/* Initialize tooltip */
var tip = d3.tip().attr('class', 'd3-tip').html(function(d) {
console.log(d);
return d;
});
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
timeFormat = d3.time.format('%Y-%m-%d'),
valueFormat = d3.format(',.2fs');
var x = techan.scale.financetime()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var candlestick = techan.plot.candlestick()
.xScale(x)
.yScale(y);
var trendline = techan.plot.trendline()
.xScale(x)
.yScale(y)
.on("mouseenter", enter)
.on("mouseout", out)
.on("drag", drag);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("#candle-stick").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 + ")");
var valueText = svg.append('text')
.style("text-anchor", "end")
.attr("class", "coords")
.attr("x", width - 5)
.attr("y", 15);
var data = [
{ date: "9-Jun-14", open: 62.40, high: 63.34, low: 61.79, close: 62.88, volume: 37617413 },
{ date: "6-Jun-14",open: 63.37, high: 63.48, low: 62.15, close: 62.50,volume: 42442096 },
{ date: "5-Jun-14",open: 63.66, high: 64.36, low: 62.82, close: 63.19,volume: 47352368 },
{ date: "4-Jun-14",open: 62.45, high: 63.59, low: 62.07, close: 63.34,volume: 36513991 },
{ date: "3-Jun-14",open: 62.62, high: 63.42, low: 62.32, close: 62.87,volume: 32216707 },
{ date: "2-Jun-14",open: 63.23, high: 63.59, low: 62.05, close: 63.08,volume: 35995537 },
{ date: "30-May-14",open: 63.95, high: 64.17, low: 62.56, close: 63.30,volume: 45283577 }
];
var accessor = candlestick.accessor();
data = data.slice(0,200).map(function(d) {
return {
date: parseDate(d.date),
open: +d.open,
high: +d.high,
low: +d.low,
close: +d.close,
volume: +d.volume
};
}).sort(function(a, b) { return d3.ascending(accessor.d(a), accessor.d(b)); });
x.domain(data.map(accessor.d));
y.domain(techan.scale.plot.ohlc(data, accessor).domain());
svg.append("g")
.datum(data)
.attr("class", "candlestick")
.call(candlestick)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
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("Price ($)");
/* Invoke the tip in the context of your visualization */
svg.call(tip)
// functions
function enter(d) {
valueText.style("display", "inline");
refreshText(d);
}
function out(d) {
valueText.style("display", "none");
}
You can see the code live at http://jsfiddle.net/sisir/ghox8ewa/1/
(look at the console when hovering on a candlestick)
/* Initialize tooltip */
var tip = d3.tip().attr('class', 'd3-tip').html(function(d) {
console.log(d);
return d;
});
In the above tooltip you are returning d for html, change it to
/* Initialize tooltip */
var tip = d3.tip().attr('class', 'd3-tip').html(function(d, i) {
return d[i].open;//your required text here
});
Hope this is what you are looking for....
If not ask for more.
The problem in the above chart is the approach we are following,
we are drawing candlestick and binding tooltip to this candlestick by writing below code
svg.append("g")
.datum(data)
.attr("class", "candlestick")
.call(candlestick)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
from the above code that will return a 'g' of class 'candlestick'
(to view that write this code
var candle= svg.append("g")
.datum(data)
.attr("class", "candlestick")
.call(candlestick)
console.log(candle);
) and we are binding tooltip to that so it is returning data(whole data object) as argument to our tooltip,
To fulfill our requirement,
I've implemented and developed required code in the below fiddle
http://jsfiddle.net/ghox8ewa/5/
Kindly follow the link and try to analyze....
If you still have doubts ask me for more.
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']); })