`
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right
, height = window.innerHeight - margin.top - margin.bottom;
// n data points
var n = 7;
// X scale
var xScale = d3.scaleBand()
.domain(['A','B','C','D','F','E','Z']) // input
.range([0, width]); // output
// Y scale
var yScale = d3.scaleLinear()
.domain([0, 1])
.range([height, 0]);
var line = d3.line()
.x(function(d, i) { return xScale(i); })
.y(function(d) { return yScale(d.y); })
.curve(d3.curveMonotoneX)
var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)()} })
// SVGs
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("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "white");
svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x axis call
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// y axis call
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset)
.attr("class", "line")
.attr("d", line);
// 12. Appends a circle for each datapoint
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.y) })
.attr("r", 6);
svg.append("text")
.attr("class", "title")
.attr("x", width/2)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Testing");
/* 13. Basic Styling with CSS */
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: green;
stroke-width: 3;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: red;
stroke: #fff;
}
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
</style>
<!-- Body tag is where we will append our SVG and SVG objects-->
<body>
</body>
<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
</script>
I need for each data point to correspond to an (string) x-coordinate.
I am knew to d3 and I have yet to get accustomed to formatting axis.
I would also be great if anyone can point me out to how to add a tooltip. (Just an explanation)
Thank you everyone.
Not sure why it keeps saying your: "
It looks like your post is mostly code; please add some more details."
`
The scaleOrdinal is mapped to an array of alphabets but when you are calculating the cx you are mapping to an integer i. To resolve this:
Separate the labels as as array first:
var labels = ['A','B','C','D','F','E','Z'];
Then pass the labels to the domain:
// X scale
var xScale = d3.scaleBand()
.domain(labels) // input
.range([0, width]); // output
Finally, when you call calculate the cx, you need to send a value which was used in the domain. In your case since your domain is an array of alphabets you need to reparse the i to that particular alphabet. Hence you need to return xScale(labels[i]) as below:
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(labels[i]) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 6);
Full working snippet below. Hope this helps.
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right
, height = window.innerHeight - margin.top - margin.bottom;
// n data points
var n = 7;
//labels
var labels = ['A','B','C','D','F','E','Z'];
// X scale
var xScale = d3.scaleBand()
.domain(labels) // input
.range([0, width]); // output
// Y scale
var yScale = d3.scaleLinear()
.domain([0, 1])
.range([height, 0]);
var line = d3.line()
.x(function(d, i) { return xScale(i); })
.y(function(d) { return yScale(d.y); })
.curve(d3.curveMonotoneX)
var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)()} })
// SVGs
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("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "white");
svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x axis call
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// y axis call
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset)
.attr("class", "line")
.attr("d", line);
// 12. Appends a circle for each datapoint
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(labels[i]) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 6);
svg.append("text")
.attr("class", "title")
.attr("x", width/2)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Testing");
/* 13. Basic Styling with CSS */
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: green;
stroke-width: 3;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: red;
stroke: #fff;
}
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
</style>
<!-- Body tag is where we will append our SVG and SVG objects-->
<body>
</body>
<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
</script>
Updated Snippet with Lines:
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right
, height = window.innerHeight - margin.top - margin.bottom;
// n data points
var n = 7;
//labels
var labels = ['A','B','C','D','F','E','Z'];
// X scale
var xScale = d3.scaleBand()
.domain(labels) // input
.range([0, width]); // output
// Y scale
var yScale = d3.scaleLinear()
.domain([0, 1])
.range([height, 0]);
var line = d3.line()
.x(function(d, i) { return xScale(labels[i]); })
.y(function(d) { return yScale(d.y); })
.curve(d3.curveMonotoneX)
var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)()} })
// SVGs
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("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "white");
svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x axis call
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// y axis call
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset)
.attr("class", "line")
.attr("d", line);
// 12. Appends a circle for each datapoint
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(labels[i]) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 6);
svg.append("text")
.attr("class", "title")
.attr("x", width/2)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Testing");
/* 13. Basic Styling with CSS */
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: green;
stroke-width: 3;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: red;
stroke: #fff;
}
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
</style>
<!-- Body tag is where we will append our SVG and SVG objects-->
<body>
</body>
<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
</script>
Related
d3.js How to draw line chart with vertical x axis labels?
My Fiddle:
https://jsfiddle.net/nitinjs/p1r49qeg/
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
UPDATE
I have few questions,
1. how to make this graph resposive in bootstrap ie. without hardcoding width and height
2. how to update this graph on button click
3. how do I start y axis at 0 to any value e.g. 0 to 9100
Updated answer: to change the label rotation just select all text elements and apply rotate through transform attribute, and adjust the location using dx and dy, also if you notice I changed the padding bottom value in margin variable to be able to view the tick text since this will make them half visible with rotation.
...
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
...
or a working snippet:
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y))
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<div id="my_dataviz"></div>
updated answer for, I added responsive to the chart and change the label of the first element in the left axis, I will leave the data update to you, also some notes there are better ways to make responsive d3 charts one of them is to use viewport attribute but I didn't test it myself, also the first the element to start from 0 I did it as a hack, I'm sure there is a better way of doing it without select and change, those are a starting point for you, I hope my change give some insights on where to look for here:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div id="my_dataviz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 1280 - margin.left - margin.right,
height = 650 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
var axisBottom = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
var axisLeft = svg.append("g")
.call(d3.axisLeft(y));
// Add the line
var line = svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
function drawChart() {
// reset the width
width = parseInt(d3.select('body').style('width'), 10) - margin.left - margin.right;
height = (width * 0.45) - margin.top - margin.bottom;
d3.select("#my_dataviz svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
d3.select('.main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
axisBottom.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.attr('class', 'axis-bottom')
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
axisLeft.call(d3.axisLeft(y)).attr('class', 'axis-left');
//this is shiit!! there must be a better way.
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
line.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
);
d3.select('.dots').remove();
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2");
}
// call this once to draw the chart initially
drawChart();
//////////////////////////////////////////////
// Resizing //////////////////////////////////
//////////////////////////////////////////////
// redraw chart on resize
window.addEventListener('resize', drawChart);
})
</script>
</body>
</html>
I am creating a line chart in D3 v4.
The x-axis is showing the year with commas like 1,998 and 1,999 instead of 1998 and 1999 etc. It is addig the thousand comma which is what I am trying to remove.
I am trying to remove the commas, but I have not been able to. tickformat is not working in v4.
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 50, right: 50, bottom: 100, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3.line()
.x(function(d) { return x(d.Year); })
.y(function(d) { return y(d.Amount); });
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 + ")");
// Get the data
d3.csv("australia.csv", function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.Year = d.Year;
d.Amount = +d.Amount;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Year}));
y.domain([0, d3.max(data, function(d) { return d.Amount; })]);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top) + ")")
.style("text-anchor", "middle")
.text("Year");
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Amount");
});
</script>
</body>
And here is my csv file:
Year,Amount
1998,103323
1999,57914.9
2003,297.969
2004,921253.8
2007,169869.2
2008,44685.5
2010,86084.5
Thanks,
You should use scaleTime for x axis, not scaleLinear:
var x = d3.scaleTime().range([0, width]);
You also should process your dataset this way:
var parseTime = d3.timeParse("%Y");
data.forEach(function(d) {
d.Year = parseTime(d.Year);
d.Amount = +d.Amount;
});
Check working example in the hidden snippet below:
var dataAsCsv = `Year,Amount
1998,103323
1999,57914.9
2003,297.969
2004,921253.8
2007,169869.2
2008,44685.5
2010,86084.5`;
// set the dimensions and margins of the graph
var margin = {top: 50, right: 50, bottom: 100, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3.line()
.x(function(d) { return x(d.Year); })
.y(function(d) { return y(d.Amount); });
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 data = d3.csvParse(dataAsCsv);
var parseTime = d3.timeParse("%Y");
// format the data
data.forEach(function(d) {
d.Year = parseTime(d.Year);
d.Amount = +d.Amount;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Year}));
y.domain([0, d3.max(data, function(d) { return d.Amount; })]);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top) + ")")
.style("text-anchor", "middle")
.text("Year");
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Amount");
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
My first time to post question here. I am converting my version 3 of d3 path line transition code to version 4, and I am having a hard time.
First of all, I saw Mike's example (posted about two days agao) of smooth line transition with non-time x axis for version 4, so I did the similar thing to his example of version 3 with time x axis. The path line moves smoothly, but the x axis doesn't. Also, for my work, I cannot trigger the transition from where he did in this example, so I cannot use the variable "this" in the tick function. Here is the code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
(function() {
var n = 243,
duration = 750,
now = new Date(Date.now() - duration),
count = 0,
data = d3.range(n).map(function() { return 0; });
random = d3.randomNormal(0, .2),
data = d3.range(n).map(random);
var margin = {top: 6, right: 0, bottom: 20, left: 40},
width = 960 - margin.right,
height = 120 - margin.top - margin.bottom;
var x = d3.scaleTime()
.domain([now - (n - 2) * duration, now - duration])
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var line = d3.line()
.x(function(d, i) { return x(now - (n - 1 - i) * duration); })
.y(function(d, i) { return y(d); });
var svg = d3.select("body").append("p").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", -margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var axis = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(x.axis = d3.axisBottom().scale(x));
var timeline = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(data)
.attr("class", "line")
.transition()
.duration(500)
.ease(d3.easeLinear)
.on("start", tick);
var transition = d3.select({}).transition()
.duration(750)
.ease(d3.easeLinear);
function tick() {
data.push(random());
now = new Date();
x.domain([now - (n - 2) * duration, now - duration]);
y.domain([0, d3.max(data)]);
// redraw the line
svg.select(".line")
.attr("d", line)
.attr("transform", null);
// slide the x-axis left
axis.call(x.axis);
// slide the line left
d3.active(this)
.attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
.transition().on("start", tick);
// pop the old data point off the front
data.shift();
}
})()
</script>
</body>
at the tick function, there is a "this", from debugging, I found out it's a path, so I tried to replace it with d3.active(d3.selectAll("path")), or d3.active(d3.selectAll(".line")), neither works. I also tried to assign a variable timeline to the path, so that I tried d3.active(timeline). It doesn't work either.
I am at my wits' end on this issue. I posted on d3 google group, nobody answered. I hope somebody here can give me some suggestions.
Thanks
Diana
The transition to v4 is indeed not easy. Had the same issue as you. Try the following code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
(function() {
var n = 243,
duration = 750,
now = new Date(Date.now() - duration),
count = 0,
data = d3.range(n).map(function() {
return 0;
});
random = d3.randomNormal(0, .2),
data = d3.range(n).map(random);
var margin = {top: 6, right: 0, bottom: 20, left: 40},
width = 960 - margin.right,
height = 120 - margin.top - margin.bottom;
var x = d3.scaleTime()
.domain([now - (n - 2) * duration, now - duration])
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var line = d3.line()
.x(function(d, i) {
return x(now - (n - 1 - i) * duration);
})
.y(function(d, i) {
return y(d);
});
var svg = d3.select("body").append("p").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", -margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var axis = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(x.axis = d3.axisBottom().scale(x));
var timeline = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(data)
.attr("class", "line")
.transition()
.duration(500)
.ease(d3.easeLinear);
var transition = d3.select({}).transition()
.duration(750)
.ease(d3.easeLinear);
(function tick() {
transition = transition.each(function() {
data.push(random());
now = new Date();
x.domain([now - (n - 2) * duration, now - duration]);
y.domain([0, d3.max(data)]);
// redraw the line
svg.select(".line")
.attr("d", line)
.attr("transform", null);
// slide the x-axis left
axis.call(d3.axisBottom(x));
// slide the line left
//d3.active(this).attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
// pop the old data point off the front
data.shift();
}).transition().on("start", tick);
})();
})()
</script>
</body>
The trick is to chain transitions and using transition().on rather than transition().each. To update the axis you need to call the d3.axisBottom(x) in the same way that you instantiate the axis.
I am totally new to D3 and trying to make a live streaming plot similar to the third one found here.
The difference, however, is that I need the data to accumulate/build up rather than pass by. I have tried to replicate the code from here and simply commented out the part where they translate and pop off old data, but that still doesn't do it.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var n = 40,
random = d3.random.normal(0, .2),
data = d3.range(n).map(random);
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([1, n - 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 1])
.range([height, 0]);
var line = d3.svg.line()
.interpolate("basis")
.x(function(d, i) { return x(i); })
.y(function(d, i) { return y(d); });
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("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
svg.append("g")
.attr("class", "y axis")
.call(d3.svg.axis().scale(y).orient("left"));
var path = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
tick();
function tick() {
// push a new data point onto the back
data.push(random());
// redraw the line, but don't slide it to the left
path
.attr("d", line)
.attr("transform", null)
.transition()
.duration(500)
.ease("linear")
//.attr("transform", "translate(" + x(0) + ",0)")
.each("end", tick);
// don't pop the old data point off the front
// data.shift();
}
</script>
Inside your tick function you need to add these lines:
data.push(random());//generate the random points
x.domain([1, data.length - 2])//update the x axis domain
xaxis.call(d3.svg.axis().scale(x).orient("bottom"))//redraw the x axis
working code here
I'm a D3 newbie and having a slow time getting up to speed on this library. I am trying to get this simple D3 area chart to work but am having some trouble displaying the actual area it self. I can get the axis to display correctly with the right ranges for the data, but no area displays on the graph itself.
I am feeding it JSON data that looks like this and it appears to be consuming the data fine as best as I can tell.
[{"Date":"Date","Close":"Close"},{"Date":"20130125","Close":"75.03"},{"Date":"20130124","Close":"75.32"},{"Date":"20130123","Close":"74.29"},{"Date":"20130122","Close":"74.16"},{"Date":"20130118","Close":"75.04"},{"Date":"20130117","Close":"75.26"},{"Date":"20130116","Close":"74.34"},{"Date":"20130115","Close":"76.94"},{"Date":"20130114","Close":"76.55"}]
This is my code
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").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.json('JSONstockPriceOverTime.php', function (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; })]);
svg.append("path")
.datum(data)
.attr("class", "area")
.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 ($)");
});
And I have this style applied
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.area {
fill: steelblue;
}
</style>
Remove the starting part of the json (JSONstockPriceOverTime.php) file;
{"Date":"Date","Close":"Close"},
Since it has the 'Date' and 'Close' variables defined as part of the json format, you won't be required to include header information like a csv file, and add 'error' into your json load line
d3.json("JSONstockPriceOverTime.php", function(error, data) {
and you should be all go (worked for me).
You're making good progress.