Restructuring a csv file with d3js
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
In my code below I have restructured the following csv file from something like this:
date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
To this:
date: "2017-01", E: 3, U: 1
Using d3.nest()
with a rollup
method.
The only thing is that I'm mapping out the type values somewhat manually like this:
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
always expecting the types to be in order. I do this by simply sorting the data by type
and then re-sort by date
again.
What I basically want to know is if there's a better way of achieving this or if there's a step or two that I can omit from the code making it more efficient.
Here's all the code:
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
javascript d3.js
add a comment |Â
up vote
2
down vote
favorite
In my code below I have restructured the following csv file from something like this:
date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
To this:
date: "2017-01", E: 3, U: 1
Using d3.nest()
with a rollup
method.
The only thing is that I'm mapping out the type values somewhat manually like this:
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
always expecting the types to be in order. I do this by simply sorting the data by type
and then re-sort by date
again.
What I basically want to know is if there's a better way of achieving this or if there's a step or two that I can omit from the code making it more efficient.
Here's all the code:
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
javascript d3.js
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
In my code below I have restructured the following csv file from something like this:
date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
To this:
date: "2017-01", E: 3, U: 1
Using d3.nest()
with a rollup
method.
The only thing is that I'm mapping out the type values somewhat manually like this:
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
always expecting the types to be in order. I do this by simply sorting the data by type
and then re-sort by date
again.
What I basically want to know is if there's a better way of achieving this or if there's a step or two that I can omit from the code making it more efficient.
Here's all the code:
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
javascript d3.js
In my code below I have restructured the following csv file from something like this:
date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
To this:
date: "2017-01", E: 3, U: 1
Using d3.nest()
with a rollup
method.
The only thing is that I'm mapping out the type values somewhat manually like this:
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
always expecting the types to be in order. I do this by simply sorting the data by type
and then re-sort by date
again.
What I basically want to know is if there's a better way of achieving this or if there's a step or two that I can omit from the code making it more efficient.
Here's all the code:
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
var csvData =
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var durations = 0;
var parseTime = d3.timeParse("%Y-%m");
var margin = top: 25, right: 25, bottom: 25, left: 25,
width = 420 - margin.left - margin.right,
height = 185 - margin.top - margin.bottom;
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 x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%B"))
.ticks(3);
var yAxis = d3.axisLeft(y).ticks(4);
var line = d3.line()
.curve(d3.curveCardinal)
.x(function(d) return x(d.date); )
.y(function(d) return y(d.lines); );
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")");
g.append("g")
.attr("class", "axis axis--y");
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
).sort((a, b) => a.type - b.type)
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
console.log("Nested: ", nestData)
var lineData = nestData.map(function(d)
return date: d.key, E: d.values[0].value, U: d.values[1].value;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
lineData.sort((a, b) => a.date - b.date)
console.log("Mapped: ", lineData)
parsed(lineData);
function parsed(dataTest)
var keys = ["E","U"]
var newData = keys.map(function(id)
return
id: id,
values: dataTest.map(function(d)
return date: d.date, lines: d[id];
)
;
);
console.log("Mapped w/key: ", newData)
z.domain(newData.map(function(c) return c.id; ));
var max = d3.max(dataTest, d => d3.max([d.E, d.U]));
y.domain([0, max]).nice();
x.domain(d3.extent(dataTest, d => d.date));
g.selectAll(".axis.axis--y").transition()
.duration(durations)
.call(yAxis);
g.selectAll(".axis.axis--x").transition()
.duration(durations)
.call(xAxis);
var lineValues = g.selectAll(".lineValues")
.data(newData);
lineValues = lineValues
.enter()
.append("path")
.attr("class", "line lineValues")
.style("stroke", function(d) return z(d.id); )
.merge(lineValues);
lineValues.transition()
.duration(durations)
.attr("d", function(d) return line(d.values) )
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.line
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
</style>
</head>
<body>
<div id="chart"></div>
<script>
</script>
</body>
</html>
javascript d3.js
asked Feb 7 at 15:28
Robert Andersson
1667
1667
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
First of all: drop the row function, which is the anonymous function as the second argument of csvParse
...
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
)
... because you are not changing anything!
So, it can be just:
var data = d3.csvParse(csvData);
Back to your question:
Indeed, you don't need to reference the array by the indices, which forces you to sort the data array and then to sort the resulting array... that's not only confusing and error-prone, but also very computer-intensive for the browser: sorting big arrays of objects can take quite some time. It's a good idea avoiding sorting, specially because, as we'll see, you don't need it.
There is a way to omit that step, making it automatic. Better than that, you can make the whole thing automatic!
In my proposed solution, you don't even need to set the keys, as you do right now...
var keys = ["E","U"];
You can easily get all the unique type
values:
var keys = [...new Set(data.map(function(d)
return d.type
))];
And then, creating your lineData
:
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
The above code will work for any number of different types you have, and since you already have the dates in the chronological order, you don't need any sort
.
This, in short, is what the function does:
For each
map
interaction we create a new object:var obj = ;
We set the key/value pair for the dates, since there is always a date:
obj.date = d.key;
Then, for each value in the
keys
array, we find the respective value in thevalues
array:keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);Finally, we return the object:
return obj;
Here is a demo, using only the relevant parts in your code:
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Now, using this code, you can automatically create the adequate lineData
array regardless the number and the order of the type
properties in your data array.
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
First of all: drop the row function, which is the anonymous function as the second argument of csvParse
...
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
)
... because you are not changing anything!
So, it can be just:
var data = d3.csvParse(csvData);
Back to your question:
Indeed, you don't need to reference the array by the indices, which forces you to sort the data array and then to sort the resulting array... that's not only confusing and error-prone, but also very computer-intensive for the browser: sorting big arrays of objects can take quite some time. It's a good idea avoiding sorting, specially because, as we'll see, you don't need it.
There is a way to omit that step, making it automatic. Better than that, you can make the whole thing automatic!
In my proposed solution, you don't even need to set the keys, as you do right now...
var keys = ["E","U"];
You can easily get all the unique type
values:
var keys = [...new Set(data.map(function(d)
return d.type
))];
And then, creating your lineData
:
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
The above code will work for any number of different types you have, and since you already have the dates in the chronological order, you don't need any sort
.
This, in short, is what the function does:
For each
map
interaction we create a new object:var obj = ;
We set the key/value pair for the dates, since there is always a date:
obj.date = d.key;
Then, for each value in the
keys
array, we find the respective value in thevalues
array:keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);Finally, we return the object:
return obj;
Here is a demo, using only the relevant parts in your code:
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Now, using this code, you can automatically create the adequate lineData
array regardless the number and the order of the type
properties in your data array.
add a comment |Â
up vote
1
down vote
accepted
First of all: drop the row function, which is the anonymous function as the second argument of csvParse
...
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
)
... because you are not changing anything!
So, it can be just:
var data = d3.csvParse(csvData);
Back to your question:
Indeed, you don't need to reference the array by the indices, which forces you to sort the data array and then to sort the resulting array... that's not only confusing and error-prone, but also very computer-intensive for the browser: sorting big arrays of objects can take quite some time. It's a good idea avoiding sorting, specially because, as we'll see, you don't need it.
There is a way to omit that step, making it automatic. Better than that, you can make the whole thing automatic!
In my proposed solution, you don't even need to set the keys, as you do right now...
var keys = ["E","U"];
You can easily get all the unique type
values:
var keys = [...new Set(data.map(function(d)
return d.type
))];
And then, creating your lineData
:
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
The above code will work for any number of different types you have, and since you already have the dates in the chronological order, you don't need any sort
.
This, in short, is what the function does:
For each
map
interaction we create a new object:var obj = ;
We set the key/value pair for the dates, since there is always a date:
obj.date = d.key;
Then, for each value in the
keys
array, we find the respective value in thevalues
array:keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);Finally, we return the object:
return obj;
Here is a demo, using only the relevant parts in your code:
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Now, using this code, you can automatically create the adequate lineData
array regardless the number and the order of the type
properties in your data array.
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
First of all: drop the row function, which is the anonymous function as the second argument of csvParse
...
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
)
... because you are not changing anything!
So, it can be just:
var data = d3.csvParse(csvData);
Back to your question:
Indeed, you don't need to reference the array by the indices, which forces you to sort the data array and then to sort the resulting array... that's not only confusing and error-prone, but also very computer-intensive for the browser: sorting big arrays of objects can take quite some time. It's a good idea avoiding sorting, specially because, as we'll see, you don't need it.
There is a way to omit that step, making it automatic. Better than that, you can make the whole thing automatic!
In my proposed solution, you don't even need to set the keys, as you do right now...
var keys = ["E","U"];
You can easily get all the unique type
values:
var keys = [...new Set(data.map(function(d)
return d.type
))];
And then, creating your lineData
:
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
The above code will work for any number of different types you have, and since you already have the dates in the chronological order, you don't need any sort
.
This, in short, is what the function does:
For each
map
interaction we create a new object:var obj = ;
We set the key/value pair for the dates, since there is always a date:
obj.date = d.key;
Then, for each value in the
keys
array, we find the respective value in thevalues
array:keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);Finally, we return the object:
return obj;
Here is a demo, using only the relevant parts in your code:
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Now, using this code, you can automatically create the adequate lineData
array regardless the number and the order of the type
properties in your data array.
First of all: drop the row function, which is the anonymous function as the second argument of csvParse
...
var data = d3.csvParse(csvData, function(d)
d.date = d.date;
d.type = d.type
return d;
)
... because you are not changing anything!
So, it can be just:
var data = d3.csvParse(csvData);
Back to your question:
Indeed, you don't need to reference the array by the indices, which forces you to sort the data array and then to sort the resulting array... that's not only confusing and error-prone, but also very computer-intensive for the browser: sorting big arrays of objects can take quite some time. It's a good idea avoiding sorting, specially because, as we'll see, you don't need it.
There is a way to omit that step, making it automatic. Better than that, you can make the whole thing automatic!
In my proposed solution, you don't even need to set the keys, as you do right now...
var keys = ["E","U"];
You can easily get all the unique type
values:
var keys = [...new Set(data.map(function(d)
return d.type
))];
And then, creating your lineData
:
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
The above code will work for any number of different types you have, and since you already have the dates in the chronological order, you don't need any sort
.
This, in short, is what the function does:
For each
map
interaction we create a new object:var obj = ;
We set the key/value pair for the dates, since there is always a date:
obj.date = d.key;
Then, for each value in the
keys
array, we find the respective value in thevalues
array:keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);Finally, we return the object:
return obj;
Here is a demo, using only the relevant parts in your code:
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Now, using this code, you can automatically create the adequate lineData
array regardless the number and the order of the type
properties in your data array.
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;
var parseTime = d3.timeParse("%Y-%m");
var data = d3.csvParse(csvData);
var keys = [...new Set(data.map(function(d)
return d.type
))];
var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);
var lineData = nestData.map(function(d)
var obj = ;
obj.date = d.key;
keys.forEach(function(e)
obj[e] = d.values.find(function(f)
return f.key === e
).value
);
return obj;
);
lineData.forEach(function(d)
d.date = parseTime(d.date);
)
console.log("Nested: ", nestData)
console.log("Mapped: ", lineData)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
edited Feb 8 at 15:42
answered Feb 8 at 1:58
Gerardo Furtado
1,1442420
1,1442420
add a comment |Â
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%2f187018%2frestructuring-a-csv-file-with-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