使用自定义(范围)值创建轴

时间:2017-12-21 11:08:25

标签: javascript d3.js

我想在我的密度图中添加带有自定义值的xAxis(参见屏幕截图)。

Adding Custom x-Axis

第一密度“小提琴”代表“0-50”,第二代表“51-100”,第三密度代表“101-150”......第七密度代表“301-350”乘客。它应该类似于以下编辑的屏幕截图中显示的内容。

enter image description here

由于我是d3和javascript的新手,我会很感激详细解答。 我正在使用d3.js(v4)。

这是我目前的代码:

function addViolin(svg, dataOfBin, heightPlot, widthPlot, domain, imposeMax, violinColor){


        var data = d3.histogram()
                    .thresholds(resolution)
                    (dataOfBin);

        var y = d3.scaleLinear()
                    .range([widthPlot/2, 0])
                    .domain([0, Math.max(imposeMax, d3.max(data, function(d) { return d.length; }))]);

        var x = d3.scaleLinear()
                    .range([heightPlot, 0])
                    .domain(domain)
                    .nice();


        var area = d3.area()
            .curve(d3.curveCardinal)
            .x(function(d) {
                   if(interpolation=="step-before")
                        return x(d.x1/2)
                   return x(d.x);
                })
            .y0(widthPlot/2)
            .y1(function(d) { return y(d.length); });


        var line=d3.line()
            .curve(d3.curveCardinal)
            .x(function(d) {
                   if(interpolation=="step-before")
                        return x(d.x1/2)
                   return x(d.x);
                })
            .y(function(d) { return y(d.length); });

        var gPlus=svg.append("g")
        var gMinus=svg.append("g")

        gPlus.append("path")
          .datum(data)
          .attr("class", "area")
          .attr("d", area)
          .style("fill", violinColor);

        gPlus.append("path")
          .datum(data)
          .attr("class", "violin")
          .attr("d", line)
          .style("stroke", violinColor);


        gMinus.append("path")
          .datum(data)
          .attr("class", "area")
          .attr("d", area)
          .style("fill", violinColor);

         gMinus.append("path")
           .datum(data)
           .attr("class", "violin")
           .attr("d", line)
           .style("stroke", violinColor);

        gPlus.attr("transform", "rotate(90,0,0)  translate(0,-"+widthPlot+")");//translate(0,-200)");

        gMinus.attr("transform", "rotate(90,0,0) scale(1,-1)");

}

function addBoxPlot(svg, dataOfBin, heightPlot, widthPlot, domain, boxPlotWidth, boxColor, boxInsideColor){
}

var marginPlot={top:10, bottom:0, left:30, right:10};

var widthPlot=400;
var heightPlot=220;
var boxWidth=44;
var boxSpacing=10;

var resolution=1000;
var d3ObjId="svgElement1";
var interpolation='step-before';


function showView3(data){
    var regionChart = document.getElementById("view3Diagram");
    if(regionChart != null){
        regionChart.innerHTML = "";
    }


    var domain=[0, 370];
    var y = d3.scaleLinear()
                .range([heightPlot-marginPlot.bottom, marginPlot.top])
                .domain(domain);

    var yAxis = d3.axisLeft()
                    .scale(y)
                    .ticks(5)
                    .tickSize(5,0,5);


    var svg = d3.select("div#view3Diagram")
                .append("div")
                .classed("svg-container2", true)
                .append("svg")
                .attr("preserveAspectRatio", "xMinYMin meet")
                .attr("viewBox", "0 0 430 430")
                .classed("svg-content-responsive", true);


    svg.append("line")
        .attr("class", "boxplot")
        .attr("x1", marginPlot.left)
        .attr("x2", widthPlot-marginPlot.right)
        .attr("y1", y(0))
        .attr("y2", y(0));

    for(var i=0; i<data.length; i++){
        data[i].Haltezeiten=data[i].Haltezeiten.sort(d3.ascending)
        var g=svg.append("g").attr("transform", "translate("+(i*(boxWidth+boxSpacing)+marginPlot.left)+",0)");
        addViolin(g, data[i].Haltezeiten, heightPlot, boxWidth, domain, 0.25, "#424242");
        addBoxPlot(g, data[i].Haltezeiten, heightPlot, boxWidth, domain, .15, "black", "white");

    }

    svg.append("g")
        .attr('class', 'axis')
        .attr("transform", "translate("+marginPlot.left+",0)")
        .call(yAxis);

}

1 个答案:

答案 0 :(得分:2)

根据您的要求,我会在这个答案中写一个详细的解释(但是,这段代码似乎不是新手的作品......)。

正如我们所看到的,您使用for循环...

for(var i=0; i<data.length; i++){

...创建<g>元素,并在其中每个元素中创建小提琴图。

所以,最重要的是data.length。我们将使用它来设置域或我们的点比例,这将是定制轴的基础&#39;嘀嗒声。跟我来:

如果您将d3.range(data.length)作为比例范围传递,则您将拥有一组长度相同data.length的数字。例如,如果data.length为7,则这是d3.range(data.length)

的结果
[0, 1, 2, 3, 4, 5, 6]

然后,通过此域,我们可以使用tickFormat在轴上创建自定义。为此,我将设置一个名为steps的变量,该变量表示第一个刻度中值之间的差距。在您的示例中:

var steps = 50;

使用域和step设置,这是tickFormat中的数学:

.tickFormat(function(d, i) {
    return i ? (d * steps) + 1 + " - " + (d * steps + steps) 
    : (d * steps) + " - " + (d * steps + steps);
});

如果您不知道,这是ternary operator。它基本上是:

condition ? expr1 : expr2

如果condition为真,则执行expr1,否则执行expr2

确保将相同的范围传递给比例,并相应地对其进行翻译。

以下是正在运行的演示:

&#13;
&#13;
var svg = d3.select("svg");
var steps = 50;
var data = ["foo", "foo", "foo", "foo", "foo", "foo", "foo"];
var scale = d3.scalePoint()
  .range([20, 470])
  .domain(d3.range(data.length));
var axis = d3.axisBottom(scale)
  .tickFormat(function(d, i) {
    return i ? (d * steps) + 1 + " - " + (d * steps + steps) : (d * steps) + " - " + (d * steps + steps);
  });
var gX = svg.append("g")
  .attr("transform", "translate(0,50)")
  .call(axis)
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="500"></svg>
&#13;
&#13;
&#13;