预览 d3 条形图,使其按每个 x 值的值排序
Preview d3 bar chart such that it sorted by values for each x value
我用以下数据创建了一个 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>
我得到的结果如下。
我的问题是,我能否重新排列 d3 图表,使其重新排列系列轴,以便按如下方式查看。通过这种方式,每个系列的条形图都会交换每个 x 值。我们可以在 d3 中实现吗?
您可能想要覆盖 nv.models.multiBar
class。这就是绘制条形图的地方。
看起来似乎每个月都有自己的组,并且它们彼此堆叠在一起。每个分组彼此偏移一定量。
您需要按 y-value 对每个组进行排序并更改 x-position(水平边距)。
组偏移由以下因素决定: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;
}
生成的数据是一个地图(按年份),每个月按 y-value 升序排序。我将条形图的原始索引(位置)包含在其分组中。
{
"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;
})
// ...
最终工作演示
免责声明: 这不适用于堆叠,我会在有机会时修复它。这只会解决用户的直接问题。
堆叠
在为 SVG 写出 y-position 之前,d.y1
值是 pre-determined。我们需要 re-calculate 数据中每个项目的 y1
(底部)位置。
if (stacked) {
barSelection
.attr('y', function(d, i, j) {
var yVal = 0;
if (!data[j].nonStackable) {
yVal = y(d.y1); // Already determined...
我用以下数据创建了一个 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>
我得到的结果如下。
我的问题是,我能否重新排列 d3 图表,使其重新排列系列轴,以便按如下方式查看。通过这种方式,每个系列的条形图都会交换每个 x 值。我们可以在 d3 中实现吗?
您可能想要覆盖 nv.models.multiBar
class。这就是绘制条形图的地方。
看起来似乎每个月都有自己的组,并且它们彼此堆叠在一起。每个分组彼此偏移一定量。
您需要按 y-value 对每个组进行排序并更改 x-position(水平边距)。
组偏移由以下因素决定: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;
}
生成的数据是一个地图(按年份),每个月按 y-value 升序排序。我将条形图的原始索引(位置)包含在其分组中。
{
"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;
})
// ...
最终工作演示
免责声明: 这不适用于堆叠,我会在有机会时修复它。这只会解决用户的直接问题。
堆叠
在为 SVG 写出 y-position 之前,d.y1
值是 pre-determined。我们需要 re-calculate 数据中每个项目的 y1
(底部)位置。
if (stacked) {
barSelection
.attr('y', function(d, i, j) {
var yVal = 0;
if (!data[j].nonStackable) {
yVal = y(d.y1); // Already determined...