D3.js streamgraph example - generating correct area function values

坚强是说给别人听的谎言 提交于 2019-12-01 08:49:18

问题


I'm new to d3js and trying to adapt the streamgraph example from here http://bl.ocks.org/mbostock/4060954:

...to work with my own data that tracks visitors to an art exhibition from different places (online, guestbook, museum). I've made some progress and I think my data's in the right format but I'm getting some really wonky final y values and my example isn't showing anything.

My data starts as csv:

index,date,venue,num_visitors
0,4/6/2013,online,3844
0,4/6/2013,museum,789
0,4/6/2013,guestbook,20
1,4/7/2013,online,217
1,4/7/2013,museum,718
1,4/7/2013,guestbook,20

And then I nest it to organize into 3 layers/streams by venue (online, museum, guestbook):

layer0 = [
  {
    "key": "online",
    "values": [
      { "x": 0, "y":  3844},
      { "x": 1, "y": 217}
      etc

    ]
  },
  {  
    "key": "museum",
    "values": [
      { "x": 0, "y":  789},
      { "x": 1, "y": 718}
      etc
    ]
  }
];

When the page is generated the y values are always 800 and the svg path objects measure 1400px width and 0 height. I'm not sure if this is a problem with how I'm scaling the input domain to the output range or if it's a problem with how the area function is generating the y values. Here's a sample of what the point values show as for one of the generated paths:

d="M0,800L17.72151898734177,800L35.44303797468354,800L53.164556962025316,800L70.88607594936708, etc"

Here's my full page - would REALLY appreciate some guidance as I feel like I'm missing something simple here.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Streamgraph</title>
<style>

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: 0;
  position: relative;
  width: 1400px;
}

button {
  position: absolute;
  right: 10px;
  top: 10px;
}

</style>
<button onclick="transition()">Update</button>
<script src="d3.js"></script>
<script>

var format = d3.time.format("%m/%d/%Y");

d3.csv("streamdata.csv", function(error, data) {
        data.forEach(function(d) {
            d.date = format.parse(d.date);
            d.y = d.num_visitors;
            d.x = d.index;

        });
        window.data = data;

        drawVisitorStats();
});

function drawVisitorStats(){
    var nest = d3.nest()
           .key(function(d){ return d.venue});
    var n = window.data.length, // number of layers, online, guestbook & museum

        stack = d3.layout.stack().offset("wiggle").offset("zero")
          .values(function(d) { return d.values; }),

        //group data by venue
        layers0 = stack(nest.entries(data)),
        layers1 = stack(nest.entries(data));

    var m = layers0[0].values.length; // number of samples per layer

    var yDomain = d3.max(layers0.concat(layers1), function(layer) { 
        return d3.max(layer, 
            function(d) { 
              return d.y0 + d.y; 
            }); 
    });

    var width = 1400,
        height = 800;

    var x = d3.scale.linear()
    .domain([0, m - 1])
    .range([0, width]);

    var y = d3.scale.linear()
    .domain([0, yDomain])
    .range([height, 0]);

    var color = d3.scale.linear()
        .range(["#ff0c00", "#ffc000"]);

    var area = d3.svg.area()
      .x(
        function(d) { 
          return x(d.x); 
        })
        .y0(function(d) { 
          return y(d.y0); 
        })
        .y1(function(d) { 
          return y(d.y0 + d.y); 
        }); 

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);

    svg.selectAll("path")
        .data(layers0)
      .enter().append("path")
        .attr("d", function(d) { return area(d.values); })
        .style("fill", function() { return color(Math.random()); });
}
function transition() {
  d3.selectAll("path")
      .data(function() {
        var d = layers1;
        layers1 = layers0;
        return layers0 = d;
      })
    .transition()
      .duration(2500)
      .attr("d", area);
}



</script>

And here is the data csv file

