2

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

First one First attempt/arrivals

Second one enter image description here

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 Scribble When I try to put both csv fiels in one file I get not exactly but something similar to this Fail1enter image description here 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); });
  });
}
basedian
  • 307
  • 1
  • 5
  • 18
  • 1
    Check out this Jason Davies [article](https://www.jasondavies.com/american-forces-in-afghanistan-and-iraq/). It seems similar to what you want, he's using bars though, not area graphs. – Mark Dec 31 '15 at 16:10
  • i'll take a look at this. thanks – basedian Jan 02 '16 at 14:36
  • I have problems to apply the general idea of the example to my version. Even though they have similarities I get stuck. Can you give me more tips/information? For example I don't know what to do with the area variable in the streamgraph and how I handle the genral variable conversion – basedian Jan 04 '16 at 16:16

1 Answers1

1

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!

Cyril Cherian
  • 32,177
  • 7
  • 46
  • 55
  • Big huge thanks to your efforts. I get the idea of your code. One little thing I'm trying to work around ist that the data of first and second really stack up based on their color and then texture but I think it is impossible based on the nature of a streamgraph that I just can't layer up all countries (color then texture, next country then texture etc.) – basedian Jan 05 '16 at 21:52
  • Yes, you are correct its not possible to have alternate countries ..it depends on the dataset. – Cyril Cherian Jan 06 '16 at 00:39
  • So when I merge the datesat I could maybe have alternative datasets? I have a entry which says if it is first or second. – basedian Jan 06 '16 at 08:33
  • Yea correct if i parse the first data set i store `d.src = "first"` (Line No: 189) If I parse the second i store `d.src = "second"` (Line No: 196) this is used later to decide the key name in the nested block check (line no 174-177) – Cyril Cherian Jan 06 '16 at 08:49
  • Ok I added a all.csv to my [repo](https://github.com/RitterLean/Streamgraph-multipledata). Is it then possible to stack something like this `(Afgh-first, Afgh-second, Albania-first, Albania-second)`? Do I then just need `d.Antragsart/source` to distinguish? because right now when I parse all.csv I get of course an error `Cannot read property '1' of undefined` – basedian Jan 06 '16 at 09:54
  • Read my comment about about reading multiple csv's i am reading multiple csv _line No 178 -181_ now if you have made a single csv by merging 2 csv manually then you will have to change my code accordingly, well that's the reason why you get error. – Cyril Cherian Jan 06 '16 at 10:05
  • I was successful. The error appeared because for Syria the names did of first.csv and second.csv where not equal because of one comma. So the strings where not equal. The main idea remains and I will post my code too. – basedian Jan 06 '16 at 12:35