2017-10-13 61 views
1

有没有办法让平行坐标一直走到边缘,然后等距离地将这些“尺寸”隔开?我认为x = d3.scaleBand().rangeRound([0, width]).padding(1)是这里的罪魁祸首,但似乎还有其他东西在起作用。如果有人帮我在这里,我会很感激。如何使用带标将图表推向边缘

enter image description here

var margin = {top: 20, right: 10, bottom: 10, left: 20}, 
        width = d3.select(ele[0])._groups[0][0].offsetWidth - margin.left - margin.right, 
        height = 400 - margin.top - margin.bottom; 

       // set the height based on the calculations above 
       svg.attr('height', height + margin.top + margin.bottom); 

       var x = d3.scaleBand().rangeRound([0, width]).padding(1), 
        y = {}, 
        dragging = {}, 
        selected; 

       var line = d3.line(), 
        background, 
        foreground, 
        extents; 

       x.domain(dimensions = d3.keys(data[0]).filter(function(d) { 
        if(d === "name") { 
         return false; 
        } 
        return y[d] = d3.scaleLinear() 
         .domain(d3.extent(data, function(p) { 
          return +p[d]; })) 
         .range([height, 0]); 
       })); 

       extents = dimensions.map(function(p) { return [0,0]; }); 

       // Add grey background lines for context. 
       background = svg.append("g") 
        .attr("class", "background") 
        .attr("transform", "translate(0," + margin.top + ")") 
        .selectAll("path") 
        .data(data) 
        .enter().append("path") 
        .attr("d", path); 

       // Add blue foreground lines for focus. 
       foreground = svg.append("g") 
        .attr("class", "foreground") 
        .attr("transform", "translate(0," + margin.top + ")") 
        .selectAll("path") 
        .data(data) 
        .enter().append("path") 
        .attr("d", path); 

       // Add a group element for each dimension. 
       var g = svg.selectAll(".dimension") 
        .data(dimensions) 
        .enter().append("g") 
        .attr("class", "dimension") 
        .attr("transform", function(d) { return "translate(" + x(d) + ")"; }) 
        .call(d3.drag() 
         .subject(function(d) { return {x: x(d)}; }) 
         .on("start", function(d) { 
          dragging[d] = x(d); 
          background.attr("visibility", "hidden"); 
         }) 
         .on("drag", function(d) { 
          dragging[d] = Math.min(width, Math.max(0, d3.event.x)); 
          foreground.attr("d", path); 
          dimensions.sort(function(a, b) { return position(a) - position(b); }); 
          x.domain(dimensions); 
          g.attr("transform", function(d) { return "translate(" + position(d) + ")"; }) 
         }) 
         .on("end", function(d) { 
          delete dragging[d]; 
          transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")"); 
          transition(foreground).attr("d", path); 
          background 
           .attr("d", path) 
           .transition() 
           .delay(500) 
           .duration(0) 
           .attr("visibility", null); 
         })); 

       // Add an axis and title. 
       g.append("g") 
        .attr("class", "y axis") 
        .each(function(d) { d3.select(this).call(d3.axisLeft(y[d]));}) 
        .attr("transform", "translate(0," + margin.top + ")") 
        .append("text") 
        .style("text-anchor", "middle") 
        .attr("y", -9) 
        .text(function(d) { return d; }); 

       // Add and store a brush for each axis. 
       g.append("g") 
        .attr("class", "brush") 
        .attr("transform", "translate(0," + margin.top + ")") 
        .each(function(d) { 
         d3.select(this) 
          .call(y[d].brush = d3.brushY().extent([[-8, 0], [8,height]]) 
           .on("brush start", brushstart) 
           .on("brush", brush_parallel_chart)); 
        }) 
        .selectAll("rect") 
        .attr("x", -8) 
        .attr("width", 16); 

       function position(d) { 
        var v = dragging[d]; 
        return v === null || v === undefined ? x(d) : v; 
       } 

       function transition(g) { 
        return g.transition().duration(500); 
       } 

       // Returns the path for a given data point. 
       function path(d) { 
        return line(dimensions.map(function(p) { 
         return [position(p), y[p](d[p])]; 
        })); 
       } 

       function brushstart() { 
        d3.event.sourceEvent.stopPropagation(); 
       } 

       function within(d, extent){ 
        return extent[1] <= d && d <= extent[0]; 
       } 

       // Handles a brush event, toggling the display of foreground lines. 
       function brush_parallel_chart() { 
        for(var i = 0; i < dimensions.length; ++i){ 
         if(d3.event.target === y[dimensions[i]].brush) { 
          extents[i] = d3.event.selection.map(y[dimensions[i]].invert,y[dimensions[i]]); 
         } 
        } 

        foreground.style("display", function(d) { 
         return dimensions.every(function(p, i) { 
          if(extents[i][0]===0 && extents[i][1]===0) { 
           return true; 
          } 
          return within(d[p], extents[i]) 
         }) ? null : "none"; 
        }); 

        selected = data.filter(function(item){ 
         if(dimensions.every(function(dim, index){ 
           if(extents[index][0]===0 && extents[index][1]===0) { 
            return true; 
           } 
           return within(item[dim], extents[index]); 
          })){ 
          return true; 
         } 
        }); 

        scope.onBrush({item: selected}); 
       } 