index,date,venue,num_visitors
0,4/6/2013,online,3844
0,4/6/2013,museum,789
0,4/6/2013,guestbook,20
1,4/7/2013,online,217
1,4/7/2013,museum,718
1,4/7/2013,guestbook,20
2,4/8/2013,online,203
2,4/8/2013,museum,741
2,4/8/2013,guestbook,6
3,4/9/2013,online,1445
3,4/9/2013,museum,874
3,4/9/2013,guestbook,7
4,4/10/2013,online,3098
4,4/10/2013,museum,755
4,4/10/2013,guestbook,3
5,4/11/2013,online,744
5,4/11/2013,museum,368
5,4/11/2013,guestbook,6
6,4/12/2013,online,1342
6,4/12/2013,museum,826
6,4/12/2013,guestbook,17
7,4/13/2013,online,694
7,4/13/2013,museum,826
7,4/13/2013,guestbook,17
8,4/14/2013,online,213
8,4/14/2013,museum,261
8,4/14/2013,guestbook,7
9,4/15/2013,online,3215
9,4/15/2013,museum,776
9,4/15/2013,guestbook,14
10,4/16/2013,online,2663
10,4/16/2013,museum,331
10,4/16/2013,guestbook,12
11,4/17/2013,online,172
11,4/17/2013,museum,633
11,4/17/2013,guestbook,10
12,4/18/2013,online,4516
12,4/18/2013,museum,543
12,4/18/2013,guestbook,5
13,4/19/2013,online,988
13,4/19/2013,museum,792
13,4/19/2013,guestbook,19
14,4/20/2013,online,2556
14,4/20/2013,museum,663
14,4/20/2013,guestbook,0
15,4/21/2013,online,2814
15,4/21/2013,museum,449
15,4/21/2013,guestbook,18
16,4/22/2013,online,596
16,4/22/2013,museum,445
16,4/22/2013,guestbook,15
17,4/23/2013,online,4790
17,4/23/2013,museum,217
17,4/23/2013,guestbook,5
18,4/24/2013,online,733
18,4/24/2013,museum,655
18,4/24/2013,guestbook,12
19,4/25/2013,online,362
19,4/25/2013,museum,321
19,4/25/2013,guestbook,20
20,4/26/2013,online,637
20,4/26/2013,museum,420
20,4/26/2013,guestbook,3
21,4/27/2013,online,2916
21,4/27/2013,museum,910
21,4/27/2013,guestbook,6
22,4/28/2013,online,1097
22,4/28/2013,museum,468
22,4/28/2013,guestbook,0
23,4/29/2013,online,796
23,4/29/2013,museum,687
23,4/29/2013,guestbook,9
24,4/30/2013,online,821
24,4/30/2013,museum,951
24,4/30/2013,guestbook,12
25,5/1/2013,online,2466
25,5/1/2013,museum,810
25,5/1/2013,guestbook,6
26,5/2/2013,online,1005
26,5/2/2013,museum,291
26,5/2/2013,guestbook,19
27,5/3/2013,online,1243
27,5/3/2013,museum,446
27,5/3/2013,guestbook,5
28,5/4/2013,online,4623
28,5/4/2013,museum,538
28,5/4/2013,guestbook,0
29,5/5/2013,online,547
29,5/5/2013,museum,457
29,5/5/2013,guestbook,11
30,5/6/2013,online,4132
30,5/6/2013,museum,407
30,5/6/2013,guestbook,8
31,5/7/2013,online,3083
31,5/7/2013,museum,741
31,5/7/2013,guestbook,9
32,5/8/2013,online,2854
32,5/8/2013,museum,516
32,5/8/2013,guestbook,1
33,5/9/2013,online,2122
33,5/9/2013,museum,932
33,5/9/2013,guestbook,14
34,5/10/2013,online,587
34,5/10/2013,museum,701
34,5/10/2013,guestbook,0
35,5/11/2013,online,698
35,5/11/2013,museum,887
35,5/11/2013,guestbook,18
36,5/12/2013,online,3538
36,5/12/2013,museum,223
36,5/12/2013,guestbook,4
37,5/13/2013,online,2413
37,5/13/2013,museum,799
37,5/13/2013,guestbook,13
38,5/14/2013,online,3581
38,5/14/2013,museum,744
38,5/14/2013,guestbook,7
39,5/15/2013,online,1750
39,5/15/2013,museum,845
39,5/15/2013,guestbook,17
40,5/16/2013,online,3025
40,5/16/2013,museum,630
40,5/16/2013,guestbook,10
41,5/17/2013,online,2038
41,5/17/2013,museum,342
41,5/17/2013,guestbook,7
42,5/18/2013,online,148
42,5/18/2013,museum,447
42,5/18/2013,guestbook,20
43,5/19/2013,online,886
43,5/19/2013,museum,755
43,5/19/2013,guestbook,20
44,5/20/2013,online,1168
44,5/20/2013,museum,305
44,5/20/2013,guestbook,10
45,5/21/2013,online,190
45,5/21/2013,museum,378
45,5/21/2013,guestbook,11
46,5/22/2013,online,1416
46,5/22/2013,museum,276
46,5/22/2013,guestbook,13
47,5/23/2013,online,1753
47,5/23/2013,museum,380
47,5/23/2013,guestbook,7
48,5/24/2013,online,2573
48,5/24/2013,museum,221
48,5/24/2013,guestbook,17
49,5/25/2013,online,2425
49,5/25/2013,museum,610
49,5/25/2013,guestbook,11
50,5/26/2013,online,3359
50,5/26/2013,museum,492
50,5/26/2013,guestbook,1
51,5/27/2013,online,1853
51,5/27/2013,museum,873
51,5/27/2013,guestbook,4
52,5/28/2013,online,4106
52,5/28/2013,museum,543
52,5/28/2013,guestbook,7
53,5/29/2013,online,591
53,5/29/2013,museum,894
53,5/29/2013,guestbook,11
54,5/30/2013,online,2938
54,5/30/2013,museum,565
54,5/30/2013,guestbook,4
55,5/31/2013,online,2237
55,5/31/2013,museum,313
55,5/31/2013,guestbook,4
56,6/1/2013,online,3754
56,6/1/2013,museum,622
56,6/1/2013,guestbook,10
57,6/2/2013,online,1529
57,6/2/2013,museum,309
57,6/2/2013,guestbook,2
58,6/3/2013,online,1482
58,6/3/2013,museum,636
58,6/3/2013,guestbook,8
59,6/4/2013,online,1607
59,6/4/2013,museum,655
59,6/4/2013,guestbook,8
60,6/5/2013,online,364
60,6/5/2013,museum,485
60,6/5/2013,guestbook,0
61,6/6/2013,online,555
61,6/6/2013,museum,219
61,6/6/2013,guestbook,3
62,6/7/2013,online,4209
62,6/7/2013,museum,674
62,6/7/2013,guestbook,18
63,6/8/2013,online,4767
63,6/8/2013,museum,824
63,6/8/2013,guestbook,11
64,6/9/2013,online,4788
64,6/9/2013,museum,877
64,6/9/2013,guestbook,2
65,6/10/2013,online,295
65,6/10/2013,museum,873
65,6/10/2013,guestbook,14
66,6/11/2013,online,2057
66,6/11/2013,museum,559
66,6/11/2013,guestbook,13
67,6/12/2013,online,3199
67,6/12/2013,museum,592
67,6/12/2013,guestbook,15
68,6/13/2013,online,2453
68,6/13/2013,museum,907
68,6/13/2013,guestbook,12
69,6/14/2013,online,3688
69,6/14/2013,museum,267
69,6/14/2013,guestbook,12
70,6/15/2013,online,352
70,6/15/2013,museum,389
70,6/15/2013,guestbook,15
71,6/16/2013,online,1583
71,6/16/2013,museum,304
71,6/16/2013,guestbook,7
72,6/17/2013,online,4202
72,6/17/2013,museum,438
72,6/17/2013,guestbook,3
73,6/18/2013,online,2652
73,6/18/2013,museum,392
73,6/18/2013,guestbook,1
74,6/19/2013,online,3988
74,6/19/2013,museum,764
74,6/19/2013,guestbook,17
75,6/20/2013,online,3025
75,6/20/2013,museum,663
75,6/20/2013,guestbook,18
76,6/21/2013,online,4057
76,6/21/2013,museum,266
76,6/21/2013,guestbook,9
77,6/22/2013,online,4853
77,6/22/2013,museum,614
77,6/22/2013,guestbook,15
78,6/23/2013,online,1334
78,6/23/2013,museum,745
78,6/23/2013,guestbook,6
79,6/24/2013,online,4729
79,6/24/2013,museum,506
79,6/24/2013,guestbook,8

