I'm working on d3.js v4 and im trying to load external data from data.tsv file but its not loading, here is my code:
var bardata = [];
d3.tsv('data.tsv', function(){
for (key in data){
bardata.push(data[key].year.value)
}
var margin = {top:30, right:30, bottom:40, left:50}
var height = 400 - margin.top - margin.bottom,
width = 400 - margin.left - margin.right,
barWidth = 50,
barOffset = 5;
var tempColor;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleBand()
.domain(d3.range(0, bardata.length))
.padding(0.1)
.range([0, width]);
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('#chart').append('svg')
.style('background', '#E7E0CB')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d){
d3.select(this)
.style('opacity', 0.5)
})
.on('mouseleave', function(d){
d3.select(this)
.style('opacity', 1)
})
.on('mouseover', function(d){
tooltip.transition()
.style('opacity', 0.9)
tooltip.html(d)
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 0.5)
.style('fill', 'yellow')
})
.on('mouseleave', function(d){
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 1)
.style('fill', '#C61C6F')
})
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease(d3.easeElastic)
var vGuideScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var vAxis = d3.axisLeft(vGuideScale).ticks(10)
var vGuide = d3.select('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
var hAxis = d3.axisBottom(xScale).tickValues(xScale.domain().filter(function(d,i){
return !(i % (bardata.length/5))
}))
var hGuide = d3.select('svg').append('g')
hAxis(hGuide)
hGuide.attr('transform', 'translate('+ margin.left +', '+ (height + margin.top) +')')
});
<!DOCTYPE html>
<html>
<head>
<title>Bar Chart</title>
<meta charset="8-UTF">
<link rel="stylesheet" src="css/style.css"> </head>
<body>
<div class="container">
<h2>Bar Chart</h2>
<div id="chart"></div>
</div>
<script src="js/d3.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
and here is the data in my tsv file
year value
2010 23,499,201
2011 22,544,175
2012 24,061,655
2013 23,413,369
2014 27,144,494
2015 26,812,665
2016 30,377,832
its has no errors but nothing appears on the chart
The way you're trying to create your bar chart right now, getting rid of the nice array of objects d3.tsv creates for you and relying in a simple array of numbers, is not the adequate let alone the most convenient way to do it. For any seasoned D3 coder, it makes little sense. However, it's not my place giving lectures here.
That being said, I'll address only the current problems:
d3.tsv needs a parameter in the callback:
d3.tsv('data.tsv', function(data){
//parameter here -------------^
Don't put comma in your numbers. This is not accepted in any programming language I'm aware of:
23,499,201 ---> 23499201
Remember, as I said in your last question, to avoid the columns property:
for (key in data) {
if (key != "columns") bardata.push(data[key].value)
}
Convert the strings to numbers:
bardata.push(+data[key].value)
All together, this is your working code:
var data = d3.tsvParse(d3.select("#tsv").text());
var bardata = [];
for (key in data){
if(key != "columns") bardata.push(+data[key].value)
}
var margin = {top:30, right:30, bottom:40, left:50}
var height = 400 - margin.top - margin.bottom,
width = 400 - margin.left - margin.right,
barWidth = 50,
barOffset = 5;
var tempColor;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleBand()
.domain(d3.range(0, bardata.length))
.padding(0.1)
.range([0, width]);
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('body').append('svg')
.style('background', '#E7E0CB')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d){
d3.select(this)
.style('opacity', 0.5)
})
.on('mouseleave', function(d){
d3.select(this)
.style('opacity', 1)
})
.on('mouseover', function(d){
tooltip.transition()
.style('opacity', 0.9)
tooltip.html(d)
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 0.5)
.style('fill', 'yellow')
})
.on('mouseleave', function(d){
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 1)
.style('fill', '#C61C6F')
})
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease(d3.easeElastic)
var vGuideScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var vAxis = d3.axisLeft(vGuideScale).ticks(10)
var vGuide = d3.select('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate('+ margin.left +', '+ margin.top +')')
var hAxis = d3.axisBottom(xScale).tickValues(xScale.domain().filter(function(d,i){
return !(i % (bardata.length/5))
}))
var hGuide = d3.select('svg').append('g')
hAxis(hGuide)
hGuide.attr('transform', 'translate('+ margin.left +', '+ (height + margin.top) +')')
pre{
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="tsv">year value
2010 23499201
2011 22544175
2012 24061655
2013 23413369
2014 27144494
2015 26812665
2016 30377832
</pre>
Again: I'm using a <pre> element to store the data. Don't simply copy/paste my snippet, as you did last time.
Related
I do not know why the tooltip does not appear. Here is my code:
// set the dimensions and margins of the graph
var margin = { top: 20, right: 30, bottom: 50, left: 90 }
var width = 460 - margin.left - margin.right
var height = 2000 - margin.top - margin.bottom;
const dataUrl = "https://raw.githubusercontent.com/yushinglui/IV/main/course_distance_v2.csv"
//fetch the data
d3.csv(dataUrl)
.then((data) => {
// append the svg object to the body of the page
var svg = d3.select("#graph-1")
.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 + ")");
// Add X axis
var x = d3.scaleLinear()
.domain([0, 60])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([0, height])
.domain(data.map(function (d) { return d.CourseCode; }))
.padding(0.1);
svg.append("g")
.call(d3.axisLeft(y))
// create tooltip element
const tooltip = d3.select("body")
.append("div")
.attr("class", "d3-tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("padding", "15px")
.style("background", "rgba(0,0,0,0.6)")
.style("border-radius", "5px")
.style("color", "#fff")
.text("a simple tooltip");
//Bars
let bars = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", function (d) { return 1; })
.attr("y", function (d) { return y(d.CourseCode); })
.attr("width", function (d) { return x(d.AverageDistance); })
.attr("height", function (d) { return y.bandwidth(); })
.attr("fill", "orange");
.on("mouseover", function (d, i) {
tooltip.html(`CourseName: ${d.CourseName}`).style("visibility", "visible");
d3.select(this)
.attr("fill", "orangered");
})
.on("mousemove", function () {
tooltip
.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px");
})
.on("mouseout", function () {
tooltip.html(``).style("visibility", "hidden");
d3.select(this).attr("fill", "orange");
});
//axis labels
svg.append('text')
.attr('x', -(height / 2))
.attr('y', width - 410)
.attr('transform', 'rotate(-90)')
.attr('text-anchor', 'middle')
.text('Course Code');
svg.append('text')
.attr('x', 150)
.attr('y', 1970)
.attr('transform', 'rotate()')
.attr('text-anchor', 'middle')
.text('Average Distance (Miles)');
//text labels on bars
svg.selectAll(null)
.data(data)
.enter()
.append("text")
.text(function (d) { return d.AverageDistance; })
.attr("x", function (d) { return x(d.AverageDistance) + 15; })
.attr("y", function (d) { console.log(d); return y(d.CourseCode) + y.bandwidth() * (0.5 + 0.1); })
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "black")
.attr("text-anchor", "middle");
})
my reference website:
https://perials.github.io/responsive-bar-chart-with-d3/
https://observablehq.com/#bsaienko/animated-bar-chart-with-tooltip
https://blockbuilder.org/1Cr18Ni9/bfadecc96183c48d13b7b90bcf358a61
http://bl.ocks.org/katirg/5f168b5c884b1f9c36a5
I'm trying to run an application for data visualization, I'm using D3.js, my code works but when I change the selected option, the graph change but go down and it goes down every change.
I have no idea where the problem is.
That's my code :
<!DOCTYPE html>
<html>
<head>
<title> Graphique </title>
<script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
</head>
<body>
<FORM>
<SELECT id="Nb" size="1" onchange="Changement()">
<option>Selection</option>
<option>NbCopie</option>
<option>NbTache</option>
<option>NbCopieBW</option>
<option>NbCopieCouleur</option>
<option>MtTotal</option>
</SELECT>
</FORM>
<div id="chart"></div>
<svg width="960" height="500"></svg>
<script>
function Changement() {
d3.selectAll("svg > *").remove();
d3.json("Data.json", function(error, data) {
var Nb = data.map(function(d) {
var x = document.getElementById('Nb');
var i = x.selectedIndex;
var text = x.options[i].text;
if (text == "NbCopie")
return d.NbCopie;
else if (text == "NbTache")
return d.NbTache;
else if (text == "NbCopieBW")
return d.NbCopieBW;
else if (text == " NbCopieCouleur")
return d.NbCopieCouleur;
else if (text == "MtTotal")
return d.MtTotal;
});
var maxNb = d3.max(Nb);
var svg = d3.select("svg"),
margin = {
top: 30,
right: 30,
bottom: 40,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var animateDuration = 700;
var animateDelay = 30;
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('background', '#f4f4f4')
.style('padding', '5 15px')
.style('border', '1px #333 solid')
.style('border-raduis', '5px')
.style('opacity', '0')
var yScale = d3.scaleLinear()
.domain([0, maxNb])
.range([0, height])
var xScale = d3.scaleBand()
.domain(d3.range(0, Nb.length))
.range([0, width])
var colors = d3.scaleLinear()
.domain([0, Nb.length])
.range(['#0080FF', '#FF3333'])
var myChart = d3.select('#chart').append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.style('background', '#f4f4f4')
.selectAll('rect')
.data(Nb)
.enter().append('rect')
.style('fill', function(d, i) {
return colors(i);
})
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i)
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d) {
tooltip.transition()
.style('opacity', 1)
tooltip.html(d)
.style('left', (d3.event.pageX) + 'px')
.style('top', (d3.event.pageY + 'px'))
d3.select(this).style('opacity', 0.5)
})
.on('mouseout', function(d) {
tooltip.transition()
.style('opacity', 0)
d3.select(this).style('opacity', 1)
})
myChart.transition()
.attr('height', function(d) {
return yScale(d);
})
.attr('y', function(d) {
return height - yScale(d);
})
.duration(animateDuration)
.delay(function(d, i) {
return i * animateDelay
})
.duration(1000)
.ease(d3.easeElastic)
var vScale = d3.scaleLinear()
.domain([0, maxNb])
.range([height, 0])
var vAxis = d3.axisLeft()
.scale(vScale)
.ticks(5)
.tickPadding(5)
var vGuide = d3.select('svg')
.append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
vGuide.selectAll('path')
.style('fill', 'none')
.style('stroke', '#000')
vGuide.selectAll('line')
.style('stroke', '#000')
var hScale = d3.scaleTime()
.domain(d3.extent(data, function(d) {
var parseDate = d3.timeParse("%Y%m%d");
Date_Id = parseDate(d.Date_Id);
return Date_Id;
}))
.range([0, width - 150])
var hAxis = d3.axisBottom()
.scale(hScale)
.ticks(d3.timeMonth)
var hGuide = d3.select('svg')
.append('g')
.attr("class", "axis axis--x")
.attr("transform", "translate(" + margin.left + "," + (height + margin.top) + ")")
.call(hAxis);
});
};
</script>
And here a screenshot of my problem:
first attempt
enter image description here
second attempt
enter image description here
and here is an extract of my JSON file
[{
"ConsoPhot_Id": "10148",
"idLotImport": 390,
"Date_Id": 20170201,
"Orga_Id": "203938",
"NbTache": 153,
"NbCopie": 798,
"NbCopieBW": 488,
"NbCopieCouleur": 310,
"MtTotal": 13.69
},
{
"ConsoPhot_Id": "10602",
"idLotImport": 391,
"Date_Id": 20161201,
"Orga_Id": "203938",
"NbTache": 153,
"NbCopie": 909,
"NbCopieBW": 779,
"NbCopieCouleur": 130,
"MtTotal": 7.93
},
{
"ConsoPhot_Id": "10905",
"idLotImport": 392,
"Date_Id": 20161101,
"Orga_Id": "203938",
"NbTache": 115,
"NbCopie": 515,
"NbCopieBW": 409,
"NbCopieCouleur": 106,
"MtTotal": 5.6
},
Don't append a new SVG every time you choose an option.
Thus, instead of:
var myChart = d3.select('#chart').append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
//etc...
Simply do:
var myChart = svg.append('g')
//etc...
Here is a plunker with that change only, using the small JSON sample you provided: https://plnkr.co/edit/PMnNI4hoBz3Q2k5fQTp5?p=preview
PS: As I said in my comment, this code right now has a lot of problems, the main one being the fact that you're erasing everything inside the SVG just to paint it again, and the second one the fact that you are loading the same JSON every time you choose an option. That being said, you should reconsider a major refactor in this code. Have in mind that here I'm only answering the problem stated in your question.
I'm trying to do a bar chart using d3.js version 4, I'm trying to make the vertical axis and it gives me the following error: Uncaught Error at Bn (d3.min.js:2) at Kn.vp [as ease] (d3.min.js:5) at main.js:88
here is my code:
var bardata = [];
for (var i=0; i < 20; i++){
bardata.push(Math.random())
}
bardata.sort(function compareNumbers(a,b){
return a -b;
})
var height = 400,
width = 600,
barWidth = 50,
barOffset = 5;
var tempColor;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleBand()
.domain(d3.range(0, bardata.length))
.padding(0.1)
.range([0, width]);
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('#chart').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d){
d3.select(this)
.style('opacity', 0.5)
})
.on('mouseleave', function(d){
d3.select(this)
.style('opacity', 1)
})
.on('mouseover', function(d){
tooltip.transition()
.style('opacity', 0.9)
tooltip.html(d)
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 0.5)
.style('fill', 'yellow')
})
.on('mouseleave', function(d){
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 1)
.style('fill', '#C61C6F')
})
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease('elastic')
var vAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(10)
var vGuide = d3.select('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(35,0)')
<!DOCTYPE html>
<html>
<head>
<title>Line Chart</title>
<meta charset="8-UTF">
<link rel="stylesheet" src="css/style.css"> </head>
<body>
<div class="container">
<h2>Bar Chart</h2>
<div id="chart"></div>
</div>
<script src="js/d3.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Instead of
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease('elastic')//INCORRECT
It should have been
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease(d3.easeElastic)
working code here
I'm new to d3.js. I wanted to drag a line chart using its points. It is working fine without the x and y axes.
I have used this example as reference: https://bl.ocks.org/mbostock/4342190
With the axes to the line chart the line is not plotting correcly. Please have a look into the snippet below.
Thanks in advance.
<!DOCTYPE html>
<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
let points = d3.range(1, 10).map(function(i) {
return [i * width / 10, 50 + Math.random() * (height - 100)];
});
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[1]); });
let drag = d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended);
svg.append('rect')
.attr('class', 'zoom')
.attr('cursor', 'move')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain(d3.extent(points, function(d) { return d[0]; }));
y.domain(d3.extent(points, function(d) { return d[1]; }));
focus.append("path")
.datum(points)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
focus.selectAll('circle')
.data(points)
.enter()
.append('circle')
.attr('r', 5.0)
.attr('cx', function(d) { return x(d[0]); })
.attr('cy', function(d) { return y(d[1]); })
.style('cursor', 'pointer')
.style('fill', 'steelblue');
focus.selectAll('circle')
.call(drag);
focus.append('g')
.attr('class', 'axis axis--x')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
focus.append('g')
.attr('class', 'axis axis--y')
.call(yAxis);
function dragstarted(d) {
d3.select(this).raise().classed('active', true);
}
function dragged(d) {
d3.select(this)
.attr('cx', d[0] = d3.event.x)
.attr('cy', d[1] = d3.event.y)
focus.select('path').attr('d', line);
}
function dragended(d) {
d3.select(this).classed('active', false);
}
</script>
d3.event is holding pixel positions, but your plot is driven by user-space coordinates. So, you need to convert those pixel positions to user-space. You can use your scales invert method to do so.
function dragged(d) {
d[0] = x.invert(d3.event.x); // convert to user-space
d[1] = y.invert(d3.event.y);
d3.select(this)
.attr('cx', x(d[0])) // back to pixels
.attr('cy', y(d[1]))
focus.select('path').attr('d', line); //line does pixel conversion too
}
Running code:
<!DOCTYPE html>
<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
let points = d3.range(1, 10).map(function(i) {
return [i * width / 10, 50 + Math.random() * (height - 100)];
});
var x = d3.scaleLinear()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y);
var line = d3.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[1]); });
let drag = d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended);
svg.append('rect')
.attr('class', 'zoom')
.attr('cursor', 'move')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain(d3.extent(points, function(d) { return d[0]; }));
y.domain(d3.extent(points, function(d) { return d[1]; }));
focus.append("path")
.datum(points)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
focus.selectAll('circle')
.data(points)
.enter()
.append('circle')
.attr('r', 5.0)
.attr('cx', function(d) { return x(d[0]); })
.attr('cy', function(d) { return y(d[1]); })
.style('cursor', 'pointer')
.style('fill', 'steelblue');
focus.selectAll('circle')
.call(drag);
focus.append('g')
.attr('class', 'axis axis--x')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
focus.append('g')
.attr('class', 'axis axis--y')
.call(yAxis);
function dragstarted(d) {
d3.select(this).raise().classed('active', true);
}
function dragged(d) {
d[0] = x.invert(d3.event.x);
d[1] = y.invert(d3.event.y);
d3.select(this)
.attr('cx', x(d[0]))
.attr('cy', y(d[1]))
focus.select('path').attr('d', line);
}
function dragended(d) {
d3.select(this).classed('active', false);
}
</script>
I have a bar chart displaying data on which you can filter through different years with the press of a button. I want the chart to transition from the current value to the new value, but now it starts at the bottom each time you press a button. How can I fix this?
Thanks!
var margin = {top: 20, right: 20, bottom: 30, left: 20},
height = 500 - margin.top - margin.bottom,
width = 600 - margin.left - margin.right
function bars(data) {
max = d3.max(data)
var yScale = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, height])
var xScale = d3.scale.ordinal()
.domain(d3.range(0, data.length))
.rangeBands([0, width], .2)
var myChart = d3.select("#chart")
var bars = myChart.selectAll("rect.bar")
.data(data)
//enter
bars.enter()
.append("svg:rect")
.attr("class", "bar")
.attr("fill", "#800")
//apply to everything (enter and update)
bars.style('fill', '#C64567')
.attr('width', xScale.rangeBand())
.attr('x', function(d,i){
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
bars.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.duration(1000)
.ease('elastic')
}
function init() {
//setup the svg
var svg = d3.select("#svg")
.style('background', '#000')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("svg:g")
.attr("id", "chart")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
//UI
d3.select("#button1")
.on("click", function (d, i) {
bars(j1996);
})
d3.select("#button2")
.on("click", function (d, i) {
bars(j1997);
})
d3.select("#button3")
.on("click", function (d, i) {
bars(j1998);
})
//draw the bars
bars(j1996);
}
A fresh new look at it and I managed to find the solution. I removed the tag bars in this line:
//apply to everything (enter and update)
bars.style('fill', '#C64567')
So all the attributes are now set on the bar.enter() command, this way d3.js makes the transitions automatically from the last value