D3 - 收缩线性刻度范围

时间:2016-04-14 12:25:36

标签: d3.js svg

我试图从包含2个值的简单数据集中创建一个非常简单的堆叠水平条形图。

  1. 我想分别在条形图的左侧和右侧显示数据集值。 <svg>是500px宽,我想 要显示的图表从100到400,以便我可以在条形图之前和之后容纳<text>。为此,我试图缩小范围 从[0,500]到[100,400],但结果不符合预期。

  2. 我还想在不使用layout.stack()的情况下绘制图表,以便我可以使用像[66852,7550]这样的简单数据集

  3. 这是Fiddle

    //Width and height
    var w = 500;
    var h = 60;
    
    //Original data
    //var dataset = [66852, 7550]
    //changed to below to support layout.stack()
    var dataset = [ [{y:66852}], [{y:7550}] ];
    
    //Set up stack method
    var stack = d3.layout.stack();
    
    //Data, stacked
    stack(dataset);
    
    //Set up scales
    var xScale = d3.scale.linear()
        .domain([0, d3.max(dataset, function(d) {
                return d3.max(d, function(d) {
                    return d.y0 + d.y;
                });
            })
        ])
        .range([100, 400]);
    
    var yScale = d3.scale.ordinal() 
        .domain(d3.range(dataset[0].length))
        .rangeRoundBands([0, h], 0.05);
    
    //Easy colors accessible via a 10-step ordinal scale
    var colors = d3.scale.category10();
    
    //Create SVG element
    var svg = d3.select(".chart")
        .attr("width", w)
        .attr("height", h);
    
    // Add a group for each row of data
    var groups = svg.selectAll("g")
        .data(dataset)
        .enter()
        .append("g")
        .style("fill", function(d, i) {
            return colors(i);
        });
    
    // Add a rect for each data value
    var rects = groups.selectAll( 'rect' )
        .data( function( d ) { return d; } )
        .enter()
        .append("rect") 
        .attr("x", function(d, i) {     
            return xScale(d.y0);        
        })
        .attr("y", function(d, i) {
            console.log('y: '+yScale(i));
            return yScale(i);
        })  
        .attr("width", function(d) {
            console.log('width: '+xScale(d.y));
            return xScale(d.y);
        })
        .attr("height", 10);
    

1 个答案:

答案 0 :(得分:2)

问题是,尽管它的名称,你的线性xScale不是线性的(0的图像是100)。因此,当您使用return xScale(d.y);作为宽度时,您将为每个矩形的宽度添加100(在数学术语中,使用的函数是xScale(z)= 0.00211 * z + 100:这是仿射,而不是线性)。

编辑,示例:

  • 从d.y0 = 0开始的矩形必须具有x = 100
  • d.y = 0的矩形必须具有width = 0
  • 一个d.y0 = 71000(大约一半的总和)的矩形必须有x = 250(图中间)
  • d.y = 71000的矩形必须宽度= 150(图纸宽度的一半)

=&GT;对于宽度和x位置,不可能直接使用相同的比例。因此,要么使用不同的函数来计算宽度和x,要么使用额外的transform来欺骗x(请参阅下面的原始解决方案)。

最简单的解决方案是range [0,300](而不是[100,400]),并将绘图区域放在g .attr("transform", "translate(100,0)")之内以情节为中心。

第二个选项(听起来像你喜欢的那个):使用xScale(d.y0+d.y) - xScale(d.y0)作为宽度(而不只是xScale(d.y))。这直接计算左右端点之间的距离,即它给出宽度。它应该适用于任何比例(不一定是线性的)。

至于你的第二个问题,我真的不知道另外一般的做法(除了编写你自己的绘图程序,它不会太难)。但您可以轻松地将简单数组转换为适合布局的数组:

var dataset = [66852, 7550]
var layoutDataset = dataset.map(function(d){ return [{y:d}] });