Thanks!


回答1:


In your yDomain definition, you need to return the max of each layer's values, since each layer is a map - it has both a key and an array of values, rather than just a flat array of numbers.

var yDomain = d3.max(layers0.concat(layers1), function(layer) { 
    return d3.max(layer.values, //Used to be layer
        function(d) { 
          return d.y0 + d.y; 
        }); 
});

Also, for your stack definition, you need to remove the second offset call.. it negates the "wiggle" one, so you will get a normal stacked graph rather than a streamgraph.

stack = d3.layout.stack().offset("wiggle")  // Used to have .offset("zero") here
      .values(function(d) { return d.values; })

Here's an example with both of those changed : http://jsfiddle.net/G6dTy/3/ . The numbers for the guestbook are small, and are dwarfed by the other two values.

It might be informative to take a look at the Stacked area chart example




回答2:


Thanks minikomi! That was super helpful. The other thing I realized was off was that I wasn't parsing the x & y values into numbers and it was reading them as strings and making the points computation go crazy. So when it's iterating through the rows of the CSV file it needs to use parseInt:

data.forEach(function(d) {
        d.date = format.parse(d.date);
        d.y = parseInt(d.num_visitors);
        d.x = parseInt(d.index);

    });

Here are my updated files in case anyone wants to use this as an example in the future.

