i have data for the first and following attempt of seeking asylum in germany for refugees and therefore two graphs which are looking like this
Transition from one to another shoulnd't be a problem i suppose but what I want is so show both of them in one graph too. So a combination of both datasets for each country. But is it possible to distinguish from one another if I combine countries and the first and following ("erst/folge")? Each country should have on layer divided by two, one is the first attempt the other is the second attempt of this country. One idea to differ those sub-layers is maybe custom coloscale which I try right now. How can I show both data in one graph? Is it even possible to join both datasets and still see the difference?
Here is my html:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.chart {
background: #fff;
}
p {
font: 12px helvetica;
}
.axis path, .axis line {
fill: none;
stroke: #000;
stroke-width: 2px;
shape-rendering: crispEdges;
}
button {
position: absolute;
right: 50px;
top: 10px;
}
</style>
<body>
<script src="http://d3js.org/d3.v2.js"></script>
<div id="option">
<input name="updateButton"
type="button"
value="Show Data for second Attemp"
onclick="updateSecond('folgeantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div id="option">
<input name="updateButton"
type="button"
value="Show Data for first Attemp"
onclick="updateFirst('erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div id="option">
<input name="updateButton"
type="button"
value="Show both"
onclick="updateBoth('erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv', 'folgeantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div class="chart">
</div>
<script>
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var dateParser = d3.time.format("%Y-%m-%d").parse;
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var z = d3.scale.category20()
chart("erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv");
var datearray = [];
var colorrange = [];
function chart(csvpath) {
// var dateParser = d3.time.format("%Y-%m-%d").parse;
// var margin = {top: 20, right: 40, bottom: 30, left: 30};
// var width = document.body.clientWidth - margin.left - margin.right;
// var height = 400 - margin.top - margin.bottom;
// var x = d3.time.scale()
// .range([0, width]);
//
// var y = d3.scale.linear()
// .range([height-10, 0]);
// var z = d3.scale.category20()
//var color = d3.scale.category10()
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.months);
var yAxis = d3.svg.axis()
.scale(y);
var yAxisr = d3.svg.axis()
.scale(y);
// var stack = d3.layout.stack()
// .offset("zero")
// .values(function(d) { return d.values; })
// .x(function(d) { return d.date; })
// .y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.Land});
// var nestFiltered = nest.filter(function(d){
// return d.Land != 'Total';
// })
// var area = d3.svg.area()
// .interpolate("cardinal")
// .x(function(d) { return x(d.date); })
// .y0(function(d) { return y(d.y0); })
// .y1(function(d) { return y(d.y0 + d.y); });
var svg = 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 + ")");
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.ErstanträgeZahl;
});
//onsole.log(data);
var layers = stack(nest.entries(data));
console.log(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return z(i); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis.orient("left"));
});
}
function updateSecond(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.Summe;
console.log(d.date);
console.log(d.value);
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
d3.selectAll("path")
.data(layers)
.transition()
.duration(750)
.style("fill", function(d, i) { return z(i); })
.attr("d", function(d) { return area(d.values); });
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
function updateFirst(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.ErstanträgeZahl;
console.log(d.date);
console.log(d.value);
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
d3.selectAll("path")
.data(layers)
.transition()
.duration(750)
.style("fill", function(d, i) { return z(i); })
.attr("d", function(d) { return area(d.values); });
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
function updateBoth(csvpathFirst, csvpathSecond){
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpathFirst, function(data1) {
d3.csv(csvpathSecond, function(data2) {
});
});
}
</script>
And my data is here at my repo
EDIT1: For example csv1 contains
Datum,Land,Summe,Position,Antragsart,EntscheidungenInsgesamt,Asylberechtigt,Flüchtling,GewährungVonSubsidiäremSchutz,Abschiebungsverbot,UnbegrenzteAblehnungen,Ablehnung,sonstigeVerfahrenserledigungen
2015-01-01,Afghanistan,1129,5,Erst,418,0,105,4,58,66,6,179
2015-02-01,Afghanistan,969,5,Erst,849,9,186,16,100,131,10,397
2015-03-01,Afghanistan,885,5,Erst,1376,17,309,58,158,201,11,622
2015-04-01,Afghanistan,1119,6,Erst,1838,21,384,75,202,261,15,880
2015-05-01,Afghanistan,1151,6,Erst,2272,21,499,91,249,303,16,1093
2015-06-01,Afghanistan,2051,6,Erst,2911,23,683,132,313,377,19,1364
2015-07-01,Afghanistan,2104,6,Erst,3340,27,767,160,366,431,21,1568
2015-08-01,Afghanistan,2270,5,Erst,3660,28,922,172,409,453,23,1653
2015-09-01,Afghanistan,2724,4,Erst,4057,36,1049,201,455,475,26,1815
2015-10-01,Afghanistan,3770,4,Erst,4540,37,1188,234,516,538,29,1998
2015-11-01,Afghanistan,4929,0,Erst,5026,46,1340,253,620,623,49,2095
And csv2 contains
Datum,Antragsart,Land,Summe,Position,Datum2,Position,Herkunft,Entscheidungeninsgesamt,Asylberechtigt,Prozent,Flüchtling,Pronzent,GewährungvonsubisdiäremSchutz,Prozent,Abschiebungsverbot,Prozent,UnbegrenzteAblehnungen,Prozent,Ablehnung,Prozent,keinweiteresverfahren,Prozent,sonstigeVerfahrenserledigungen,Prozent
2015-01-01,Folge,Afghanistan,33,10,2015-01-01,10,Afghanistan,29,0,0,5,17.2,2,6.9,8,27.6,0,0,0,0,1,3.4,13,44.8
2015-02-01,Folge,Afghanistan,29,10,2015-02-01,10,Afghanistan,81,0,0,13,16,4,4.9,22,27.2,0,0,0,0,10,12.3,32,39.5
2015-03-01,Folge,Afghanistan,41,9,2015-03-01,9,Afghanistan,135,0,0,21,15.6,10,7.4,37,27.4,1,0.7,0,0,23,17,43,31.9
2015-04-01,Folge,Afghanistan,25,10,2015-04-01,10,Afghanistan,165,0,0,34,20.6,12,7.3,41,24.8,4,2.4,0,0,30,18.2,44,26.7
2015-05-01,Folge,Afghanistan,37,9,2015-05-01,9,Afghanistan,212,0,0,54,25.5,12,5.7,50,23.6,4,1.9,0,0,32,15.1,60,28.3
2015-06-01,Folge,Afghanistan,35,9,2015-06-01,9,Afghanistan,261,0,0,72,27.6,17,6.5,59,22.6,6,2.3,0,0,35,13.4,72,27.6
2015-07-01,Folge,Afghanistan,35,9,2015-07-01,9,Afghanistan,288,0,0,82,28.5,17,5.9,64,22.2,6,2.1,0,0,42,14.6,77,26.7
2015-08-01,Folge,Afghanistan,34,9,2015-08-01,9,Afghanistan,321,0,0,100,31.2,20,6.2,66,20.6,6,1.9,0,0,52,16.2,77,24
2015-09-01,Folge,Afghanistan,27,4,2015-09-01,9,Afghanistan,354,0,0,120,33.9,20,5.6,72,20.3,7,2,0,0,54,15.3,81,22.9
2015-10-01,Folge,Afghanistan,24,9,2015-10-01,9,Afghanistan,389,0,0,136,35,20,5.1,83,21.3,7,1.8,0,0,54,13.9,89,22.9
2015-11-01,Folge,Afghanistan,47,,,,,431,1,0.2,148,34.3,23,5.3,97,22.5,8,1.9,0,0,58,13.5,96,22.3
The values ("Summe") should sum up the values per month of each country (Afghanistan) but also should reflect the values for their stacks on their own (Right now I'm trying to figur out how to use texture.js and custom scales to use textures to distinguish the colors from another because every country should have it's own color in this graph but as I already mentioned they should be different in their sublayers When I try to put both csv fiels in one file I get not exactly but something similar to this Can you give me some tips how to archive sub-layers (data structure/algorithm or what i takes to achieve this) so I can proceed and try to implement textures?
Thanks in advance
Final EDIT as answer to Cyrils :
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var dateParser = d3.time.format("%Y-%m-%d").parse;
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.graphDate; })
.y(function(d) { return d.value; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.graphDate); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var z = d3.scale.category20()
doInit();
updateFirst('data/all.csv');
function doInit(){
//make the svg and axis
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.months);
yAxis = d3.svg.axis()
.scale(y);
yAxisr = d3.svg.axis()
.scale(y);
//make svg
var graph = 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 + ")");
graph.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
graph.append("g")
.attr("class", "y axis yright")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
graph.append("g")
.attr("class", "y axis yleft")
.call(yAxis.orient("left"));
}
function updateFirst(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land+ "-" + d.Antragsart});
//console.log(nest);
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
//console.log(data);
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.type= d.Antragsart;
});
var layers = stack(nest.entries(data)).sort(function(a,b){return d3.ascending(a.key, b.key)});
console.log(layers);
x.domain(d3.extent(data, function(d) { return d.graphDate; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
var k = d3.select("g .x")
.call(xAxis);
d3.select("g .yright")
.call(yAxis);
d3.select("g .yleft")
.call(yAxis);
d3.selectAll("defs").remove();
d3.select(".chart svg g").selectAll("path").remove();
d3.select(".chart svg g").selectAll("path")
.data(layers).enter().append("path")
//.style("fill", function(d, i) { console.log(d.key);return z(d.key); })
.attr("class", function(d){
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
return src;
})
.style("fill", function(d){
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
if (src === "Folge"){
var t = textures.lines().thicker(2).stroke(z(country));
d3.select(".chart").select("svg").call(t);
return t.url();
} else {
return z(country);
}
})
.attr("d", function(d) { return area(d.values); });
});
}
For merging the records I am making use of d3 queue..Read here
The purpose of this is to load 2 CSV via ajax and when both loaded calls the callback.
queue()
.defer(d3.csv, csvpathFirst) //using queue so that callback is called after loading both CSVs
.defer(d3.csv, csvpathSecond)
.await(makeMyChart);
function makeMyChart(error, first, second) {
var data = [];
Make the nested function based on country and csv
var nest = d3.nest() .key(function(d) { return d.Land + "-" + d.src; //d.src is first if first csv second if vice versa });
Next I am merging the records like this:
//iterate first
first.forEach(function(d) {
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.src = "first"
data.push(d)
});
//iterate second
second.forEach(function(d) {
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.src = "second"
data.push(d)
});
//sort layers on basis of country
var layers = stack(nest.entries(data)).sort(function(a, b) {
return d3.ascending(a.key, b.key)
});
Regenerate the axis like this:
//regenerate the axis with new domains
var k = d3.select("g .x")
.call(xAxis);
d3.select("g .yright")
.call(yAxis);
d3.select("g .yleft")
.call(yAxis);
Remove all old paths and defs
DOM like this:
d3.selectAll("defs").remove();
d3.select(".chart svg g").selectAll("path").remove();
Next based on country and first csv and second csv add style fill.
.style("fill", function(d) {
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
if (src === "first") {
//use texture.js for pattern
var t = textures.lines().thicker().stroke(z(country));
d3.select(".chart").select("svg").call(t);
return t.url();
} else {
return z(country);
}
})
Working code here
Hope this helps!