javascript - 预览 d3 条形图,使其按每个 x 值的值排序

标签 javascript sorting d3.js nvd3.js

我使用以下数据创建了一个 nvd3 组条形图。

var data = [{
  key: "JUN",
  values: [
    { x: 2013, y: 200 },
    { x: 2014, y: 352 },
    { x: 2015, y: 1100 },
    { x: 2016, y: 120 }
  ]
}, {
  key: "JUL",
  values: [
    { x: 2013, y: 200 },
    { x: 2014, y: 862 },
    { x: 2015, y: 124 },
    { x: 2016, y: 500 }
  ]
}, {
  key: "MAR",
  values: [
    { x: 2013, y: 578 },
    { x: 2014, y: 964 },
    { x: 2015, y: 788 },
    { x: 2016, y: 152 }
  ]
}, {
  key: "JAN",
  values: [
    { x: 2013, y: 20 },
    { x: 2014, y: 485 },
    { x: 2015, y: 258 },
    { x: 2016, y: 900 }
  ]
}];

nv.addGraph(function() {
  var chart = nv.models.multiBarChart();

  chart.xAxis.tickFormat(d3.format(',f'));
  chart.yAxis.tickFormat(d3.format(',.1f'));

  d3.select('#chart svg')
      .datum(data)
      .transition().duration(500)
      .call(chart);

  nv.utils.windowResize(chart.update);

  return chart;
});
#chart svg {
  height: 400px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.js"></script>

<div id="chart"><svg></svg></div>


我得到的结果如下。 enter image description here

我的问题是,我能否重新排列 d3 图表,使其重新排列系列轴,以便按如下方式查看。通过这种方式,每个系列的条形图都会交换每个 x 值。我们可以在 d3 中实现吗?

enter image description here

最佳答案

您可能想要覆盖 nv.models.multiBar类(class)。这就是绘制条形图的地方。

看起来每个月都有自己的组,并且它们相互堆叠。每个分组都相互偏移一定量。

您需要按 y 值对每个组进行排序并更改 x 位置(水平边距)。

组偏移由:x(getX(d, i))决定。

bars
  .attr('class', function(d, i) {
    return getY(d, i) < 0 ? 'nv-bar negative' : 'nv-bar positive'
  })
  .attr('transform',
    function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)';
  })

组内的条形位置由以下因素决定:

barSelection
  .attr('x', function(d, i) {
    return d.series * x.rangeBand() / data.length;
  })

如果可以对数据进行排序,则可以更改这些值。


您可以使用以下方法转换数据。这可以在条形图布局函数中使用以引用索引位置。

function sortGroupedData(data) {
  var groups = {};
  for (var m = 0; m < data.length; m++) {
    var subset = data[m];
    for (var y = 0; y < subset.values.length; y++) {
      var point = subset.values[y],
          tuples = groups[point.x] || [];
      tuples.push([subset.key, point.y, m]);
      groups[point.x] = tuples;
    }
  }
  Object.keys(groups).forEach(function(key) {
    groups[key].sort(function(a, b) {
      return a[1] - b[1];
    });
  });
  return groups;
}

结果数据是一个 map (按年份),每个月按其 y 值升序排序。我将条形图的原始索引(位置)包含在其分组中。

{
  "2013" : [
    ["JAN", 20,  3],
    ["JUN", 200, 0],
    ["JUL", 200, 1],
    ["MAR", 578, 2]
  ],
  "2014" : [
    ["JUN", 352, 0],
    ["JAN", 485, 3],
    ["JUL", 862, 1],
    ["MAR", 964, 2]
  ],
  "2015" : [
    ["JUL", 124,  1],
    ["JAN", 258,  3],
    ["MAR", 788,  2],
    ["JUN", 1100, 0]
  ],
  "2016" : [
    ["JUN", 120, 0],
    ["MAR", 152, 2],
    ["JUL", 500, 1],
    ["JAN", 900, 3]
  ]
}

所需的代码更改

nv.models.multiBar = function() {
  // ...
  function chart(selection) {
    // ...
    selection.each(function(data) {
      var dataMap = sortGroupedData(data);
      // ...
      else {
        barSelection
          .attr('x', function(d,i) {
            var pos = dataMap[d.x].map((val, idx) => val[0] === d.key ? idx : -1).filter(x => x > -1)[0];
            return pos * x.rangeBand() / data.length;
          })
        // ...

最终工作演示

免责声明:这不适用于堆叠,我会在有机会时修复它。这只会解决用户眼前的问题。

https://jsfiddle.net/MrPolywhirl/xrj4eyph/


堆积

d.y1 值是在写出 SVG 的 y 位置之前预先确定的。我们需要重新计算数据中每个项目的 y1(底部)位置。

if (stacked) {
  barSelection
    .attr('y', function(d, i, j) {
      var yVal = 0;
      if (!data[j].nonStackable) {
        yVal = y(d.y1); // Already determined...

关于javascript - 预览 d3 条形图,使其按每个 x 值的值排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49637313/

相关文章:

javascript - Google Map API - 获取有关一个坐标的信息

javascript - 在 jQuery/Javascript 中生成复杂的 HTML 元素

c++ - 为什么自定义数据的 thrust::sort 需要默认构造函数而 STL::sort 不需要?

javascript - 是否可以将饼图添加到 d3 工具提示中

reactjs - React-hooks 和 d3.forceSimulation

javascript - 用 Puppeteer 提取所有 CSS?

javaScript 过滤嵌套对象和数组

Python 对排序列表重新排序,使最高值位于中间

python - 需要在 Python 中对长的、格式奇怪的数据集取平均值

javascript - 具有多个图的 D3 转换