HTML

<!DOCTYPE html>
<meta charset="utf-8">
<title>Streamgraph</title>
<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<style>

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: 0;
  position: relative;
  width: 1400px;
  background-color: #053749;
}

button {
  position: absolute;
  right: 10px;
  top: 10px;
}
svg{
  margin-top: 450px;
}

</style>
<script src="d3.js"></script>
<body>
  <div id="layerTitle"></div>
</body>
<script>


var format = d3.time.format("%m/%d/%Y");

d3.csv("streamdata.csv", function(error, data) {
        data.forEach(function(d) {
            d.date = format.parse(d.date);
            d.y = parseInt(d.num_visitors) + 1;
            d.x = parseInt(d.index);

        });
        window.data = data;

        drawVisitorStats();
        //$('path').tooltip('{container:layerTitle}');
        $("path").tooltip({
            'container': 'body',
            'placement': 'bottom'
        });


});

function drawVisitorStats(){
    var nest = d3.nest()
           .key(function(d){ return d.venue});
    var n = window.data.length, // number of layers, online, guestbook & museum

    stack = d3.layout.stack().offset("wiggle")
          .values(function(d) { return d.values; });

    //group data by venue
    layers0 = stack(nest.entries(data));

    var m = layers0[0].values.length; // number of samples per layer

    var allValues = layers0[0].values.concat(layers0[1].values).concat(layers0[2].values);

    var yDomain = d3.max(allValues, function(d) { 
      return d.y0 + d.y; 
    });

    var width = 1400,
        height = 200;

    var x = d3.scale.linear()
      .domain([0, m - 1])
      .range([0, width]);

    var y = d3.scale.linear()
    .domain([1, yDomain])
    .range([height, 0]);

    var color = d3.scale.linear()
        .range(["#053749", "#6bb9d6"]);

    var area = d3.svg.area()
      .x(
        function(d) { 
          return x(d.x); 
        })
        .y0(function(d) {          
          return y(d.y0); 
        })
        .y1(function(d) { 
          return y(d.y0 + d.y); 
        })
        .interpolate("cardinal")
        .tension(0.6); 

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);

    svg.selectAll("path")
        .data(layers0)
      .enter().append("path")
        .attr("d", function(d) { return area(d.values); })
        .attr("id", function(d) { 
          return d.key;
        })
        .attr("title", function(d) { 
          return "visitors from " + d.key;
        })
        .style("fill", function() { return color(Math.random()); });
}

