I am trying to draw a path that means line chart using d3.js. I am using the following code
var data;
d3.csv("myfile.csv",function(datagot){data=datagot;});
var format = d3.time.format("%Y/%m/%d %H:%M:%S");
data.forEach(function (e){
e.dist = +e.dist;
e.speed = +e.speed;
e.lat=+e.lat;
e.lon=+e.lon;
e.dd=format.parse(e.time);
});
var xScale = d3.time.scale().range([margin.left, width - margin.right]).domain([d3.min(dataset,function(d){return d.dd}),d3.max(dataset,function(d){ return d.dd})]),
yScale = d3.scale.linear().range([height - margin.top, margin.bottom]).domain([d3.min(dataset,function(d){return d.dist;}),d3.max(dataset,function(d){return d.dist;})]),
xAxis = d3.svg.axis()
.scale(xScale).ticks(10).tickFormat(d3.time.format("%H:%M")).tickPadding(2),
yAxis = d3.svg.axis()
.scale(yScale).orient("left").tickPadding(5).ticks(5);
var svg = d3.select("body").append("svg")
.attr("width", width-50 )
.attr("height", height -60);
svg.append("svg:g")
.attr("class","axis")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(xAxis);
// x axis label
svg.append("text")
.attr("x", width / 2 )
.attr("y", height - 60)
.style("text-anchor", "middle")
.text("Time");
svg.append("svg:g")
.attr("class","axis")
.attr("transform", "translate(" + (margin.left-10) + ",-90)")
.call(yAxis);
// Y axis label
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 15)
.attr("x",70- (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Distance");
// svg.append("g")
//.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
lineh = d3.svg.line().x(function(d) {
return x(d.dd);
}).y(function(d) {
return y(d.dist);
});
var line = svg.append("g").attr("transform", "translate(" + margin.left + "," + (-margin.top) + ")").selectAll(".hour")
.data(outputf)
.enter().append("path")
//.attr("x", function(d) { return (d.dd.getMinutes())*15 ; })
// .attr("cx", function(d) { return (d.dd.getMinutes())*10 ; })
//.attr("y", function(d) { return (d.dist)*50 ; })
// .attr("cy", function(d) { return height-100-(d.dist)*50 ; })
//.attr("r",3)
/* .attr("rx", 2)
.attr("ry", 2)*/
.attr("d",lineh)
.attr("class", "line");
But its actually not plotting anything. I am giving the jsfiddle for your help to understand. http://jsfiddle.net/1b0gn0r2/. The jsfiddle is not well organized but it contains my code and the csv data I am using is at the bottom. Can anyone help me to find the error?
In my actual code the output is the following
There's a lot that seems to be wrong in your code! Having various things missing (like margin, height, width, other variables, the CSS etc), makes it very painful to answer your question.
To start with, if you're struggling with jsfiddle you may prefer Plunker, which makes it easier to organise your code and data.
I've created a plunk that works with your code here: http://plnkr.co/edit/ZEi7U6qQ8pxq06FdDIW6?p=preview
...but it involved quite a few changes, which I'll try to summarise:
Loading is asynchronous, so this line:
d3.csv("myfile.csv",function(datagot){data=datagot;});
will not do what you expect. The rest of the code will go off and execute (eg drawing axes) without data having been properly set. So you try to draw the line before the data is ready. Fix this by inserting the main code into the data load function.
Defining scales. You seem to define 4 different scales:
xScale = d3.time.scale()
yScale = d3.scale.linear()
x = d3.scale.linear()
y = d3.scale.linear()
That causes problems later in your line drawing function (more to come on that). I've got rid of x and y here
The line drawing function lineh expects the scales to be x and y, but I suggest using the xScale and yScale ones you've defined before.
// line function
lineh = d3.svg.line()
.x(function(d) {
return xScale(d.dd); // <- do not use d(d.dd)
})...
Calling the line function should be done in a completely different way: Your code:
var line = svg.append("g")
.data(outputf)
.enter().append("path")
.attr("d",lineh)
.attr("class", "line");
Not sure what outputf is so I ignored that. lineh (defines how to draw the line) should be called with the data. I changed the call to:
var line = svg.append("g")
.append("path")
.attr("d", lineh(dataset)) // <- Note the change
.attr("class", "line");
Finally I reorganised the code to bring some variable definitions to the top of the file and make it easier to follow.
Related
Update, here is error message in console:
Error: attribute d: Expected number, "M0,NaNL21.654801022…".
I am sure this is a fairly simple d3 question, and I have looked at other answers but nothing posted seems to help, the ticks don't show up on the y-axis, but they work perfectly on x-axis. Additionally, this is supposed to be a line graph but the line is not being drawn.
Here is the code:
var margin = {top: 10, right: 40, bottom: 150, left: 70},
width = 760 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var w = width + margin.left + margin.right;
var h = height + margin.top + margin.bottom;
var svg = d3.select("body").append("svg") // this appends a new SVG element to body
.attr("width", w) // set the width
.attr("height", h) // set the height
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x scale will handle time
var xScale = d3.scaleTime().range([0,width]);
// y scale will handle energy consumption values
var yScale = d3.scaleLinear().range([height,0]);
// Define X and Y AXIS
var yAxis = d3.axisLeft(yScale);
var xAxis = d3.axisBottom(xScale);
var parseTime = d3.timeParse("%Y");
function rowConverter(data) {
return {
year : parseTime(data.year),
value : +data.average // the + operator parses strings into numbers
};
}
// line generator function
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return xScale(d.year); })
.y(function(d) { return yScale(d.average); })
d3.csv("moreDummyData.csv",rowConverter).then(function(data){
yScale.domain([0,d3.max(data, function(d) {return d.average; })]);
xScale.domain(d3.extent(data, function(d) { return d.year; }));
// Draw xAxis
svg.append("g") // add a new svg group element
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".25em")
.attr("text-anchor", "end");
// Draw yAxis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".25em")
.attr("text-anchor", "end");
// add a title for the yAxis
svg.append("text") // add a new svg "text" element
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)") // turn it on its side
// position the title in space
.attr("y", -margin.left+20)
.attr("x", -margin.top-75)
// give it text and style
.text("ADD TITLE")
.attr("font-family", "Times")
.attr("font-size", "16px");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
And this is what the output looks like with this code:
code output
Here's what the data looks like:
year,average
1971,30
1972,34
1973,29
1974,28
1975,31
1976,35
Good Image
Bad Image
I am trying to create a D3 graph which looks like the Illustrator created design (Good Image 1), but the closest in terms of positioning I have been able to get is the second (Bad Image 2).
I'm really new to D3 and creating SVGs in general, so I may be going about this all wrong. The code below is what I've been able to figure out / find online. It looks like I can't directly adjust positioning of the elements themselves using css positioning? I tried adding classes via the html and also in JQuery with $(.myClass).css..., but everything I do has exactly zero effect. The only thing that seems to work is transform, but it's ugly, as can be seen in the second pic.
var margin = { left:10, right:10, top:10, bottom:10 };
var width = 400 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var g = d3.select("#pyramid-chart-area")
.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("../data/pyramid_hp.json").then(function(data){
data.forEach(function(d){
d.hp = +d.hp;
});
var x = d3.scaleBand()
.domain(data.map(function(d){ return d.hp; }))
.range([0, width])
.paddingInner(0.3)
.paddingOuter(0.3);
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d){
return d.hp;
})])
.range([height, 0]);
var xAxisCall = d3.axisBottom(x);
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxisCall)
.selectAll("text")
.attr("y", "10")
.attr("x", "-5")
.attr("text-anchor", "end")
.attr("transform", "rotate(-40)");
var yAxisCall = d3.axisLeft(y)
.ticks(3)
.tickFormat(function(d){
return d;
});
g.append("g")
.attr("class", "y-axis")
.call(yAxisCall);
var arc = d3.symbol().type(d3.symbolTriangle)
.size(function(d){ return scale(d.hp); });
var scale = d3.scaleLinear()
.domain([0, 5])
.range([0, width]);
var colors = d3.scaleLinear()
.domain(d3.extent(data, function(d) {return d.hp}))
.range([
'#ffffff',
'#303030'
]);
var group = g.append('g')
.attr('transform','translate('+ 192 +','+ 320 +')')
.attr('class', 'triangle-container');
var line = group.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', arc)
// .attr('fill',function(d){ return colorscale(d.hp); })
.attr('fill', d => colors(d.hp))
.attr('stroke','#000')
.attr('stroke-width', 1)
.attr('class', 'triangle')
.attr('transform',function(d,i){ return "translate("+ (i * 20) +","+(i * 10)+")"; });
You can position the symbols, but its tricky - symbol size represents area and as rioV8 notes symbols are positioned by their center. But if you can figure out the properties of the triangle we can place it relatively easily.
In the case of a equilateral triangle, you'll want to know the length of a given side as well as the height of that centroid (which is triangle height/3). So these functions will likely be useful:
// get length of a side/width of upright equilateral triangle from area:
function getWidth(a) {
return Math.sqrt(4 * a / Math.sqrt(3));
}
// get height of the triangle from length of a side
function getHeight(l) {
return Math.sqrt(3)*l/2;
}
Using the height of the centroid we can position the circle where we want with something like:
y = SVGheight - SymbolHeight/3 - marginBottom;
No need for scaling here.
The x values of each symbol do need some scaling to arrange them to your liking. Below I use a linear scale with a range of [width/10,0] arbitrarily, the denominator will change the horizontal skew in this case, there are probably better ways to fine tune this.
With this you can achieve the desired result:
For simplicity's sake, below I'm using data (since you don't show any) that represents pixel area - scaling must be factored into the height and width calculations if scaling areas. I've also included circles on the top of each triangle for possible label use, since we know the dimensions of the triangle this is trivial now
var margin = { left:10, right:10, top:10, bottom:10 };
var width = 400 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var g = 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 data = [
{a: 40000},
{a: 30000},
{a: 20000},
{a: 10000}
];
function getWidth(a) {
return Math.sqrt(4 * a / Math.sqrt(3));
}
function getHeight(l) {
return Math.sqrt(3)*l/2;
}
data.forEach(function(d) {
d.w = getWidth(d.a);
d.h = getHeight(d.w);
})
var x = d3.scaleLinear()
.domain(d3.extent(data, function(d){ return d.w; }) )
.range([width/10,0]);
var arc = d3.symbol().type(d3.symbolTriangle)
.size(function(d){ return d.a; });
var colors = d3.scaleLinear()
.domain(d3.extent(data, function(d) {return d.a}))
.range(['#ffffff','#303030']);
var group = g.append('g')
.attr('transform','translate('+ width/2 +',0)')
.attr('class', 'triangle-container');
var line = group.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', d => colors(d.a))
.attr('class', 'triangle')
.attr('transform',function(d,i){ return "translate("+ x(d.w) +","+ (height - d.h/3 - margin.bottom ) +")"; });
var circles = group.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.w); })
.attr("cy", function(d) { return height - d.h - margin.bottom; })
.attr("r", 3);
<script src='https://d3js.org/d3.v5.min.js' type='text/javascript'></script>
axes could present a bit of a challenge
I have a barchart which is populated by values from a JSON variable. The chart is dynamic because the values are retrieved from an SQL query by doing a count. So my data gets fed back in like :
[{"Fruit":"Apple","COUNT( Fruit )":"12"},{"Fruit":"Orange","COUNT( Fruit )":"6"},{"Fruit":"Pear","COUNT( Fruit )":"1"},{"Fruit":"Blank","COUNT( Fruit )":"1"},{"Fruit":"Pineapple","COUNT( Fruit )":"1"},{"Fruit":"Kiwi","COUNT( Fruit )":"1"}]
For the most part my graphs seem to be displaying properly. However some are returning values that exceed the Y Axis, I dont think it's the values that are causing the issues I believe its the axis that isnt calculating the right height. For instance
If Orange count is 14, sometimes the Y axis stops at a number less than this and that column extends the graph.
By viewing it in google chrome developer console, I can see the height of the bar is
<rect id="Orange" y="-520px" x="94px" height="1040px" width="162"></rect>
which far extends my SVG height of 600px - Margins(top + bottom) of 80px!
Does anyone know why my Y Axis isn't getting the right Max value?
Code here:
var canv = document.getElementById("exportCanvas");
canv.width = screen.width;
var margin ={top:40, right:0, bottom:40, left:40},
width=screen.width - 250,
height=600-margin.top-margin.bottom;
var jsplit = jdata.split('"');
var keyX = jsplit[1];
var keyY = "";
var data = JSON.parse(jdata);
for (k in data[0]) {
if (k!=keyX) keyY=k;
}
console.log("keyX = " + keyX);
console.log(keyY);
console.log(data[0]);
// scale to ordinal because x axis is not numerical
var x = d3.scale.ordinal()
.domain(['Orange','Apple','Pear']) //Added this in temporarilly. this should be calculated from the data.
.rangeRoundBands([0, width], 0.25,0.25);
//scale to numerical value by height
// var y = d3.scale.linear().range([height, 0]);
var y = d3.scale.linear()
.range([height, 0]);
console.log(data);
x.domain(data.map(function(d){ return d[keyX]}));
y.domain([0, d3.max(data, function(d){return d[keyY]})]);
var chart = d3.select("#chart")
.append("svg") //append svg element inside #chart
.attr("width", width+ margin.left+margin.right) //set width
// .attr("width", width+(2*margin.left)+margin.right) //set width
.attr("height", height+margin.top+margin.bottom); //set height
// .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");
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")
.ticks(10).tickFormat(function(d) {
if (d % 1 == 0) {
return d3.format('.f')(d)
} else {
return ""
}
});
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g");
//you're moving the group and then moving the rect below as well
//one or the other not both need to be moved.
//.attr("transform", function(d, i){
// return "translate("+x(d[keyX])+", 0)";
//});
bar.append("rect")
.attr("id", function(d) {
return d[keyX];
})
.attr("y", function(d) {
return y(d[keyY]) + "px";
})
.attr("x", function(d,i){
//AB - Adjusted this so it correcly places the bar along the X
//x.range is an array of x values for each bar
//calculated in the var x = line above , with the .rangeRoundBands([0, width], 0.25,0.25);
//setting the width of the bars (an equal division of width) with margins of 0.25 at the start
//and end of the graph and 0.25 between each bar.
return x.range()[i] + margin.left + "px";
})
.attr("height", function(d) {
return height - y(d[keyY]) +"px";
})
.attr("width", x.rangeBand()); //set width base on range on ordinal data
bar.append("text")
.attr("x",function(d,i){
//similar to above but adding half the width of the bar to the x position
//to roughly center it on the bar. only rough as doesnt take account of length of text.
return x.range()[i] + margin.left + (x.rangeBand()/2)+ "px";
})
.attr("y", function(d) { return y(d[keyY]) +20; })
.attr("dy", ".75em")
.style("fill","white")
.style("font-weight", "bold")
.text(function(d) { return d[keyY]; });
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(keyY);
Apologies for commented out code, I have been playing with it alot to try and suss this out.
You need to recalculate y.domain() when your dataset refreshes. So when you update your data, you can try something like:
y.domain([0, d3.max(data, function(d){return d[keyY]})]);
chart.select(".y.axis")
.call(yAxis.scale(y));
I have a simple d3 area chart, with two areas plotted using the following data:
var data = [
[{'year':0,'amount':2},{'year':1,'amount':3},{'year':2,'amount':9},{'year':3,'amount':5},{'year':4,'amount':6},{'year':5,'amount':7},{'year':6,'amount':8},{'year':7,'amount':9},{'year':8,'amount':10},{'year':9,'amount':11},{'year':10,'amount':12}],
[{'year':0,'amount':1},{'year':1,'amount':2},{'year':2,'amount':8},{'year':3,'amount':4},{'year':4,'amount':5},{'year':5,'amount':6},{'year':6,'amount':7},{'year':7,'amount':8},{'year':8,'amount':9},{'year':9,'amount':10},{'year':10,'amount':11}]
];
The two separate arrays of objects allow me to plot two areas on one chart using the code below:
var colors = [
'steelblue',
'lightblue',
];
var margin = {top: 20, right: 30, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain(d3.extent(data.map(function(d,i) { console.log(d); return d[i].year; })))
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(true)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(true)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", (-margin.left) + 10)
.attr("x", -height/2)
.text('Axis Label');
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
//************************************************************
// Create D3 line object and draw data on our SVG object
//************************************************************
var line = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.year); })
.y0(height)
.y1(function(d) { return y(d.amount); });
svg.selectAll('.line')
.data(data)
.enter()
.append("path")
.attr("class", "area")
.attr('fill', function(d,i){
return colors[i%colors.length];
})
.attr("d", line);
Thing is I need to set the domains based on the data. I've tried doing:
.domain(d3.extent(data.map(function(d) { return d.amount; })))
...when creating my linear scale but obviously this doesn't work as the array map in the call above just maps out the nested arrays instead of the objects inside.
How do I set the domain using data in this format? Or is there a better way to structure my data whilst still allowing for multiple areas to be drawn?
To get the overall extent of all the amount values contained in both arrays you need to somehow merge these arrays into one. There are several ways this could be done:
d3.merge() to merge both arrays into one:
var allValues = d3.merge(data);
The main advantage of this approach over the following ones is the fact, that this will work with any number of nested arrays in data without any changes to the code.
Built-in method Array.prototype.concat():
var allValues = data[0].concat(data[1])
If you want to show off and don't need to be compatible with older version of JavaScript, you can apply the spread operator new to ES6:
var allValues = [...data[0], ...data[1]];
Having this flattened array containing all values you can pass it to d3.extent() to calculate the overall extent.
var extent = d3.extent(allValues, function(d) { return d.amount; });
var data = [
[{'year':0,'amount':2},{'year':1,'amount':3},{'year':2,'amount':9},{'year':3,'amount':5},{'year':4,'amount':6},{'year':5,'amount':7},{'year':6,'amount':8},{'year':7,'amount':9},{'year':8,'amount':10},{'year':9,'amount':11},{'year':10,'amount':12}],
[{'year':0,'amount':1},{'year':1,'amount':2},{'year':2,'amount':8},{'year':3,'amount':4},{'year':4,'amount':5},{'year':5,'amount':6},{'year':6,'amount':7},{'year':7,'amount':8},{'year':8,'amount':9},{'year':9,'amount':10},{'year':10,'amount':11}]
];
console.log(d3.extent(d3.merge(data), function(d) { return d.amount; })); // using d3.merge()
console.log(d3.extent(data[0].concat(data[1]), function(d) { return d.amount; })); // using Array.prototype.concat()
// This will only work in compatible browsers which support the new ES6 spread operator
console.log(d3.extent([...data[0], ...data[1]], function(d) { return d.amount; })); // using ES6 spread operator
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I am trying do some path interpolation in D3. I'd like to produce an area plot like this, but I want to transition the area along the y-axis, starting from the bottom of the xaxis up to the final position shown in the example. Here's a quick sketch to explain what I'd like to do:
I'd like to start the transition with no area:
and transition it up along the y-axis:
Using the code, copied from the example, here's what I'd trying to do:
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-%y").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 area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
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.tsv("data.tsv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
var dataSel = svg.selectAll('.area').data(data)
dataSel.exit().remove()
dataSel.enter()
.append('path')
.attr("class", "area")
.attr("d", 'M0,0h' + width) // my idea here was to draw a path that
// has no area along the x-axis and then
// interpolate the path up to the final area
dataSel.transition() // transition the path to its final position
.duration(1000)
.attr("d", area)
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 ($)");
});
Can anyone explain/show how I can transition a path along one axis as I'm trying to do?
D3 path transitions only really work if the starting and ending paths have the same number of control points. So, for example, D3 can't transition a line into an area. What you could do, however, is something like the following:
Use d3.area to generate the final path for the area.
Make a copy of the path and, in the copy, change all the control points that correspond to the "top" of the area to control points on the "bottom" of the area. (In other words, modify their y-values.)
Draw the area using this modified path.
Transition to the final path.