Updating data in d3js
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
In this chart I'm calling d3.csv
everytime I update the data, which if I understand correctly is a bad thing to do.
In this answer on S.O the answerer explains that d3.csv
is asynchronous and the data should only be loaded in once.
I understand why that is, but what I'm wondering now is what is a better way of doing this and if the way that I've done it in the sample code is ever acceptable.
<html>
<head>
<meta charset ="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
body
margin:auto;
width:850px;
font:10px arial;
padding:25px;
color:#555;
select
border: none;
border-bottom: 1px solid #ccc;
padding: 3px;
text-decoration: none;
font-size: 11px;
cursor: pointer;
select:focus
outline:0;
.sortCheck
float:right;
margin-top:-35px;
margin-right:190px;
#myCheckbox
position:relative;
top:3px;
/* --- Chart Css --- */
.barEnter
fill: steelblue;
opacity: .9;
.barEnter:hover
opacity: 1;
.axis--x path
display: none;
.grid--y path,
.grid--y text
display: none;
.grid--y line
opacity:.15;
</style>
</head>
<body onclick>
<h2 style="font-weight:lighter;">Mulitple datasets test</h2>
<!-- Selection Category -->
<b style="font-size:11px;">
Choose Category
</b>
<select id="category">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<!-- Selection New dataset -->
<span style="margin-left:30px;">
<b style="font-size:11px;">
Choose Year
</b>
<select id="year" onchange="toggle();">
<option value="data2017">2017</option>
<option value="data2016">2016</option>
</select>
</span>
<!-- Chart -->
<div id="chart"></div>
<!-- Sort dimension -->
<span class="sortCheck">Sort Values
<input type="checkbox" id="myCheckbox">
</span>
<script>
let Globalvar = ; // Global access variables
Globalvar.csvShift = "data.csv"; // CSV init
let formatValue = d3.format(",.0f");
let margin = top: 35, right: 145, bottom: 35, left: 45,
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
let x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
let xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y),
yGrid = d3.axisLeft(y).tickSize(-width);
let g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
let sideTextX = width + 30,
sideTextY = -height + height;
Globalvar.durations = 0;
function afterLoad()
Globalvar.durations = 750;
;
// Sum of value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY)
.text("Accumulated value: ")
g.append("text").attr("id","totalValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 20);
// Average value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 40)
.text("Average value: ")
g.append("text").attr("id","avgValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 60);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis grid--y");
// event handlers
d3.select("#myCheckbox").on('change', update);
d3.select("#category").on('change', update);
update();
var file, catInt;
function update()
file = Globalvar.csvShift
catInt = d3.select('#category').property('value');
d3.csv(file, type, function(error,data)
if(error) throw error;
var sortIndex = data.map(function(d) return d.month);
// Update domain
y.domain([0, d3.max(data, function(d)
return d["Category" + catInt]; )
]).nice();
// Update axis
g.selectAll(".axis.axis--y").transition()
.duration(Globalvar.durations)
.call(yAxis);
g.selectAll(".axis.grid--y").transition()
.duration(Globalvar.durations)
.call(yGrid);
// Sums and averages
let sumOfAll = d3.sum(data, function(d)
return d["Category" + catInt];
);
let avgValue = d3.sum(data, function(d)
return d["Category" + catInt];
) / data.length;
//sort data
data.sort( d3.select("#myCheckbox").property("checked")
? function(a, b) return b["Category" + catInt] - a["Category" + catInt];
: function(a, b) return sortIndex.indexOf(a.month) - sortIndex.indexOf(b.month);)
// set x domain
x.domain(data.map(function(d) return d.month; ));
g.selectAll(".axis.axis--x").transition()
.duration(Globalvar.durations)
.call(xAxis);
// Update rectangles
let bars = g.selectAll(".barEnter")
.data(data, function(d)
return d.month;
);
bars = bars
.enter()
.append("rect")
.attr("class", "barEnter") // Enter data reference
.attr("width", x.bandwidth())
.merge(bars);
bars.transition()
.duration(Globalvar.durations)
.attr("height", function(d)
return height - y(d["Category" + catInt]);
)
.attr("x", function(d)
return x(d.month);
)
.attr("y", function(d)
return y(d["Category" + catInt]);
);
bars.exit().remove();
// Update text on rectangles
let textUpdate = g.selectAll(".textEnter")
.data(data, function(d)
return d.month;
);
textUpdate = textUpdate.enter()
.append("text")
.style("text-shadow","1px 1px #777")
.attr("class", "textEnter") // Enter data reference
.attr("text-anchor","middle")
.attr("font-size",11)
.attr("fill","#fff")
.merge(textUpdate);
textUpdate.transition()
.duration(Globalvar.durations)
.attr("y", function(d)
return y(d["Category" + catInt]) + 15;
)
// Update text value
.text( function(d)
return d["Category" + catInt];
)
.attr("x", function(d)
return x(d.month) + x.bandwidth()/2;
)
// Update sum and avg value
g.selectAll("#totalValue").transition()
.duration(Globalvar.durations)
.text(sumOfAll + " Category " + catInt)
g.selectAll("#avgValue").transition()
.duration(Globalvar.durations)
.text(formatValue(avgValue))
afterLoad()
);
// Initialize csv data
function type(d)
d["Category" + catInt] = +d["Category" + catInt];
return d;
// Toggle csv data
function toggle()
if (document.getElementById('year').value == 'data2017')
Globalvar.csvShift = "data.csv" ;
else if
(document.getElementById('year').value == 'data2016')
Globalvar.csvShift = "data2.csv";
update();
</script>
</body>
</html>
javascript performance d3.js
add a comment |Â
up vote
2
down vote
favorite
In this chart I'm calling d3.csv
everytime I update the data, which if I understand correctly is a bad thing to do.
In this answer on S.O the answerer explains that d3.csv
is asynchronous and the data should only be loaded in once.
I understand why that is, but what I'm wondering now is what is a better way of doing this and if the way that I've done it in the sample code is ever acceptable.
<html>
<head>
<meta charset ="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
body
margin:auto;
width:850px;
font:10px arial;
padding:25px;
color:#555;
select
border: none;
border-bottom: 1px solid #ccc;
padding: 3px;
text-decoration: none;
font-size: 11px;
cursor: pointer;
select:focus
outline:0;
.sortCheck
float:right;
margin-top:-35px;
margin-right:190px;
#myCheckbox
position:relative;
top:3px;
/* --- Chart Css --- */
.barEnter
fill: steelblue;
opacity: .9;
.barEnter:hover
opacity: 1;
.axis--x path
display: none;
.grid--y path,
.grid--y text
display: none;
.grid--y line
opacity:.15;
</style>
</head>
<body onclick>
<h2 style="font-weight:lighter;">Mulitple datasets test</h2>
<!-- Selection Category -->
<b style="font-size:11px;">
Choose Category
</b>
<select id="category">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<!-- Selection New dataset -->
<span style="margin-left:30px;">
<b style="font-size:11px;">
Choose Year
</b>
<select id="year" onchange="toggle();">
<option value="data2017">2017</option>
<option value="data2016">2016</option>
</select>
</span>
<!-- Chart -->
<div id="chart"></div>
<!-- Sort dimension -->
<span class="sortCheck">Sort Values
<input type="checkbox" id="myCheckbox">
</span>
<script>
let Globalvar = ; // Global access variables
Globalvar.csvShift = "data.csv"; // CSV init
let formatValue = d3.format(",.0f");
let margin = top: 35, right: 145, bottom: 35, left: 45,
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
let x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
let xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y),
yGrid = d3.axisLeft(y).tickSize(-width);
let g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
let sideTextX = width + 30,
sideTextY = -height + height;
Globalvar.durations = 0;
function afterLoad()
Globalvar.durations = 750;
;
// Sum of value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY)
.text("Accumulated value: ")
g.append("text").attr("id","totalValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 20);
// Average value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 40)
.text("Average value: ")
g.append("text").attr("id","avgValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 60);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis grid--y");
// event handlers
d3.select("#myCheckbox").on('change', update);
d3.select("#category").on('change', update);
update();
var file, catInt;
function update()
file = Globalvar.csvShift
catInt = d3.select('#category').property('value');
d3.csv(file, type, function(error,data)
if(error) throw error;
var sortIndex = data.map(function(d) return d.month);
// Update domain
y.domain([0, d3.max(data, function(d)
return d["Category" + catInt]; )
]).nice();
// Update axis
g.selectAll(".axis.axis--y").transition()
.duration(Globalvar.durations)
.call(yAxis);
g.selectAll(".axis.grid--y").transition()
.duration(Globalvar.durations)
.call(yGrid);
// Sums and averages
let sumOfAll = d3.sum(data, function(d)
return d["Category" + catInt];
);
let avgValue = d3.sum(data, function(d)
return d["Category" + catInt];
) / data.length;
//sort data
data.sort( d3.select("#myCheckbox").property("checked")
? function(a, b) return b["Category" + catInt] - a["Category" + catInt];
: function(a, b) return sortIndex.indexOf(a.month) - sortIndex.indexOf(b.month);)
// set x domain
x.domain(data.map(function(d) return d.month; ));
g.selectAll(".axis.axis--x").transition()
.duration(Globalvar.durations)
.call(xAxis);
// Update rectangles
let bars = g.selectAll(".barEnter")
.data(data, function(d)
return d.month;
);
bars = bars
.enter()
.append("rect")
.attr("class", "barEnter") // Enter data reference
.attr("width", x.bandwidth())
.merge(bars);
bars.transition()
.duration(Globalvar.durations)
.attr("height", function(d)
return height - y(d["Category" + catInt]);
)
.attr("x", function(d)
return x(d.month);
)
.attr("y", function(d)
return y(d["Category" + catInt]);
);
bars.exit().remove();
// Update text on rectangles
let textUpdate = g.selectAll(".textEnter")
.data(data, function(d)
return d.month;
);
textUpdate = textUpdate.enter()
.append("text")
.style("text-shadow","1px 1px #777")
.attr("class", "textEnter") // Enter data reference
.attr("text-anchor","middle")
.attr("font-size",11)
.attr("fill","#fff")
.merge(textUpdate);
textUpdate.transition()
.duration(Globalvar.durations)
.attr("y", function(d)
return y(d["Category" + catInt]) + 15;
)
// Update text value
.text( function(d)
return d["Category" + catInt];
)
.attr("x", function(d)
return x(d.month) + x.bandwidth()/2;
)
// Update sum and avg value
g.selectAll("#totalValue").transition()
.duration(Globalvar.durations)
.text(sumOfAll + " Category " + catInt)
g.selectAll("#avgValue").transition()
.duration(Globalvar.durations)
.text(formatValue(avgValue))
afterLoad()
);
// Initialize csv data
function type(d)
d["Category" + catInt] = +d["Category" + catInt];
return d;
// Toggle csv data
function toggle()
if (document.getElementById('year').value == 'data2017')
Globalvar.csvShift = "data.csv" ;
else if
(document.getElementById('year').value == 'data2016')
Globalvar.csvShift = "data2.csv";
update();
</script>
</body>
</html>
javascript performance d3.js
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
In this chart I'm calling d3.csv
everytime I update the data, which if I understand correctly is a bad thing to do.
In this answer on S.O the answerer explains that d3.csv
is asynchronous and the data should only be loaded in once.
I understand why that is, but what I'm wondering now is what is a better way of doing this and if the way that I've done it in the sample code is ever acceptable.
<html>
<head>
<meta charset ="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
body
margin:auto;
width:850px;
font:10px arial;
padding:25px;
color:#555;
select
border: none;
border-bottom: 1px solid #ccc;
padding: 3px;
text-decoration: none;
font-size: 11px;
cursor: pointer;
select:focus
outline:0;
.sortCheck
float:right;
margin-top:-35px;
margin-right:190px;
#myCheckbox
position:relative;
top:3px;
/* --- Chart Css --- */
.barEnter
fill: steelblue;
opacity: .9;
.barEnter:hover
opacity: 1;
.axis--x path
display: none;
.grid--y path,
.grid--y text
display: none;
.grid--y line
opacity:.15;
</style>
</head>
<body onclick>
<h2 style="font-weight:lighter;">Mulitple datasets test</h2>
<!-- Selection Category -->
<b style="font-size:11px;">
Choose Category
</b>
<select id="category">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<!-- Selection New dataset -->
<span style="margin-left:30px;">
<b style="font-size:11px;">
Choose Year
</b>
<select id="year" onchange="toggle();">
<option value="data2017">2017</option>
<option value="data2016">2016</option>
</select>
</span>
<!-- Chart -->
<div id="chart"></div>
<!-- Sort dimension -->
<span class="sortCheck">Sort Values
<input type="checkbox" id="myCheckbox">
</span>
<script>
let Globalvar = ; // Global access variables
Globalvar.csvShift = "data.csv"; // CSV init
let formatValue = d3.format(",.0f");
let margin = top: 35, right: 145, bottom: 35, left: 45,
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
let x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
let xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y),
yGrid = d3.axisLeft(y).tickSize(-width);
let g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
let sideTextX = width + 30,
sideTextY = -height + height;
Globalvar.durations = 0;
function afterLoad()
Globalvar.durations = 750;
;
// Sum of value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY)
.text("Accumulated value: ")
g.append("text").attr("id","totalValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 20);
// Average value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 40)
.text("Average value: ")
g.append("text").attr("id","avgValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 60);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis grid--y");
// event handlers
d3.select("#myCheckbox").on('change', update);
d3.select("#category").on('change', update);
update();
var file, catInt;
function update()
file = Globalvar.csvShift
catInt = d3.select('#category').property('value');
d3.csv(file, type, function(error,data)
if(error) throw error;
var sortIndex = data.map(function(d) return d.month);
// Update domain
y.domain([0, d3.max(data, function(d)
return d["Category" + catInt]; )
]).nice();
// Update axis
g.selectAll(".axis.axis--y").transition()
.duration(Globalvar.durations)
.call(yAxis);
g.selectAll(".axis.grid--y").transition()
.duration(Globalvar.durations)
.call(yGrid);
// Sums and averages
let sumOfAll = d3.sum(data, function(d)
return d["Category" + catInt];
);
let avgValue = d3.sum(data, function(d)
return d["Category" + catInt];
) / data.length;
//sort data
data.sort( d3.select("#myCheckbox").property("checked")
? function(a, b) return b["Category" + catInt] - a["Category" + catInt];
: function(a, b) return sortIndex.indexOf(a.month) - sortIndex.indexOf(b.month);)
// set x domain
x.domain(data.map(function(d) return d.month; ));
g.selectAll(".axis.axis--x").transition()
.duration(Globalvar.durations)
.call(xAxis);
// Update rectangles
let bars = g.selectAll(".barEnter")
.data(data, function(d)
return d.month;
);
bars = bars
.enter()
.append("rect")
.attr("class", "barEnter") // Enter data reference
.attr("width", x.bandwidth())
.merge(bars);
bars.transition()
.duration(Globalvar.durations)
.attr("height", function(d)
return height - y(d["Category" + catInt]);
)
.attr("x", function(d)
return x(d.month);
)
.attr("y", function(d)
return y(d["Category" + catInt]);
);
bars.exit().remove();
// Update text on rectangles
let textUpdate = g.selectAll(".textEnter")
.data(data, function(d)
return d.month;
);
textUpdate = textUpdate.enter()
.append("text")
.style("text-shadow","1px 1px #777")
.attr("class", "textEnter") // Enter data reference
.attr("text-anchor","middle")
.attr("font-size",11)
.attr("fill","#fff")
.merge(textUpdate);
textUpdate.transition()
.duration(Globalvar.durations)
.attr("y", function(d)
return y(d["Category" + catInt]) + 15;
)
// Update text value
.text( function(d)
return d["Category" + catInt];
)
.attr("x", function(d)
return x(d.month) + x.bandwidth()/2;
)
// Update sum and avg value
g.selectAll("#totalValue").transition()
.duration(Globalvar.durations)
.text(sumOfAll + " Category " + catInt)
g.selectAll("#avgValue").transition()
.duration(Globalvar.durations)
.text(formatValue(avgValue))
afterLoad()
);
// Initialize csv data
function type(d)
d["Category" + catInt] = +d["Category" + catInt];
return d;
// Toggle csv data
function toggle()
if (document.getElementById('year').value == 'data2017')
Globalvar.csvShift = "data.csv" ;
else if
(document.getElementById('year').value == 'data2016')
Globalvar.csvShift = "data2.csv";
update();
</script>
</body>
</html>
javascript performance d3.js
In this chart I'm calling d3.csv
everytime I update the data, which if I understand correctly is a bad thing to do.
In this answer on S.O the answerer explains that d3.csv
is asynchronous and the data should only be loaded in once.
I understand why that is, but what I'm wondering now is what is a better way of doing this and if the way that I've done it in the sample code is ever acceptable.
<html>
<head>
<meta charset ="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<style>
body
margin:auto;
width:850px;
font:10px arial;
padding:25px;
color:#555;
select
border: none;
border-bottom: 1px solid #ccc;
padding: 3px;
text-decoration: none;
font-size: 11px;
cursor: pointer;
select:focus
outline:0;
.sortCheck
float:right;
margin-top:-35px;
margin-right:190px;
#myCheckbox
position:relative;
top:3px;
/* --- Chart Css --- */
.barEnter
fill: steelblue;
opacity: .9;
.barEnter:hover
opacity: 1;
.axis--x path
display: none;
.grid--y path,
.grid--y text
display: none;
.grid--y line
opacity:.15;
</style>
</head>
<body onclick>
<h2 style="font-weight:lighter;">Mulitple datasets test</h2>
<!-- Selection Category -->
<b style="font-size:11px;">
Choose Category
</b>
<select id="category">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<!-- Selection New dataset -->
<span style="margin-left:30px;">
<b style="font-size:11px;">
Choose Year
</b>
<select id="year" onchange="toggle();">
<option value="data2017">2017</option>
<option value="data2016">2016</option>
</select>
</span>
<!-- Chart -->
<div id="chart"></div>
<!-- Sort dimension -->
<span class="sortCheck">Sort Values
<input type="checkbox" id="myCheckbox">
</span>
<script>
let Globalvar = ; // Global access variables
Globalvar.csvShift = "data.csv"; // CSV init
let formatValue = d3.format(",.0f");
let margin = top: 35, right: 145, bottom: 35, left: 45,
width = 700 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
let x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
let xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y),
yGrid = d3.axisLeft(y).tickSize(-width);
let g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
let sideTextX = width + 30,
sideTextY = -height + height;
Globalvar.durations = 0;
function afterLoad()
Globalvar.durations = 750;
;
// Sum of value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY)
.text("Accumulated value: ")
g.append("text").attr("id","totalValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 20);
// Average value
g.append("text")
.attr("fill","#555")
.attr("font-weight","bold")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 40)
.text("Average value: ")
g.append("text").attr("id","avgValue")
.attr("fill","#555")
.attr("font-size",11)
.attr("x", sideTextX)
.attr("y", sideTextY + 60);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis grid--y");
// event handlers
d3.select("#myCheckbox").on('change', update);
d3.select("#category").on('change', update);
update();
var file, catInt;
function update()
file = Globalvar.csvShift
catInt = d3.select('#category').property('value');
d3.csv(file, type, function(error,data)
if(error) throw error;
var sortIndex = data.map(function(d) return d.month);
// Update domain
y.domain([0, d3.max(data, function(d)
return d["Category" + catInt]; )
]).nice();
// Update axis
g.selectAll(".axis.axis--y").transition()
.duration(Globalvar.durations)
.call(yAxis);
g.selectAll(".axis.grid--y").transition()
.duration(Globalvar.durations)
.call(yGrid);
// Sums and averages
let sumOfAll = d3.sum(data, function(d)
return d["Category" + catInt];
);
let avgValue = d3.sum(data, function(d)
return d["Category" + catInt];
) / data.length;
//sort data
data.sort( d3.select("#myCheckbox").property("checked")
? function(a, b) return b["Category" + catInt] - a["Category" + catInt];
: function(a, b) return sortIndex.indexOf(a.month) - sortIndex.indexOf(b.month);)
// set x domain
x.domain(data.map(function(d) return d.month; ));
g.selectAll(".axis.axis--x").transition()
.duration(Globalvar.durations)
.call(xAxis);
// Update rectangles
let bars = g.selectAll(".barEnter")
.data(data, function(d)
return d.month;
);
bars = bars
.enter()
.append("rect")
.attr("class", "barEnter") // Enter data reference
.attr("width", x.bandwidth())
.merge(bars);
bars.transition()
.duration(Globalvar.durations)
.attr("height", function(d)
return height - y(d["Category" + catInt]);
)
.attr("x", function(d)
return x(d.month);
)
.attr("y", function(d)
return y(d["Category" + catInt]);
);
bars.exit().remove();
// Update text on rectangles
let textUpdate = g.selectAll(".textEnter")
.data(data, function(d)
return d.month;
);
textUpdate = textUpdate.enter()
.append("text")
.style("text-shadow","1px 1px #777")
.attr("class", "textEnter") // Enter data reference
.attr("text-anchor","middle")
.attr("font-size",11)
.attr("fill","#fff")
.merge(textUpdate);
textUpdate.transition()
.duration(Globalvar.durations)
.attr("y", function(d)
return y(d["Category" + catInt]) + 15;
)
// Update text value
.text( function(d)
return d["Category" + catInt];
)
.attr("x", function(d)
return x(d.month) + x.bandwidth()/2;
)
// Update sum and avg value
g.selectAll("#totalValue").transition()
.duration(Globalvar.durations)
.text(sumOfAll + " Category " + catInt)
g.selectAll("#avgValue").transition()
.duration(Globalvar.durations)
.text(formatValue(avgValue))
afterLoad()
);
// Initialize csv data
function type(d)
d["Category" + catInt] = +d["Category" + catInt];
return d;
// Toggle csv data
function toggle()
if (document.getElementById('year').value == 'data2017')
Globalvar.csvShift = "data.csv" ;
else if
(document.getElementById('year').value == 'data2016')
Globalvar.csvShift = "data2.csv";
update();
</script>
</body>
</html>
javascript performance d3.js
edited Jan 17 at 14:00
asked Jan 17 at 12:34
Robert Andersson
1667
1667
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
Well, I am the answerer that gave you that advice on S.O. The reason, or reasons, are actually quite simple.
Right now, every time you change the dropdown menu, you call the update
function:
d3.select("#selectbox").on('change', update);
And then, inside update
, you have this:
function update()
d3.csv("data.csv", function(error, data)
//code here
)
Which is not a good design. These are the reasons why:
d3.csv
is asynchronous. That means that, every time you call it, it will load the CSV, parse it and run the code inside the callback (while the code outside it keeps running as the CSV is being loaded/parsed). You really should not used3.csv
inside a function called by a change in a dropdown menu. Right now you're not seeing any performance issue because your CSV is not that big. However, if you had a big CSV, or a slow connection, the difference is noticeable.- This is the most important reason: that CSV is the same! Why are you loading it again and again when the user changes the dropdown? It's just an unnecessary waste of resources, which can in certain situations cause a bad user experience.
All that being said, this is the correct design:
d3.csv("data.csv", function(error, data)
d3.select("#selectbox").on('change', update);
function update()
//code here
)
Here is your code with that design:
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
PS: as I cant' use d3.csv
in the Code Review snippet, I'm using d3.csvParse
instead, with the CSV content in a template literal. For completeness, here is the updated Plunker with the pattern I suggested: https://plnkr.co/edit/D9cvHoIw98CJ2xXNPNEj?p=preview
Thank you! What if I have more than one csv file? Should I use something likequeue().defer
?
â Robert Andersson
Jan 17 at 13:51
1
@RobertAndersson Yes, or you can nest thed3.csv
functions, like this: stackoverflow.com/a/41193922/5768908
â Gerardo Furtado
Jan 17 at 13:52
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Well, I am the answerer that gave you that advice on S.O. The reason, or reasons, are actually quite simple.
Right now, every time you change the dropdown menu, you call the update
function:
d3.select("#selectbox").on('change', update);
And then, inside update
, you have this:
function update()
d3.csv("data.csv", function(error, data)
//code here
)
Which is not a good design. These are the reasons why:
d3.csv
is asynchronous. That means that, every time you call it, it will load the CSV, parse it and run the code inside the callback (while the code outside it keeps running as the CSV is being loaded/parsed). You really should not used3.csv
inside a function called by a change in a dropdown menu. Right now you're not seeing any performance issue because your CSV is not that big. However, if you had a big CSV, or a slow connection, the difference is noticeable.- This is the most important reason: that CSV is the same! Why are you loading it again and again when the user changes the dropdown? It's just an unnecessary waste of resources, which can in certain situations cause a bad user experience.
All that being said, this is the correct design:
d3.csv("data.csv", function(error, data)
d3.select("#selectbox").on('change', update);
function update()
//code here
)
Here is your code with that design:
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
PS: as I cant' use d3.csv
in the Code Review snippet, I'm using d3.csvParse
instead, with the CSV content in a template literal. For completeness, here is the updated Plunker with the pattern I suggested: https://plnkr.co/edit/D9cvHoIw98CJ2xXNPNEj?p=preview
Thank you! What if I have more than one csv file? Should I use something likequeue().defer
?
â Robert Andersson
Jan 17 at 13:51
1
@RobertAndersson Yes, or you can nest thed3.csv
functions, like this: stackoverflow.com/a/41193922/5768908
â Gerardo Furtado
Jan 17 at 13:52
add a comment |Â
up vote
1
down vote
accepted
Well, I am the answerer that gave you that advice on S.O. The reason, or reasons, are actually quite simple.
Right now, every time you change the dropdown menu, you call the update
function:
d3.select("#selectbox").on('change', update);
And then, inside update
, you have this:
function update()
d3.csv("data.csv", function(error, data)
//code here
)
Which is not a good design. These are the reasons why:
d3.csv
is asynchronous. That means that, every time you call it, it will load the CSV, parse it and run the code inside the callback (while the code outside it keeps running as the CSV is being loaded/parsed). You really should not used3.csv
inside a function called by a change in a dropdown menu. Right now you're not seeing any performance issue because your CSV is not that big. However, if you had a big CSV, or a slow connection, the difference is noticeable.- This is the most important reason: that CSV is the same! Why are you loading it again and again when the user changes the dropdown? It's just an unnecessary waste of resources, which can in certain situations cause a bad user experience.
All that being said, this is the correct design:
d3.csv("data.csv", function(error, data)
d3.select("#selectbox").on('change', update);
function update()
//code here
)
Here is your code with that design:
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
PS: as I cant' use d3.csv
in the Code Review snippet, I'm using d3.csvParse
instead, with the CSV content in a template literal. For completeness, here is the updated Plunker with the pattern I suggested: https://plnkr.co/edit/D9cvHoIw98CJ2xXNPNEj?p=preview
Thank you! What if I have more than one csv file? Should I use something likequeue().defer
?
â Robert Andersson
Jan 17 at 13:51
1
@RobertAndersson Yes, or you can nest thed3.csv
functions, like this: stackoverflow.com/a/41193922/5768908
â Gerardo Furtado
Jan 17 at 13:52
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Well, I am the answerer that gave you that advice on S.O. The reason, or reasons, are actually quite simple.
Right now, every time you change the dropdown menu, you call the update
function:
d3.select("#selectbox").on('change', update);
And then, inside update
, you have this:
function update()
d3.csv("data.csv", function(error, data)
//code here
)
Which is not a good design. These are the reasons why:
d3.csv
is asynchronous. That means that, every time you call it, it will load the CSV, parse it and run the code inside the callback (while the code outside it keeps running as the CSV is being loaded/parsed). You really should not used3.csv
inside a function called by a change in a dropdown menu. Right now you're not seeing any performance issue because your CSV is not that big. However, if you had a big CSV, or a slow connection, the difference is noticeable.- This is the most important reason: that CSV is the same! Why are you loading it again and again when the user changes the dropdown? It's just an unnecessary waste of resources, which can in certain situations cause a bad user experience.
All that being said, this is the correct design:
d3.csv("data.csv", function(error, data)
d3.select("#selectbox").on('change', update);
function update()
//code here
)
Here is your code with that design:
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
PS: as I cant' use d3.csv
in the Code Review snippet, I'm using d3.csvParse
instead, with the CSV content in a template literal. For completeness, here is the updated Plunker with the pattern I suggested: https://plnkr.co/edit/D9cvHoIw98CJ2xXNPNEj?p=preview
Well, I am the answerer that gave you that advice on S.O. The reason, or reasons, are actually quite simple.
Right now, every time you change the dropdown menu, you call the update
function:
d3.select("#selectbox").on('change', update);
And then, inside update
, you have this:
function update()
d3.csv("data.csv", function(error, data)
//code here
)
Which is not a good design. These are the reasons why:
d3.csv
is asynchronous. That means that, every time you call it, it will load the CSV, parse it and run the code inside the callback (while the code outside it keeps running as the CSV is being loaded/parsed). You really should not used3.csv
inside a function called by a change in a dropdown menu. Right now you're not seeing any performance issue because your CSV is not that big. However, if you had a big CSV, or a slow connection, the difference is noticeable.- This is the most important reason: that CSV is the same! Why are you loading it again and again when the user changes the dropdown? It's just an unnecessary waste of resources, which can in certain situations cause a bad user experience.
All that being said, this is the correct design:
d3.csv("data.csv", function(error, data)
d3.select("#selectbox").on('change', update);
function update()
//code here
)
Here is your code with that design:
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
PS: as I cant' use d3.csv
in the Code Review snippet, I'm using d3.csvParse
instead, with the CSV content in a template literal. For completeness, here is the updated Plunker with the pattern I suggested: https://plnkr.co/edit/D9cvHoIw98CJ2xXNPNEj?p=preview
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body
font: 10px arial;
margin: auto;
position: relative;
width: 930px;
padding: 25px;
.line
fill: none;
stroke: #555;
stroke-width: 1.5px;
/* === Axis === */
.axis--y .tick:not(.tick--one) line
stroke-opacity: .5;
stroke: #555;
shape-rendering: crispEdges;
.tick--one line
shape-rendering: crispEdges;
.axis--y path
display: none;
/* === Area === */
.area
fill-opacity: 0.6;
.area--below
fill: darkorange;
.area--above
fill: steelblue;
</style>
<body>
Choose a thing
<select id="selectbox">
<option value=" 1">Category 1</option>
<option value=" 2">Category 2</option>
</select>
<div id="chart"></div>
<script>
var csv = `date,Category 1,Category 2
20111001,63.4,62.7
20111002,58.0,59.9
20111003,53.3,59.1
20111004,55.7,58.8
20111005,64.2,58.7
20111006,58.8,57.0
20111007,57.9,56.7
20111008,61.8,56.8
20111009,69.3,56.7
20111010,71.2,60.1
20111011,68.7,61.1
20111012,61.8,61.5
20111013,63.0,64.3
20111014,66.9,67.1
20111015,61.7,64.6
20111016,61.8,61.6
20111017,62.8,61.1
20111018,60.8,59.2
20111019,62.1,58.9
20111020,65.1,57.2
20111021,55.6,56.4
20111022,54.4,60.7
20111023,54.4,65.1
20111024,54.8,60.9
20111025,57.9,56.1
20111026,54.6,54.6
20111027,54.4,56.1
20111028,42.5,58.1
20111029,40.9,57.5
20111030,38.6,57.7
20111031,44.2,55.1
20111101,49.6,57.9
20111102,47.2,64.6
20111103,50.1,56.2
20111104,50.1,50.5
20111105,43.5,51.3
20111106,43.8,52.6
20111107,48.9,51.4
20111108,55.5,50.6
20111109,53.7,54.6
20111110,57.7,55.6
20111111,48.5,53.9
20111112,46.8,54.0
20111113,51.1,53.8
20111114,56.8,53.5
20111115,59.7,53.4
20111116,56.5,52.2
20111117,49.6,52.7
20111118,41.5,53.1
20111119,44.3,49.0
20111120,54.0,50.4
20111121,54.1,51.1
20111122,49.4,52.3
20111123,50.0,54.6
20111124,44.0,55.1
20111125,50.3,51.5
20111126,52.1,53.6
20111127,49.6,52.3
20111128,57.2,51.0
20111129,59.1,49.5
20111130,50.6,49.8
20111201,44.3,60.4
20111202,43.9,62.2
20111203,42.1,58.3
20111204,43.9,52.7
20111205,50.2,51.5
20111206,54.2,49.9
20111207,54.6,48.6
20111208,43.4,46.4
20111209,42.2,49.8
20111210,45.0,52.1
20111211,33.8,48.8
20111212,36.8,47.4
20111213,38.6,47.2
20111214,41.9,46.1
20111215,49.6,48.8
20111216,50.2,47.9
20111217,40.6,49.8
20111218,29.1,49.1
20111219,33.7,48.3
20111220,45.8,49.3
20111221,47.4,48.4
20111222,54.4,53.3
20111223,47.8,47.5
20111224,34.9,47.9
20111225,35.9,48.9
20111226,43.6,45.9
20111227,42.9,47.2
20111228,46.2,48.9
20111229,30.8,50.9
20111230,40.8,52.9
20111231,49.8,50.1
20120101,46.3,53.9
20120102,43.2,53.1
20120103,30.3,49.7
20120104,19.2,52.7
20120105,32.1,52.6
20120106,41.2,49.0
20120107,47.0,51.0
20120108,46.0,56.8
20120109,34.7,52.3
20120110,39.4,51.6
20120111,40.4,49.8
20120112,45.4,51.9
20120113,40.7,53.7
20120114,30.4,52.9
20120115,23.9,49.7
20120116,22.6,45.3
20120117,39.8,43.6
20120118,43.2,45.0
20120119,26.3,47.3
20120120,32.8,51.4
20120121,27.4,53.7
20120122,25.0,48.3
20120123,39.4,52.9
20120124,48.7,49.1
20120125,43.0,52.1
20120126,37.1,53.6
20120127,48.2,50.4
20120128,43.7,50.3
20120129,40.1,53.8
20120130,38.0,51.9
20120131,43.5,50.0
20120201,50.4,50.0
20120202,45.8,51.3
20120203,37.5,51.5
20120204,40.8,52.0
20120205,36.5,53.8
20120206,39.1,54.6
20120207,43.2,54.3
20120208,36.5,51.9
20120209,36.5,53.8
20120210,38.3,53.9
20120211,36.9,52.3
20120212,29.7,50.1
20120213,33.1,49.5
20120214,39.6,48.6
20120215,42.3,49.9
20120216,39.7,52.4
20120217,46.0,49.9
20120218,41.2,51.6
20120219,39.8,47.8
20120220,38.1,48.7
20120221,37.1,49.7
20120222,45.5,53.4
20120223,50.6,54.1
20120224,42.7,55.9
20120225,42.6,51.7
20120226,36.9,47.7
20120227,40.9,45.4
20120228,45.9,47.0
20120229,40.7,49.8
20120301,41.3,48.9
20120302,36.8,48.1
20120303,47.6,50.7
20120304,44.2,55.0
20120305,38.5,48.8
20120306,32.9,48.4
20120307,43.3,49.9
20120308,51.2,49.2
20120309,47.8,51.7
20120310,37.2,49.3
20120311,42.9,50.0
20120312,48.8,48.6
20120313,52.6,53.9
20120314,60.5,55.2
20120315,47.2,55.9
20120316,44.7,54.6
20120317,48.2,48.2
20120318,48.2,47.1
20120319,53.1,45.8
20120320,57.8,49.7
20120321,57.5,51.4
20120322,57.3,51.4
20120323,61.7,48.4
20120324,55.8,49.0
20120325,48.4,46.4
20120326,49.8,49.7
20120327,39.6,54.1
20120328,49.7,54.6
20120329,56.8,52.3
20120330,46.5,54.5
20120331,42.2,56.2
20120401,45.3,51.1
20120402,48.1,50.5
20120403,51.2,52.2
20120404,61.0,50.6
20120405,50.7,47.9
20120406,48.0,47.4
20120407,51.1,49.4
20120408,55.7,50.0
20120409,58.3,51.3
20120410,55.0,53.8
20120411,49.0,52.9
20120412,51.7,53.9
20120413,53.1,50.2
20120414,55.2,50.9
20120415,62.3,51.5
20120416,62.9,51.9
20120417,69.3,53.2
20120418,59.0,53.0
20120419,54.1,55.1
20120420,56.5,55.8
20120421,58.2,58.0
20120422,52.4,52.8
20120423,51.6,55.1
20120424,49.3,57.9
20120425,52.5,57.5
20120426,50.5,55.3
20120427,51.9,53.5
20120428,47.4,54.7
20120429,54.1,54.0
20120430,51.9,53.4
20120501,57.4,52.7
20120502,53.7,50.7
20120503,53.1,52.6
20120504,57.2,53.4
20120505,57.0,53.1
20120506,56.6,56.5
20120507,54.6,55.3
20120508,57.9,52.0
20120509,59.2,52.4
20120510,61.1,53.4
20120511,59.7,53.1
20120512,64.1,49.9
20120513,65.3,52.0
20120514,64.2,56.0
20120515,62.0,53.0
20120516,63.8,51.0
20120517,64.5,51.4
20120518,61.0,52.2
20120519,62.6,52.4
20120520,66.2,54.5
20120521,62.7,52.8
20120522,63.7,53.9
20120523,66.4,56.5
20120524,64.5,54.7
20120525,65.4,52.5
20120526,69.4,52.1
20120527,71.9,52.2
20120528,74.4,52.9
20120529,75.9,52.1
20120530,72.9,52.1
20120531,72.5,53.3
20120601,67.2,54.8
20120602,68.3,54.0
20120603,67.7,52.3
20120604,61.9,55.3
20120605,58.3,53.5
20120606,61.7,54.1
20120607,66.7,53.9
20120608,68.7,54.4
20120609,72.2,55.0
20120610,72.6,60.0
20120611,69.2,57.2
20120612,66.9,55.1
20120613,66.7,53.3
20120614,67.7,53.4
20120615,68.5,54.6
20120616,67.5,57.0
20120617,64.2,55.6
20120618,61.7,52.5
20120619,66.4,53.9
20120620,77.9,55.3
20120621,88.3,53.3
20120622,82.2,54.1
20120623,77.0,55.2
20120624,75.4,55.8
20120625,70.9,56.8
20120626,65.9,57.5
20120627,73.5,57.7
20120628,77.4,56.6
20120629,79.6,56.4
20120630,84.2,58.4
20120701,81.8,58.8
20120702,82.5,56.4
20120703,80.2,56.5
20120704,77.8,55.8
20120705,86.1,54.8
20120706,79.9,54.9
20120707,83.5,54.7
20120708,81.5,52.8
20120709,77.8,53.7
20120710,76.1,53.1
20120711,76.3,52.7
20120712,75.8,52.0
20120713,77.2,53.4
20120714,79.3,54.0
20120715,78.9,54.0
20120716,79.6,54.5
20120717,83.3,56.7
20120718,84.3,57.5
20120719,75.1,57.1
20120720,68.4,58.1
20120721,68.4,57.6
20120722,72.2,56.0
20120723,75.6,56.6
20120724,82.6,57.8
20120725,78.4,57.5
20120726,77.0,56.4
20120727,79.4,55.3
20120728,77.4,55.0
20120729,72.5,55.6
20120730,72.9,55.6
20120731,73.6,55.9
20120801,75.0,55.4
20120802,77.7,54.4
20120803,79.7,53.7
20120804,79.6,54.1
20120805,81.5,57.8
20120806,80.0,58.2
20120807,75.7,58.0
20120808,77.8,57.0
20120809,78.6,55.0
20120810,77.8,54.8
20120811,78.5,53.0
20120812,78.8,52.5
20120813,78.6,53.3
20120814,76.8,53.9
20120815,76.7,56.2
20120816,75.9,57.1
20120817,77.6,55.3
20120818,72.6,56.2
20120819,70.4,54.3
20120820,71.8,53.1
20120821,73.6,53.4
20120822,74.7,54.5
20120823,74.6,55.7
20120824,76.0,54.8
20120825,76.2,53.8
20120826,73.4,56.5
20120827,74.6,58.3
20120828,79.4,58.7
20120829,74.7,57.5
20120830,73.5,55.9
20120831,77.9,55.4
20120901,80.7,55.7
20120902,75.1,53.1
20120903,73.5,53.5
20120904,73.5,52.5
20120905,77.7,54.5
20120906,74.2,56.3
20120907,76.0,56.4
20120908,77.1,56.5
20120909,69.7,56.4
20120910,67.8,55.4
20120911,64.0,56.2
20120912,68.1,55.7
20120913,69.3,54.3
20120914,70.0,55.2
20120915,69.3,54.3
20120916,66.3,52.9
20120917,67.0,54.8
20120918,72.8,54.8
20120919,67.2,56.8
20120920,62.1,55.4
20120921,64.0,55.8
20120922,65.5,55.9
20120923,65.7,52.8
20120924,60.4,54.5
20120925,63.2,53.3
20120926,68.5,53.6
20120927,69.2,52.1
20120928,68.7,52.6
20120929,62.5,53.9
20120930,62.3,55.1`;
var margin =
top: 20,
right: 80,
bottom: 30,
left: 45
,
width = 960 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y%m%d");
var formatPercent = d3.format("+.0%"),
formatValue = d3.format(",.1f"),
formatChange = function(x)
return formatPercent(x - 1);
;
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0])
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y).tickSize(-width, 0).tickFormat(formatChange);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y(function(d)
return y(d.city);
);
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d)
return x(d.date);
)
.y1(function(d)
return y(d.city);
);
var g = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var gY = g.append("g")
.attr("class", "axis axis--y");
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
var defs = g.append("defs");
var durations = 0;
var afterLoad = () => durations = 750;
var data = d3.csvParse(csv, function(d, _, columns)
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i)
d[c = columns[i]] = +d[c];
return d;
)
update();
var VALUE, baseValue;
function update()
d3.selectAll('clipPath').remove();
VALUE = d3.select('#selectbox').property('value');
baseValue = data[0]["Category" + VALUE];
var keys = data.columns.slice(1, 2);
var copy = ;
keys.forEach(function(t)
t = t.slice(0, -2) // Slice last two letters
copy.push(t) // Push sliced strings into copy array
);
var cities = copy.map(function(id)
return
id: id,
values: data.map(function(d)
return
date: d.date,
city: d[id + VALUE] / baseValue
;
)
;
);
x.domain(d3.extent(data, function(d)
return d.date;
));
y.domain([
d3.min(cities, function(c)
return d3.min(c.values, function(d)
return d.city;
);
),
d3.max(cities, function(c)
return d3.max(c.values, function(d)
return d.city;
);
)
]).nice();
area.y0(y(1));
yAxis.tickValues(d3.scaleLinear()
.domain(y.domain())
.ticks(10));
gY.transition().duration(durations).call(yAxis);
gY.selectAll(".tick")
.classed("tick--one", function(d)
return Math.abs(d - 1) < 1e-6;
);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
defs.append("clipPath")
.attr("id", "clip-above")
.append("rect");
g.selectAll("#clip-above>rect")
.transition().duration(durations)
.attr("width", width)
.attr("height", y(1));
defs.append("clipPath")
.attr("id", "clip-below")
.append("rect");
g.selectAll("#clip-below>rect")
.transition().duration(durations)
.attr("y", y(1))
.attr("width", width)
.attr("height", height - y(1));
// ========= Above Clip =========
var above = g.selectAll(".above")
.data(cities);
above = above
.enter()
.append("path")
.attr("class", "area area--above above")
.attr("clip-path", "url(#clip-above)")
.merge(above);
above.transition()
.duration(durations)
.attr("clip-path", "url(#clip-above)")
.attr("d", function(d)
return area(d.values)
);
// ========= Below Clip =========
var below = g.selectAll(".below")
.data(cities);
below = below
.enter()
.append("path")
.attr("class", "area area--below below")
.attr("clip-path", "url(#clip-below)")
.merge(below);
below.transition()
.duration(durations)
.attr("clip-path", "url(#clip-below)")
.attr("d", function(d)
return area(d.values)
);
// ========= Line Path =========
var cityLine = g.selectAll(".cities")
.data(cities);
cityLine = cityLine
.enter()
.append("path")
.attr("class", "line cities")
.merge(cityLine);
cityLine.transition()
.duration(durations)
.attr("d", function(d)
return line(d.values)
);
afterLoad();
d3.select("#selectbox").on('change', update);
</script>
</body>
edited Jan 17 at 14:26
answered Jan 17 at 13:44
Gerardo Furtado
1,1442420
1,1442420
Thank you! What if I have more than one csv file? Should I use something likequeue().defer
?
â Robert Andersson
Jan 17 at 13:51
1
@RobertAndersson Yes, or you can nest thed3.csv
functions, like this: stackoverflow.com/a/41193922/5768908
â Gerardo Furtado
Jan 17 at 13:52
add a comment |Â
Thank you! What if I have more than one csv file? Should I use something likequeue().defer
?
â Robert Andersson
Jan 17 at 13:51
1
@RobertAndersson Yes, or you can nest thed3.csv
functions, like this: stackoverflow.com/a/41193922/5768908
â Gerardo Furtado
Jan 17 at 13:52
Thank you! What if I have more than one csv file? Should I use something like
queue().defer
?â Robert Andersson
Jan 17 at 13:51
Thank you! What if I have more than one csv file? Should I use something like
queue().defer
?â Robert Andersson
Jan 17 at 13:51
1
1
@RobertAndersson Yes, or you can nest the
d3.csv
functions, like this: stackoverflow.com/a/41193922/5768908â Gerardo Furtado
Jan 17 at 13:52
@RobertAndersson Yes, or you can nest the
d3.csv
functions, like this: stackoverflow.com/a/41193922/5768908â Gerardo Furtado
Jan 17 at 13:52
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185300%2fupdating-data-in-d3js%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password