2016-04-16 14 views
0

Derzeit habe ich ein Flächendiagramm, das die Bereiche mehrerer Datenpfade anzeigt. Ich suche jedoch nach einer Möglichkeit, dies in ein gestapeltes Flächendiagramm umzuwandeln. Grundsätzlich möchte ich, dass die Datensätze übereinander gestapelt werden, sodass sie sichtbar sind und nicht von anderen größeren Bereichen verdeckt werden. Ich habe zwei Beispiele gefunden: http://bl.ocks.org/mbostock/3885211 und http://bl.ocks.org/mbostock/3020685. Das Problem, das ich habe, ist, dass meine Daten in einem ganz anderen Format sind und ich bin mir auch nicht sicher, wie d3 das tatsächlich funktioniert. Konzeptionell fällt es mir schwer zu verstehen, was d3 hinter den Kulissen macht. Mein Verständnis ist, dass es die Unterschiede zwischen der letzten hinzugefügten Schicht berechnet, aber es scheint, dass das ohne Verwendung von Stapeln getan werden könnte.Wie kann ich einen vorhandenen d3-Bereich in einen gestapelten Bereich umwandeln?

ist Meine Daten wie folgt strukturiert:

// datasets { data1: Array[10], data2: Array[10], data3: Array[10] } 
// data1 [{value: 2340234, year: 1945}...] 

Und die Zeichenfunktion ist dies:

function draw(series) { 
    var data1 = []; 
    var data2 = []; 
    var data3 = []; 
    var prop = 0; 

    for (prop in series) { 
    var current = series[prop]; 

    data1.push({value: current.data1, year: current.year}); 
    data2.push({value: current.data2, year: current.year}); 
    data3.push({value: current.data3, year: current.year}); 
    } 

    var datasets = { 
    data1: data1, 
    data2: data2, 
    data3: data3 
    }; 

    // updated 
    var layers = [datasets.data1, datasets.data2, datasets.data3]; 

    var height = 800; 
    var width = window.innerWidth - 100; 

    var x = d3.time.scale() 
     .range([0, width]); 

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

    var xAxis = d3.svg.axis() 
     .scale(x) 
     .orient("bottom"); 

    var yAxis = d3.svg.axis() 
     .scale(y) 
     .orient("left"); 

    // updated 
    var stack = d3.layout.stack() 
     .values(function(d) { return d.values; }); 
    /

    var stacked = stack(layers.map(function(layer) { 
    return { 
     values: layer.map(function(d) { 
     return { year: new Date(d.year, 0), y: +d.value}; 
     }) 
    }; 
    })); 

    var area = d3.svg.area() 
     .x(function(d) { 
      console.log(x(d.year) + ' is the result of x(d.year)') 
      return x(d.year); 
     }) 
     // d.year is defined correctly 
     .y0(height) 
     .y1(function(d) { 
      console.log(y(d.value) + ' is the result of y(d.value)') 
      return y(d.value); 
     }); 
     // d is Object {year: Sat Jan 01 2005 00:00:00 GMT-0800 (PST), y: 47390331, y0: 0} 
     // here y(d.value) returns NaN for some reason 

    var svg = d3.select('body').append("svg") 
    .append("g") 
     .attr("transform", "translate(" + 120 + "," + 30 + ")"); 

    // Calculate max value 
    var maxY = 0; 
    var minY = 0; 
    series.forEach(function(object) { 
    for (var key in object) { 
     if (object[key] > maxY) { 
     maxY = object[key]; 
     } 
    } 
    }); 

    // Calculate min value 
    series.forEach(function(object) { 
    for (var key in object) { 
     if (object[key] < minY) { 
     minY = object[key]; 
     } else if (minY === 0) { 
     continue; 
     } 
    } 
    }); 

    var minYear = new Date("1945"); 
    var maxYear = new Date("2015"); 

    x.domain([minYear, maxYear]); 
    y.domain([minY, maxY]); 

    svg.append("path").data(stacked) 
    .attr('d', function(d) { return area(d.values); }); 

    svg.append("g") 
    .attr("class", "x axis") 
    .attr("transform", "translate(0," + height + ")") 
    .call(xAxis); 

    svg.append("g") 
    .attr("class", "y axis") 
    .call(yAxis); 

} 

Was ist der beste Weg, dies zu einer gestapelten Flächendiagramm zu konvertieren?

bearbeiten

behoben. Lösung inklusive Berechnungsbereich wie im Beispiel zu sehen:

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

Antwort

1

Die schnelle Vorbeiflugs von dem, was Sie tun müssen:


Erstellen eines geeigneten Stapel Generator:

var stack = d3.layout.stack() 
    .values(function(d) { return d.values; }); 

Führen Sie Ihre Daten durch den Stapelgenerator. Sie sollten dem Generator eine Reihe von "Schichten" geben. Für das Beispiel unten nehme ich an, dass etwas wie layers = [datasets.data1, datasets.data2, datasets.data3] passiert ist.

var stacked = stack(layers.map(function(layer) { 
    return { 
     values: layer.map(function(d) { 
     return {year: new Date(d.year, 0), y: +d.value}; 
     }) 
    }; 
    })); 

values Der Schlüssel ist die gleiche, früher verwendet, wenn der Generator der Einrichtung. Sie können diesem Objekt weitere Objekte hinzufügen, wenn Sie sie später während der Zeichnung benötigen.


Nachdem die gestapelten Daten erstellt wurde, ist es durch die Gegend Generator laufen:

svg.append("path") 
    .data(stacked) 
    .attr("d", function(d) { return area(d.values); }); 

In Ihrem ursprünglichen Code, den Sie .datum(datasets[data]) verwendet — Sie können tun dies auch weiterhin, wenn Sie wollen, aber die for-Schleife wird müssen die gestapelten Daten laufen über:

for (var data in stacked) { ... 

Allerdings empfehle ich .data über .datum wher e möglich. Sie machen eine Menge Manipulation am ursprünglichen Dataset, bevor Sie es an die d3-Generatoren senden, aber ich vermute, dass das meiste unnötig oder doppelt ist.Sie sollten in der Lage sein, etwas, das wie folgt aussieht:

var datasets = ... 

    var stacked = stack(datasets.map(function(dataset) { ... })); 

    svg.selectAll("path") 
     .data(stacked) 
     .enter() 
     .attr("d", function(d) { return area(d.values); }); 

die Datensätze einrichten und die Generatoren sollten nicht mehr als die Abbildung der Positionen der spezifischen Felder/Werte Ihnen wichtig sein.

Wenn es helfen würde, kann ich versuchen, ein voll funktionsfähiges Beispiel zu bekommen. Ich würde jedoch eine echte Datendatei benötigen.

Verwandte Themen