23 Stimmen

D3.js - gleichmäßig verteilte Balken auf einer Zeitskala

Ich baue ein Balkendiagramm in d3.js auf, in dem jeder Balken die Gesamtzahl der TB-Fälle in einem Monat darstellt. Die Daten bestehen im Wesentlichen aus einem Datum (zunächst Zeichenfolgen im Format %Y-%m, aber analysiert mit d3.time.format.parse) und einer Ganzzahl. Ich möchte, dass die Achsenbeschriftungen relativ flexibel sind (nur Jahresgrenzen anzeigen, jeden Monat beschriften usw.), aber ich möchte auch, dass die Balken gleichmäßig verteilt sind.

Ich kann flexible Achsenbeschriftungen erhalten, wenn ich eine Datenskala verwende:

var xScaleDate = d3.time.scale()
    .domain(d3.extent(thisstat, function(d) { return d.date; }))
    .range([0, width - margin.left - margin.right]);

... aber die Balken sind nicht gleichmäßig verteilt aufgrund der unterschiedlichen Anzahl von Tagen in jedem Monat (zum Beispiel liegen Februar und März deutlich näher beieinander als andere Monate). Ich kann gleichmäßig verteilte Balken mit einer linearen Skala erhalten:

var xScaleLinear = d3.scale.linear()
      .domain([0, thisstat.length])
      .range([0, width - margin.left - margin.right]);

... aber ich kann nicht herausfinden, wie ich dann datumsbasierte Achsenbeschriftungen haben kann. Ich habe versucht, beide Skalen gleichzeitig zu verwenden und die Achse nur aus der xScaleDate zu generieren, nur um zu sehen, was passieren würde, aber die Skalen stimmen natürlich nicht ganz überein.

Gibt es einen einfachen Weg, um dies zu erreichen, den ich übersehe?

10voto

coquin Punkte 1318

Sie können Ordinal- und Zeitskalen kombinieren:

// Verwenden Sie dies, um die x-Achse zu zeichnen
var xScaleDate = d3.time.scale()
    .domain(d3.extent(thisstat, function(d) { return d.date; }))
    .range([0, width - margin.left - margin.right]);

// Fügen Sie eine Ordinalskala hinzu
var ordinalXScale = d3.scale.ordinal()
    .domain(d3.map(thisstat, function(d) { return d.date; }))
    .rangeBands([0, width], 0.4, 0);

// Jetzt können Sie beide verwenden, um Spalten gleichmäßig zu platzieren:
columnGroup.enter()
    .append("rect")
    .attr("class", "column")
    .attr("width", ordinalXScale.rangeBand())
    .attr("height", function (d) {
        return height - yScale(d.value);
    })
    .attr("x", function (d) {
        return xScaleDate(d.date);
    })
    .attr("y", function (d){
        return yScale(d.value);
    });

Ich habe vor einiger Zeit ein Beispiel erstellt, um diesen Ansatz zu demonstrieren: http://codepen.io/coquin/pen/BNpQoO

1voto

Andrew Punkte 536

Ich hatte das gleiche Problem, ich habe akzeptiert, dass einige Monate länger sind als andere und habe die Breite der Säulenspalte angepasst, so dass der Abstand zwischen den Balken konstant bleibt. Durch Anpassen der barPath-Funktion im crossfilter-Startseiten-Demo (http://square.github.com/crossfilter/ - verwendet d3) habe ich etwas in dieser Art bekommen:

var colWidth = Math.floor(x.range()[1] / groups.length) - 1;//9;
if (i < n - 1) {
     //Wenn rechts eine Säule sein wird, diese Säule einen Pixel nach links beenden
      var nextX = x(groups[i+1].key)
      colWidth = nextX - x(d.key) - 1;
}
path.push("M", x(d.key), ",", height, "V", yVal, "h",colWidth,"V", height);

-2voto

Paulo Punkte 85

Versuchen Sie d3.scale.ordinal:

    var y = d3.scale.ordinal()
     .domain(yourDomain)
     .rangeRoundBands([0, chartHeight], 0.2);

Passen Sie den Parameter 0.2 an.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X