回答

1

对于这个dataviz,band scale是错误的工具。

问题是,一个频段有相关的带宽。所以,当你使用一个带刻度,它会返回各自带宽的左缘(或,换句话说,“台阶”的左边空白处):

enter image description here

看看返回的值通过使用5个值和范围会从0100一个带刻度:

var data = "abcde".split("") 
 
var s = d3.scaleBand() 
 
    .domain(data) 
 
    .range([0, 100]); 
 

 
data.forEach(function(d) { 
 
    console.log(s(d)) 
 
})
<script src="https://d3js.org/d3.v4.min.js"></script>

如果设置填充为1它将帮助减少带宽,但并不多(更多的下面):

var data = "abcde".split("") 
 
var s = d3.scaleBand() 
 
    .domain(data) 
 
    .range([0, 100]) 
 
    .padding(1); 
 

 
data.forEach(function(d) { 
 
    console.log(s(d)) 
 
})
<script src="https://d3js.org/d3.v4.min.js"></script>

解决方案

使用一个点,而不是规模。点秤有没有带宽:

enter image description here

这里是演示,看看值:

var data = "abcde".split("") 
 
var s = d3.scalePoint() 
 
    .domain(data) 
 
    .range([0, 100]); 
 

 
data.forEach(function(d) { 
 
    console.log(s(d)) 
 
})
<script src="https://d3js.org/d3.v4.min.js"></script>

关于填充,因为我说上“更多低于“:你差不多了!问题是padding是...

...一种方便的方法,用于将内部和外部填充设置为相同的填充值。

因此,它设置内部填充和外部填充。如果您使用paddingInner(1)paddingOuter(0)你会得到一个点规模相同的结果:

var data = "abcde".split("") 
 
var s = d3.scaleBand() 
 
    .domain(data) 
 
    .range([0, 100]) 
 
    .paddingInner(1) 
 
    .paddingOuter(0); 
 

 
data.forEach(function(d) { 
 
    console.log(s(d)) 
 
})
<script src="https://d3js.org/d3.v4.min.js"></script>

+1

这太棒了。这很有道理。我知道它必须是乐队的东西。我最初的直觉是将'outerPadding()'设置为0,但没有设置'innerPadding()',它仍然不正确。谢谢你澄清! – konrad

-2

尝试改变margin到:第一行

var margin = {top: 20, right: 0, bottom: 10, left: 0}, 

。余量是图表周围有多少空间。这也应该更改width的值,该值在其声明中使用了边距。由于宽度将增加,x尺度应该改变,使得“尺寸”等间距但彼此进一步分开。

+0

正如你可以看到我的当前设置,右边距为10px的。这几乎没有接近正在应用的偏移量。 SVG对象的宽度设置为100%,因此它是它所在的div框架的大小。“width”值设置为div的宽度 - margin.left - margin.right,因此它只小了30px,但我的图表并没有占用太多的空间。我猜问题是RangeRound()以及间隔如何设置,或者尺寸如何偏移。 – konrad