</script>
</html>

DATA FILE

index,date,venue,num_visitors
0,4/8/2013,online,1721
0,4/8/2013,museum,826
0,4/8/2013,guestbook,333
1,4/9/2013,online,1377
1,4/9/2013,museum,840
1,4/9/2013,guestbook,61
2,4/10/2013,online,1849
2,4/10/2013,museum,539
2,4/10/2013,guestbook,191
3,4/11/2013,online,1205
3,4/11/2013,museum,810
3,4/11/2013,guestbook,65
4,4/12/2013,online,1960
4,4/12/2013,museum,957
4,4/12/2013,guestbook,221
5,4/13/2013,online,1215
5,4/13/2013,museum,658
5,4/13/2013,guestbook,384
6,4/14/2013,online,1565
6,4/14/2013,museum,621
6,4/14/2013,guestbook,94
7,4/15/2013,online,1678
7,4/15/2013,museum,710
7,4/15/2013,guestbook,35
8,4/16/2013,online,1267
8,4/16/2013,museum,964
8,4/16/2013,guestbook,8
9,4/17/2013,online,1781
9,4/17/2013,museum,896
9,4/17/2013,guestbook,238
10,4/18/2013,online,1185
10,4/18/2013,museum,712
10,4/18/2013,guestbook,318
11,4/19/2013,online,1097
11,4/19/2013,museum,753
11,4/19/2013,guestbook,132
12,4/20/2013,online,1053
12,4/20/2013,museum,927
12,4/20/2013,guestbook,399
13,4/21/2013,online,1738
13,4/21/2013,museum,653
13,4/21/2013,guestbook,78
14,4/22/2013,online,1491
14,4/22/2013,museum,568
14,4/22/2013,guestbook,72
15,4/23/2013,online,1403
15,4/23/2013,museum,997
15,4/23/2013,guestbook,184
16,4/24/2013,online,1335
16,4/24/2013,museum,987
16,4/24/2013,guestbook,26
17,4/25/2013,online,1964
17,4/25/2013,museum,753
17,4/25/2013,guestbook,239
18,4/26/2013,online,1260
18,4/26/2013,museum,815
18,4/26/2013,guestbook,249
19,4/27/2013,online,1404
19,4/27/2013,museum,817
19,4/27/2013,guestbook,360
20,4/28/2013,online,1790
20,4/28/2013,museum,840
20,4/28/2013,guestbook,163
21,4/29/2013,online,1698
21,4/29/2013,museum,700
21,4/29/2013,guestbook,129
22,4/30/2013,online,1479
22,4/30/2013,museum,921
22,4/30/2013,guestbook,347
23,5/1/2013,online,1093
23,5/1/2013,museum,720
23,5/1/2013,guestbook,278
24,5/2/2013,online,1148
24,5/2/2013,museum,655
24,5/2/2013,guestbook,162
25,5/3/2013,online,1521
25,5/3/2013,museum,806
25,5/3/2013,guestbook,267
26,5/4/2013,online,1365
26,5/4/2013,museum,662
26,5/4/2013,guestbook,232
27,5/5/2013,online,1809
27,5/5/2013,museum,659
27,5/5/2013,guestbook,398
28,5/6/2013,online,1078
28,5/6/2013,museum,999
28,5/6/2013,guestbook,51
29,5/7/2013,online,1477
29,5/7/2013,museum,512
29,5/7/2013,guestbook,385



回答3:


Just to note, there is a follow-up question here based on the same CSV data but attempting to use transitions. Similarly the error is related to 'area' but within the transition function.



来源:https://stackoverflow.com/questions/15881613/d3-js-streamgraph-example-generating-correct-area-function-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!