I have the following code that nests my data based on region and date. The problem I am having is that I don't know how to define yScale to dynamically draw the axis so that the max sum from the nested data is returned (the max val of the nested data is higher than the max val in the dataset bc it is aggregated). Thus my yAxis is truncated and the chart doesn't show all the data.
In the code, if I hardcode the domain to .domain([0, 3500]) then the axis is correct, but otherwise it is not correct. I don't want to hardcode the domain. How do I reference the nested values?
EDITED to show code provided in comments, which helps but doesn't entirely fix when the script is run on the entire dataset. Please see pic at bottom.
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
return parseInt(d.count,10);
})])
.range([h - padding, padding])
// var yScale = d3.scaleLinear()
// .domain([0, 3500])
// .range([h - padding, padding]) //not supposed to hard code the scale but it is not working
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nested Chart</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
.pagebreak {
page-break-before: always;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.point {
fill: none;
size: 2px
}
.dot {
fill: #ffab00;
stroke: #fff;
}
</style>
</head>
<div style="width:800px; margin:0 auto;" class='body'></div>
<div class="pagebreak"> </div>
<body>
<script type="text/javascript">
var parseTime = d3.timeParse("%Y");
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var padding = 20;
/////////////////get the data//////////////////
const csv = `state,region,year,count
Alabama,South,2010,1
Alabama,South,2011,1
Alabama,South,2012,0
Alabama,South,2013,0
Alabama,South,2014,2
Alabama,South,2015,6
Alaska,West,2010,2245
Alaska,West,2011,1409
Alaska,West,2012,1166
Alaska,West,2013,1329
Alaska,West,2014,1296
Alaska,West,2015,1575
Connecticut,Northeast,2010,0
Connecticut,Northeast,2011,0
Connecticut,Northeast,2012,0
Connecticut,Northeast,2013,0
Connecticut,Northeast,2014,0
Connecticut,Northeast,2015,1
Missouri,Midwest,2010,2
Missouri,Midwest,2011,3
Missouri,Midwest,2012,2
Missouri,Midwest,2013,0
Missouri,Midwest,2014,1
Missouri,Midwest,2015,5
California,West,2010,546
California,West,2012,243
California,West,2013,240
Wyoming,West,2015,198
California,West,2011,195
California,West,2014,191`;
const dataset = d3.csvParse(csv);
dataset.forEach(function(d) {
d.date = parseTime(d.year);
d.region = d['region'];
d.state = d['state'];
d.count = d['count'];
//console.log(d)
});
/////////////////scales the data//////////////////
var xScale = d3.scaleTime()
.domain([d3.min(dataset, function(d) {
return d.date
}), d3.max(dataset, function(d) {
return d.date
})]).range([padding, w - padding * 2])
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
console.log(d.count)
return d.count ///ERROR HERE
})]).range([h - padding, padding])
// var yScale = d3.scaleLinear()
// .domain([0, 3500])
// .range([h - padding, padding]) //not supposed to hard code the scale but it is not working otherwise...commented out above
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
/////////////////charts start here//////////////////
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var svg1 = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Define the line
var valueLine = d3.line()
.x(function(d) {
return xScale(new Date(d.key));
})
.y(function(d) {
return yScale(d.value);
})
var nest = d3.nest()
.key(function(d) {
return d.region;
})
.key(function(d) {
return d.date;
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return (d.count)
});
})
.entries(dataset)
console.log(nest)
// Set the color scheme
var colors = d3.scaleOrdinal()
.domain(["South", "West", "Northeast","Midwest"])
.range(["#EF5285", "#88F284" , "#5965A3","#900C3F"]);
var regYear = svg.selectAll(".regYear")
.data(nest)
.enter()
.append("g")
.attr("stroke", function(d){ return colors(d.key)}); // Adding color!
// console.log(regYear)
var paths = regYear.selectAll(".line")
.data(function(d) {
return [d.values]
})
.enter()
.append("path");
// Draw the line
paths
.attr("d", function(d) {
return valueLine(d)
})
.attr("class", "line")
.style("fill", "none");
svg.selectAll(".dot")
.data(dataset)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d, i) { return xScale(i) })
.attr("cy", function(d) { return yScale(d.count) })//this is not working
.attr("r", 5);
svg.append("g").attr("class", "axis").attr("transform", "translate(0," + (h - padding) + ")").call(xAxis);
//draw Y axis
svg.append("g").attr("class", "axis").attr("transform", "translate(" + padding + ",0)").call(yAxis);
// add label
svg.append("text").attr("x", (w / 2)).attr("y", h + 30).attr("text-anchor", "middle").text("Year");
svg.append("text").attr("x", padding).attr("y", padding - 20).attr("text-anchor", "middle").text("# of Events");
//add title
svg.append("text").attr("x", (w / 2)).attr("y", padding).attr("text-anchor", "middle").text("Events per Year by Category");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("x", w - 65)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100);
////////////////////////////////////END///////////////////////////
</script>
</body>
</html>
UPDATE :
The max value of yAxis is less than the actual max value of the nest data, so it's truncated.
You have to use your nest data inside yScale calculation rather than using the original dataset data.
Steps to achieve this:
define nest first
get the totalMax value by flatting nest twice
use totalMax to calculate the yScale value
var totalMax = Object
.entries(nest)
.reduce(function(totalMax, [key, regionValue]){
const regionMax = Object
.entries(regionValue.values)
.reduce(function(regionMax, [key,yearValue]){
return parseInt(yearValue.value,10) > regionMax ? parseInt(yearValue.value, 10) : regionMax;
}, 0)
return parseInt(regionMax, 10) > totalMax ? parseInt(regionMax, 10) : totalMax;
}, 0)
var yScale = d3.scaleLinear().domain([0, totalMax]).range([h - padding, padding])
I write a Demo base on your code :
var parseTime = d3.timeParse("%Y");
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var padding = 20;
/////////////////get the data//////////////////
const csv = `state,region,year,count
Alabama,South,2010,1
Alabama,South,2011,1
Alabama,South,2012,0
Alabama,South,2013,0
Alabama,South,2014,2
Alabama,South,2015,6
Alaska,West,2010,2245
Alaska,West,2011,1409
Alaska,West,2012,1166
Alaska,West,2013,1329
Alaska,West,2014,1296
Alaska,West,2015,1575
Connecticut,Northeast,2010,0
Connecticut,Northeast,2011,0
Connecticut,Northeast,2012,0
Connecticut,Northeast,2013,0
Connecticut,Northeast,2014,0
Connecticut,Northeast,2015,1
Missouri,Midwest,2010,2
Missouri,Midwest,2011,3
Missouri,Midwest,2012,2
Missouri,Midwest,2013,0
Missouri,Midwest,2014,1
Missouri,Midwest,2015,5
California,West,2010,546
California,West,2012,243
California,West,2013,240
Wyoming,West,2015,198
California,West,2011,195
California,West,2014,191`;
const dataset = d3.csvParse(csv);
dataset.forEach(function(d) {
d.date = parseTime(d.year);
d.region = d['region'];
d.state = d['state'];
d.count = d['count'];
});
var nest = d3.nest()
.key(function(d) {
return d.region;
})
.key(function(d) {
return d.date;
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return parseInt(d.count, 10);
});
})
.entries(dataset)
/////////////////scales the data//////////////////
var xScale = d3.scaleTime()
.domain([d3.min(dataset, function(d) {
return d.date
}), d3.max(dataset, function(d) {
return d.date
})]).range([padding, w - padding * 2])
var totalMax = Object
.entries(nest)
.reduce(function(totalMax, [key, regionValue]){
const regionMax = Object
.entries(regionValue.values)
.reduce(function(regionMax, [key,yearValue]){
return parseInt(yearValue.value,10) > regionMax ? parseInt(yearValue.value, 10) : regionMax;
}, 0)
return parseInt(regionMax, 10) > totalMax ? parseInt(regionMax, 10) : totalMax;
}, 0)
var yScale = d3.scaleLinear()
.domain([0, totalMax]).range([h - padding, padding])
// var yScale = d3.scaleLinear()
// .domain([0, 3500])
// .range([h - padding, padding]) //not supposed to hard code the scale but it is not working otherwise...commented out above
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
/////////////////charts start here//////////////////
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var svg1 = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Define the line
var valueLine = d3.line()
.x(function(d) {
return xScale(new Date(d.key));
})
.y(function(d) {
return yScale(d.value);
})
// Set the color scheme
var colors = d3.scaleOrdinal()
.domain(["South", "West", "Northeast","Midwest"])
.range(["#EF5285", "#88F284" , "#5965A3","#900C3F"]);
var regYear = svg.selectAll(".regYear")
.data(nest)
.enter()
.append("g")
.attr("stroke", function(d){ return colors(d.key)}); // Adding color!
var paths = regYear.selectAll(".line")
.data(function(d) {
return [d.values]
})
.enter()
.append("path");
// Draw the line
paths
.attr("d", function(d) {
return valueLine(d)
})
.attr("class", "line")
.style("fill", "none");
svg.selectAll(".dot")
.data(dataset)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d, i) { return xScale(i) })
.attr("cy", function(d) { return yScale(d.count) })//this is not working
.attr("r", 5);
svg.append("g").attr("class", "axis").attr("transform", "translate(0," + (h - padding) + ")").call(xAxis);
//draw Y axis
svg.append("g").attr("class", "axis").attr("transform", "translate(" + padding + ",0)").call(yAxis);
// add label
svg.append("text").attr("x", (w / 2)).attr("y", h + 30).attr("text-anchor", "middle").text("Year");
svg.append("text").attr("x", padding).attr("y", padding - 20).attr("text-anchor", "middle").text("# of Events");
//add title
svg.append("text").attr("x", (w / 2)).attr("y", padding).attr("text-anchor", "middle").text("Events per Year by Category");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("x", w - 65)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100);
////////////////////////////////////END///////////////////////////
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nested Chart</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
.pagebreak {
page-break-before: always;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.point {
fill: none;
size: 2px
}
.dot {
fill: #ffab00;
stroke: #fff;
}
</style>
</head>
<div style="width:800px; margin:0 auto;" class='body'></div>
<div class="pagebreak"> </div>
<body>
</body>
</html>
I noticed the data type of your d.count is string so that the max won't be correct.
console.log(d3.max(['6','2245'])) // it's 6!
Try converting the value to the number before return it :
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
return parseInt(d.count,10);
})])
.range([h - padding, padding])
To get max value inside nested array you can nest d3.max function in the way like"
var maxCountSum = d3.max(nest, function(d) {
return d3.max(d.values, function (f) {
return f.value
});
});
Then apply to yScale domain:
var yScale = d3.scaleLinear()
.domain([0, maxCountSum]).range([height, 0]);
Related
I'm having issues getting a nested line chart to appear. The data is in the console, but maybe I am missing something crucial. I was following this for reference: https://amber.rbind.io/2017/05/02/nesting/
Possibly I am calling the nested data incorrectly, or maybe i need to append it to the svg? Any help greatly appreciated!
The chart needs to have year on the x-axis, sum of events on the y axis, and each line should be a region.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nested Chart</title>
<script src="../lib/d3.v5.min.js"></script>
<style type="text/css">
.pagebreak { page-break-before: always; }
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.point {
fill:none;
size: 2px
}
</style>
</head>
<div style= "width:800px; margin:0 auto;" class ='body'></div>
<div class="pagebreak"> </div>
<body>
<script type="text/javascript">
var parseTime = d3.timeParse("%Y");
var margin = {top: 20, right: 20, bottom: 30, left: 50},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var padding =20;
/////////////////get the data//////////////////
d3.csv("state-year-earthquakes.csv").then(function(dataset) {
dataset.forEach(function(d) {
d.date = parseTime(d.year);
d.region = d['region'];
d.state = d['state'];
d.count = d['count'];
//console.log(d)
});
/////////////////scales the data//////////////////
var xScale = d3.scaleTime()
.domain([d3.min(dataset,function (d) { return d.date }),d3.max(dataset,function (d) { return d.date }) ]).range([padding, w - padding * 2])
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset,function (d) { return d.count }) ]).range([h- padding, padding])
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
/////////////////charts start here//////////////////
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Define the line
var valueLine = d3.line()
.x(function(d) { return xScale(d.date); })
.y(function(d) { return yScale(+d.count); })
var nest = d3.nest()
.key(function(d){
return d.region;
})
.key(function(d){
return d.date;
})
.rollup(function(leaves){
return d3.sum(leaves, function(d) {return (d.count)});
})
.entries(dataset)
var color = d3.scaleOrdinal(d3.schemeCategory10); // set the colour scale
console.log(nest)
var regYear = svg.selectAll(".regYear")
.data(nest)
.enter()
.append("g")
// console.log(regYear)
var paths = regYear.selectAll(".line")
.data(function(d){
return d.values
})
.enter()
.append("path");
console.log(paths)
// Draw the line
paths
.attr("d", function(d){
return d.values
})
.attr("class", "line")
svg.append("g").attr("class", "axis").attr("transform", "translate(0," + (h - padding) + ")").call(xAxis);
//draw Y axis
svg.append("g").attr("class", "axis").attr("transform", "translate(" + padding + ",0)").call(yAxis);
// add label
svg.append("text").attr("x", (w/2)).attr("y", h+30).attr("text-anchor", "middle").text("Year");
svg.append("text").attr("x", padding).attr("y", padding-20).attr("text-anchor", "middle").text("# of Events");
//add title
svg.append("text").attr("x", (w/2)).attr("y", padding).attr("text-anchor", "middle").text("Events per Year by Category");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("x", w - 65)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100);
////////////////////////////////////END///////////////////////////
} );
</script>
</body>
</html>
data.csv
state,region,year,count
Alabama,South,2010,1
Alabama,South,2011,1
Alabama,South,2012,0
Alabama,South,2013,0
Alabama,South,2014,2
Alabama,South,2015,6
Alaska,West,2010,2245
Alaska,West,2011,1409
Alaska,West,2012,1166
Alaska,West,2013,1329
Alaska,West,2014,1296
Alaska,West,2015,1575
Connecticut,Northeast,2010,0
Connecticut,Northeast,2011,0
Connecticut,Northeast,2012,0
Connecticut,Northeast,2013,0
Connecticut,Northeast,2014,0
Connecticut,Northeast,2015,1
Missouri,Midwest,2010,2
Missouri,Midwest,2011,3
Missouri,Midwest,2012,2
Missouri,Midwest,2013,0
Missouri,Midwest,2014,1
Missouri,Midwest,2015,5
You have a couple of problems. First, you're not using your line generator. It should be:
.attr("d", function(d) {
return valueLine(d)
})
Second, you are parsing the date strings, but then converting them to strings again. So, change your line generator (or do not use them as a key, which returns a string):
var valueLine = d3.line()
.x(function(d) {
return xScale(new Date(d.key));
})
.y(function(d) {
return yScale(d.value);
})
Finally, each datum for the line generator must be an array itself. So:
var paths = regYear.selectAll(".line")
.data(function(d) {
return [d.values]
})
Here is your code with those changes (and a little CSS for the paths):
path {
fill: none;
stroke: black;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nested Chart</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<style type="text/css">
.pagebreak {
page-break-before: always;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.point {
fill: none;
size: 2px
}
</style>
</head>
<div style="width:800px; margin:0 auto;" class='body'></div>
<div class="pagebreak"> </div>
<body>
<script type="text/javascript">
var parseTime = d3.timeParse("%Y");
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var padding = 20;
/////////////////get the data//////////////////
const csv = `state,region,year,count
Alabama,South,2010,1
Alabama,South,2011,1
Alabama,South,2012,0
Alabama,South,2013,0
Alabama,South,2014,2
Alabama,South,2015,6
Alaska,West,2010,2245
Alaska,West,2011,1409
Alaska,West,2012,1166
Alaska,West,2013,1329
Alaska,West,2014,1296
Alaska,West,2015,1575
Connecticut,Northeast,2010,0
Connecticut,Northeast,2011,0
Connecticut,Northeast,2012,0
Connecticut,Northeast,2013,0
Connecticut,Northeast,2014,0
Connecticut,Northeast,2015,1
Missouri,Midwest,2010,2
Missouri,Midwest,2011,3
Missouri,Midwest,2012,2
Missouri,Midwest,2013,0
Missouri,Midwest,2014,1
Missouri,Midwest,2015,5`;
const dataset = d3.csvParse(csv);
dataset.forEach(function(d) {
d.date = parseTime(d.year);
d.region = d['region'];
d.state = d['state'];
d.count = d['count'];
//console.log(d)
});
/////////////////scales the data//////////////////
var xScale = d3.scaleTime()
.domain([d3.min(dataset, function(d) {
return d.date
}), d3.max(dataset, function(d) {
return d.date
})]).range([padding, w - padding * 2])
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
return d.count
})]).range([h - padding, padding])
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
/////////////////charts start here//////////////////
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Define the line
var valueLine = d3.line()
.x(function(d) {
return xScale(new Date(d.key));
})
.y(function(d) {
return yScale(d.value);
})
var nest = d3.nest()
.key(function(d) {
return d.region;
})
.key(function(d) {
return d.date;
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return (d.count)
});
})
.entries(dataset)
var color = d3.scaleOrdinal(d3.schemeCategory10); // set the colour scale
var regYear = svg.selectAll(".regYear")
.data(nest)
.enter()
.append("g")
// console.log(regYear)
var paths = regYear.selectAll(".line")
.data(function(d) {
return [d.values]
})
.enter()
.append("path");
// Draw the line
paths
.attr("d", function(d) {
return valueLine(d)
})
.attr("class", "line")
svg.append("g").attr("class", "axis").attr("transform", "translate(0," + (h - padding) + ")").call(xAxis);
//draw Y axis
svg.append("g").attr("class", "axis").attr("transform", "translate(" + padding + ",0)").call(yAxis);
// add label
svg.append("text").attr("x", (w / 2)).attr("y", h + 30).attr("text-anchor", "middle").text("Year");
svg.append("text").attr("x", padding).attr("y", padding - 20).attr("text-anchor", "middle").text("# of Events");
//add title
svg.append("text").attr("x", (w / 2)).attr("y", padding).attr("text-anchor", "middle").text("Events per Year by Category");
// add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("x", w - 65)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100);
////////////////////////////////////END///////////////////////////
</script>
</body>
</html>
I am plotting a bar chart in D3.js (Version 3). Which has two axis, one is receive_data and another one is responses. I have a JSON file where I stored the data. JSON format looks like,
[{"receive_date":"2013-11-04","responses":"2"}]
In my JSON, I have two responses values for the same date 2013-11-04 .
Like,
[{"receive_date":"2013-11-04","responses":"2"},{"receive_date":"2013-11-04","responses":"8668"}
This is the JSON Source :- https://api.myjson.com/bins/gdpu7
So, when I am plotting the graph, it is not taking the sum of the values for the same receive_date instead it is showing two times. I want it to show the sum of responses. responses should be (8668+2) for the receive_date 2013-11-04
I also found it that by using reduce we can do this. I tried to use d3.json.reduce . But it is showing error d3.json.reduce is not a function.
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// scale to ordinal because x axis is not numerical
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
//scale to numerical value by height
var y = d3.scale.linear().range([height, 0]);
var chart = d3.select("#chart")
.append("svg") //append svg element inside #chart
.attr("width", width + (2 * margin.left) + margin.right) //set width
.attr("height", height + margin.top + margin.bottom); //set height
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom"); //orient bottom because x-axis will appear below the bars
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
d3.json("https://api.myjson.com/bins/gdpu7", function(error, data) {
x.domain(data.map(function(d) {
return d.receive_date
}));
y.domain([0, d3.max(data, function(d) {
return d.responses
})]);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(" + x(d.receive_date) + ", 0)";
});
bar.append("rect")
.attr("y", function(d) {
return y(d.responses);
})
.attr("x", function(d, i) {
return x.rangeBand() + (margin.left / 2);
})
.attr("height", function(d) {
return height - y(d.responses);
})
.attr("width", x.rangeBand()); //set width base on range on ordinal data
bar.append("text")
.attr("x", x.rangeBand() + margin.left)
.attr("y", function(d) {
return y(d.responses) - 10;
})
.attr("dy", ".75em")
.text(function(d) {
return d.responses;
});
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margin.left + "," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("responses");
});
function type(d) {
d.receive_date = +d.receive_date; // coerce to number
return d;
}
#chart rect {
fill: #4aaeea;
}
#chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #fff;
shape-rendering: crispEdges;
}
body {
background: #1a1a1a;
color: #eaeaea;
padding: 10px;
}
<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>
<div id="chart"></div>
JSfiddle :- https://jsfiddle.net/bL9940at/
The relevant part:
var array1 = data; //input
var array2 = [];
var last_d;
array1.reduce(function (accumulator, currentValue, i) {
var r = Number(currentValue.responses),
d = currentValue.receive_date;
if (d == last_d) r += accumulator;
array2[i] = {
receive_date: d,
responses: r
};
last_d = d;
return accumulator + Number(currentValue.responses);
}, 0);
data = array2; //output
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// scale to ordinal because x axis is not numerical
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
//scale to numerical value by height
var y = d3.scale.linear().range([height, 0]);
var chart = d3.select("#chart")
.append("svg") //append svg element inside #chart
.attr("width", width + (2 * margin.left) + margin.right) //set width
.attr("height", height + margin.top + margin.bottom); //set height
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom"); //orient bottom because x-axis will appear below the bars
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
d3.json("https://api.myjson.com/bins/gdpu7", function(error, data) {
//create new arrays
var array1 = data; //input
var array2 = [];
var last_d;
array1.reduce(function (accumulator, currentValue, i) {
var r = Number(currentValue.responses),
d = currentValue.receive_date;
if (d == last_d) r += accumulator;
array2[i] = {
receive_date: d,
responses: r
};
last_d = d;
return accumulator + Number(currentValue.responses);
}, 0);
data = array2; //output
x.domain(data.map(function(d) {
return d.receive_date;
}));
y.domain([0, d3.max(data, function(d) {
return d.responses;
})*1.1]);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(" + x(d.receive_date) + ", 0)";
});
bar.append("rect")
.attr("y", function(d) {
return y(d.responses);
})
.attr("x", function(d, i) {
return x.rangeBand() + (margin.left / 2);
})
.attr("height", function(d) {
return height - y(d.responses);
})
.attr("width", x.rangeBand()); //set width base on range on ordinal data
bar.append("text")
.attr("x", x.rangeBand() + margin.left)
.attr("y", function(d) {
return y(d.responses) - 10;
})
.attr("dy", ".75em")
.text(function(d) {
return d.responses;
});
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margin.left + "," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("responses");
});
function type(d) {
d.receive_date = +d.receive_date; // coerce to number
return d;
}
#chart rect {
fill: #4aaeea;
}
#chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #fff;
shape-rendering: crispEdges;
}
body {
background: #1a1a1a;
color: #eaeaea;
padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-git.js"></script>
<div id="chart"></div>
</body>
</html>
Trying to implement border for selected bar in d3 stack bar chart. Here the first bar's top border goes behind second bar a little bit. How to avoid this?
var svg, height, width, margin, parentWidth, parentHeight;
// container size
parentWidth = 700;
parentHeight = 500;
margin = {top: 50, right: 20, bottom: 35, left: 30};
width = parentWidth - margin.left - margin.right;
height = parentHeight - margin.top - margin.bottom;
var selectedSection = window.sessionStorage.getItem('selectedSection');
// data
var dataset = [{"label":"DEC","Set Up":{"count":12,"id":1,"label":"Set Up","year":"2016","graphType":"setup"},"Not Set Up":{"count":12,"id":0,"label":"Not Set Up","year":"2016","graphType":"setup"}},{"label":"JAN","Set Up":{"count":6,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":21,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"FEB","Set Up":{"count":1,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":2,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"MAR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"APR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}}];
// x cord
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.2);
// color helper
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
// x axis
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom');
var colors = ['#50BEE9', '#30738C'];
// Set SVG
svg = d3.select('#chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom )
.attr('class', 'setup')
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== 'label'; }));
dataset.forEach(function(d) {
var y0 = 0;
d.values = color.domain().map(function(name) {
return {
name: name,
y0: y0,
y1: y0 += +d[name].count,
patientStatus:d[name].id,
graphType:d[name].graphType,
fromDate:{
month:d.label,
year:d[name].year
},
toDate:{
month:d.label,
year:d[name].year
}
};
});
d.total = d.values[d.values.length - 1].y1;
});
var y = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.total;
})])
.range([height, 0]);
var ticks = y.ticks(),
lastTick = ticks[ticks.length-1];
var newLastTick = lastTick + (ticks[1] - ticks[0]);
if (lastTick<y.domain()[1]){
ticks.push(lastTick + (ticks[1] - ticks[0]));
}
// adjust domain for further value
y.domain([y.domain()[0], newLastTick]);
// y axis
var yAxis = d3.svg.axis()
.scale(y)
.orient('left')
.tickSize(-width, 0, 0)
.tickFormat(d3.format('d'))
.tickValues(ticks);
x.domain(dataset.map(function(d) { return d.label; }));
y.domain([0, d3.max(dataset, function(d) { return d.total; })]);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
var bar = svg.selectAll('.label')
.data(dataset)
.enter().append('g')
.attr('class', 'g')
.attr('id', function(d, i) {
return i;
})
.attr('transform', function(d) { return 'translate(' + x(d.label) + ',0)'; });
var barEnter = bar.selectAll('rect')
.data(function(d) { return d.values; })
.enter();
barEnter.append('rect')
.attr('width', x.rangeBand())
.attr('y', function(d) {
return y(d.y1);
})
.attr('class', function(d, i){
return 'bar';
})
.attr('height', function(d) { return y(d.y0) - y(d.y1); })
.style('fill', function(d,i) { return colors[i]; })
.on('click', function(d, i) {
d3.selectAll('.bar').classed('selected', false);
d3.select(this)
.classed('bar selected', true);
});
barEnter.append('text')
.text(function(d) {
var calcH = y(d.y0) - y(d.y1);
var inText = (d.y1-d.y0);
if(calcH >= 20) {
return inText;
} else {
return '';
}
})
.attr('class','inner-text')
.attr('y', function(d) { return y(d.y1)+(y(d.y0) - y(d.y1))/2 + 5; })
.attr('x', function(){
return (x.rangeBand()/2) - 10;
});
svg
.select('.y')
.selectAll('.tick')
.filter(function (d) {
return d % 1 !== 0;
})
.style('display','none');
svg
.select('.y')
.selectAll('.tick')
.filter(function (d) {
return d === 0;
})
.select('text')
.style('display','none');
JSFiddle
JSFiddle with d3 v4
In a SVG, just like a real painter putting ink to a white canvas, the element that is painted last stays on top.
Right now, the behaviour you're seeing is the expected one, because each stacked bar (rectangle) is in a different <g> element, and the groups, of course, have a given order in the SVG structure.
The solution involves just one line:
d3.select(this.parentNode).raise();
What this line does is selecting the group of the clicked rectangle and raising it (that is, moving it down in the DOM tree), so that group will be on top of all others. According to the API, raise():
Re-inserts each selected element, in order, as the last child of its parent. (emphasis mine)
"Moving down", "be on top" and "be the last child" may be a bit confusing and seem contradictory, but here is the explanation. Given this SVG structure:
<svg>
<foo></foo>
<bar></bar>
<baz></baz>
</svg>
<baz>, being the last element, is the one painted last, and it is the element visually on the top in the SVG. So, raising an element means moving it down in the SVG tree structure, but moving it up visually speaking.
Here is your updated fiddle: https://jsfiddle.net/86Lgaupt/
PS: I increased the stroke-width just to make visibly clear that the clicked rectangle is now on top.
Tag:
<div id='stacked-bar'></div>
Script:
var initStackedBarChart = {
draw: function(config) {
me = this,
domEle = config.element,
stackKey = config.key,
data = config.data,
margin = {top: 20, right: 20, bottom: 30, left: 50},
parseDate = d3.timeParse("%m/%Y"),
width = 550 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
xScale = d3.scaleBand().range([0, width]).padding(0.1),
yScale = d3.scaleLinear().range([height, 0]),
color = d3.scaleOrdinal(d3.schemeCategory20),
xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%b")),
yAxis = d3.axisLeft(yScale),
svg = d3.select("#"+domEle).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top+10 + margin.bottom+10)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var stack = d3.stack()
.keys(stackKey)
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone);
var layers= stack(data);
data.sort(function(a, b) { return b.total - a.total; });
xScale.domain(data.map(function(d) { return parseDate(d.date); }));
yScale.domain([0, d3.max(layers[layers.length - 1], function(d) { return d[0] + d[1]; }) ]).nice();
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) { return color(i); });
layer.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr('class', 'bar')
.attr("x", function(d) { return xScale(parseDate(d.data.date)); })
.attr("y", function(d) { return yScale(d[1]); })
.attr("height", function(d) { return yScale(d[0]) - yScale(d[1]) -1; })
.attr("width", xScale.bandwidth())
.on('click', function(d, i) {
d3.selectAll('.bar').classed('selected', false);
d3.select(this).classed('selected', true);
});
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height+5) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(0,0)")
.call(yAxis);
}
}
var data = [
{"date":"4/1854","total":45,"disease":12,"wounds":14,"other":25},
{"date":"5/1854","total":23,"disease":12,"wounds":0,"other":9},
{"date":"6/1854","total":38,"disease":11,"wounds":0,"other":6},
{"date":"7/1854","total":26,"disease":11,"wounds":8,"other":7}
];
var key = ["wounds", "other", "disease"];
initStackedBarChart.draw({
data: data,
key: key,
element: 'stacked-bar'
});
Css:
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis--x path {
display: none;
}
.path-line {
fill: none;
stroke: yellow;
stroke-width: 1.5px;
}
svg {
background: #f0f0f0;
}
.selected{
stroke:#333;
stroke-width:2;
}
I'm trying to figure out how to get two d3 graphs onto the same page with one on the left and one on the right. However, what I'm getting is this.
This is my html file.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.polyline path {
fill: none;
stroke: #666;
shape-rendering: crispEdges;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
cursor: move;
}
.xaxis text {
font: 10px sans-serif;
}
.yaxis text {
font: 10px sans-serif;
}
.xaxis path,
.xaxis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.yaxis path,
.yaxis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<svg class="chart"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src = "project3.js">//https://my.up.ist.psu.edu/lng5099/project3.html </script>
</body>
</html>
This is my js file.
(function() {
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangePoints([0, width], 1),
y = {};
var axis = d3.svg.axis().orient("left");
var line = d3.svg.line() //define a function to convert points into a polyline
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");//line style. you can try "cardinal".
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var cars=[];
d3.csv("cars.csv", type, function(error, data) {
cars = data;
drawPC();
});
function drawPC() {
// Extract the list of dimensions and create a scale for each.
for (var dim in cars[0]) {
if (dim != "name") {
y[dim] = d3.scale.linear()
.domain([d3.min(cars, function(d) { return +d[dim]; }), d3.max(cars, function(d) { return +d[dim]; })])
.range([height,0]);
}
}
x.domain(dimensions = d3.keys(cars[0]).filter(function(d) { return d != "name";}));
//draw polylines
for (var i=1; i< cars.length; i++) { //for each car
//prepare the coordinates for a polyline
var lineData = []; //initialize an array for coordinates of a polyline
for (var prop in cars[0]) { //get each dimension
if (prop != "name" ) { //skip the name dimension
var point = {}; //initialize a coordinate object
var val = cars[i][prop]; //obtain the value of a car in a dimension
point['x'] = x(prop); //x value: mapping the dimension
point['y'] = y[prop](val);//y value: mapping the value in that dimension
lineData.push(point); //add the object into the array
}
}
//draw a polyline based on the coordindates
chart.append("g")
.attr("class", "polyline")
.append("path") // a path shape
.attr("d", line(lineData)); //line() is a function to turn coordinates into SVG commands
}
//next: draw individual dimension lines
//position dimension lines appropriately
var g = chart.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; }); //translate each axis
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.style("text-anchor", "middle")
.attr("y", -9)
.text(function(d) { return d; });
};
//this function coerces numerical data to numbers
function type(d) {
d.economy = +d.economy; // coerce to number
d.displacement = +d.displacement; // coerce to number
d.power = +d.power; // coerce to number
d.weight = +d.weight; // coerce to number
d.year = +d.year;
return d;
}
})();
(function() {
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear().range([50, width]),
y = d3.scale.linear().range([height-20,0]);
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var cars=[];
d3.csv("cars.csv", type, function(error, data) {
cars = data;
drawXY();
});
function drawXY(){
x.domain([d3.min(cars, function(d) { return d.year; }), d3.max(cars, function(d) { return d.year; })]);
y.domain([d3.min(cars, function(d) { return d.power; }), d3.max(cars, function(d) { return d.power; })]);
var yPos = height -20;
chart.append("g")
.attr("class", "xaxis")
.attr("transform", "translate(0," + yPos + ")")
.call(xAxis);
chart.append("g")
.attr("class", "yaxis")
.attr("transform", "translate(50,0)")
.call(yAxis);
chart.selectAll(".dot")
.data(cars)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.power); })
.attr("r", 3);
}
d3.selectAll("circle").data(cars).enter()
.append("circle")
.classed("circle", true)
.on("mouseover", function() { d3.select(d3.event.target).classed("highlight", true); })
.on("mouseout", function() { d3.select(d3.event.target).classed("highlight", false); });
function type(d) {
d.economy = +d.economy; // coerce to number
d.displacement = +d.displacement; // coerce to number
d.power = +d.power; // coerce to number
d.weight = +d.weight; // coerce to number
d.year = +d.year;
return d;
}
})();
Both are displaying, but I'm not sure how set it so that they position properly. Please help.
Figured it out there was an issue with the positioning of my margins, width and height. There is the java code for anyone who needs the help.
(function() {
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 700 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangePoints([0, width], 1),
y = {};
var axis = d3.svg.axis().orient("left");
var line = d3.svg.line() //define a function to convert points into a polyline
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");//line style. you can try "cardinal".
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var cars=[];
d3.csv("cars.csv", type, function(error, data) {
cars = data;
drawPC();
});
function drawPC() {
// Extract the list of dimensions and create a scale for each.
for (var dim in cars[0]) {
if (dim != "name") {
y[dim] = d3.scale.linear()
.domain([d3.min(cars, function(d) { return +d[dim]; }), d3.max(cars, function(d) { return +d[dim]; })])
.range([height,0]);
}
}
x.domain(dimensions = d3.keys(cars[0]).filter(function(d) { return d != "name";}));
//draw polylines
for (var i=1; i< cars.length; i++) { //for each car
//prepare the coordinates for a polyline
var lineData = []; //initialize an array for coordinates of a polyline
for (var prop in cars[0]) { //get each dimension
if (prop != "name" ) { //skip the name dimension
var point = {}; //initialize a coordinate object
var val = cars[i][prop]; //obtain the value of a car in a dimension
point['x'] = x(prop); //x value: mapping the dimension
point['y'] = y[prop](val);//y value: mapping the value in that dimension
lineData.push(point); //add the object into the array
}
}
//draw a polyline based on the coordindates
chart.append("g")
.attr("class", "polyline")
.append("path") // a path shape
.attr("d", line(lineData)); //line() is a function to turn coordinates into SVG commands
}
//next: draw individual dimension lines
//position dimension lines appropriately
var g = chart.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; }); //translate each axis
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.style("text-anchor", "middle")
.attr("y", -9)
.text(function(d) { return d; });
};
//this function coerces numerical data to numbers
function type(d) {
d.economy = +d.economy; // coerce to number
d.displacement = +d.displacement; // coerce to number
d.power = +d.power; // coerce to number
d.weight = +d.weight; // coerce to number
d.year = +d.year;
return d;
}
})();
(function() {
var margin = {top: 20, right: 30, bottom: 30, left: 690},
width = 1300 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var x = d3.scale.linear().range([50, width]),
y = d3.scale.linear().range([height-20,0]);
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var cars=[];
d3.csv("cars.csv", type, function(error, data) {
cars = data;
drawXY();
});
function drawXY(){
x.domain([d3.min(cars, function(d) { return d.year; }), d3.max(cars, function(d) { return d.year; })]);
y.domain([d3.min(cars, function(d) { return d.power; }), d3.max(cars, function(d) { return d.power; })]);
var yPos = height -20;
chart.append("g")
.attr("class", "xaxis")
.attr("transform", "translate(0," + yPos + ")")
.call(xAxis);
chart.append("g")
.attr("class", "yaxis")
.attr("transform", "translate(50,0)")
.call(yAxis);
chart.selectAll(".dot")
.data(cars)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.power); })
.attr("r", 3);
}
d3.selectAll("circle").data(cars).enter()
.append("circle")
.classed("circle", true)
.on("mouseover", function() { d3.select(d3.event.target).classed("highlight", true); })
.on("mouseout", function() { d3.select(d3.event.target).classed("highlight", false); });
function type(d) {
d.economy = +d.economy; // coerce to number
d.displacement = +d.displacement; // coerce to number
d.power = +d.power; // coerce to number
d.weight = +d.weight; // coerce to number
d.year = +d.year;
return d;
}
})();
I wanted to use the Sortable Bar Chart of Mike Bostock without it's transition property and sort the bars according to their lenght but I couldn't. I want the bars just like this. without interactivity.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>
body {
font: 10px sans-serif;
}
.bar rect {
fill: steelblue;
}
.bar text {
fill: white;
}
.axis path, .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
</style>
<script src="http://mbostock.github.com/d3/d3.js"></script>
<script>
var margin = {top: 0, right: 10, bottom: 20, left: 10},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var index = d3.range(24),
data = index.map(d3.random.normal(100, 10));
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, width]);
var y = d3.scale.ordinal()
.domain(index)
.rangeRoundBands([0, height], .1);
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 bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });
bar.append("rect")
.attr("height", y.rangeBand())
.attr("width", x);
bar.append("text")
.attr("text-anchor", "end")
.attr("x", function(d) { return x(d) - 6; })
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.text(function(d, i) { return i; });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis()
.scale(x)
.orient("bottom"));
//var sort = false;
//setInterval(function() {
// if (sort = !sort) {
// index.sort(function(a, b) { return data[a] - data[b]; });
// } else {
// index = d3.range(24);
// }
// y.domain(index);
// bar.transition()
// .duration(750)
// .delay(function(d, i) { return i * 50; })
// .attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });
//}, 5000);
var hierarchy = d3.layout.partition()
.data(function(d) { return d.data; });
</script>
I removed the the code from var sort = false; part and added
var hierarchy =.. part but It's still not working. How can I make it?
Any help will be appreciated.
Thanks.
You should add the following line to sort the values:
index.sort(function(a, b) { return data[b] - data[a]; });
Check out the jsfiddle: http://jsfiddle.net/k9rcyeyo/