简体   繁体   English

d3.js 堆叠条形图排序/更改堆栈中各个值的顺序

[英]d3.js stacked bar chart sort / change order of individual values within a stack

In my earlier question: d3.js stacked bar chart - modify stack order logic I learned that d3 doesn't have an off the shelf solution for sorting by individual values within a stack.在我之前的问题中: d3.js 堆积条形图 - 修改堆栈顺序逻辑我了解到 d3 没有现成的解决方案来按堆栈中的单个值进行排序。 D3's stack.order() can only sort the entire series. D3 的stack.order()只能对整个系列进行排序。 I also learned that I will need to write a custom function to achieve this.我还了解到我需要编写一个自定义函数来实现这一点。

Before I get into the function, let me explain the motivation here.在我进入这个函数之前,让我解释一下这里的动机。 I want to show proportions alongside the aggregate total, which is what d3 stacked bar charts are good at.我想在汇总总数旁边显示比例,这正是 d3 堆积条形图所擅长的。 However, I want the emphasis to be on the ranking.但是,我希望重点放在排名上。 This is why I need to change the order the individual rects are ordered in each stack, to reflect any changes in ranking.这就是为什么我需要更改各个 rect 在每个堆栈中的排序顺序,以反映排名的任何变化。 The biggest values should be at the top of the stack, and the smallest values should appear at the bottom.最大值应该在栈顶,最小值应该出现在栈底。 As noted in the previous post, the typical output for stacked bar charts lumps all rects into stacks based only on the initial order.如前一篇文章所述,堆叠条形图的典型输出仅根据初始顺序将所有矩形集中到堆栈中。

Code again for reference:再次代码供参考:

 var margins = { top: 100, bottom: 300, left: 100, right: 100 }; var height = 600; var width = 900; var totalWidth = width + margins.left + margins.right; var totalHeight = height + margins.top + margins.bottom; var svg = d3.select('body') .append('svg') .attr('width', totalWidth) .attr('height', totalHeight); var graphGroup = svg.append('g') .attr('transform', "translate(" + margins.left + "," + margins.top + ")"); var data = [{ period: 't1', fmc1: 2, fmc2: 5, fmc3: 6, fmc4: 9, fmc5: 10 }, { period: 't2', fmc1: 3, fmc2: 4, fmc3: 9, fmc4: 8, fmc5: 11 }, { period: 't3', fmc1: 3, fmc2: 5, fmc3: 15, fmc4: 12, fmc5: 10 }, ]; var groups = d3.map(data, function(d) { return (d.period) }).keys(); var subgroups = Object.keys(data[0]).slice(1); var stackedData = d3.stack() .keys(subgroups) (data); //console.log(stackedData); var yScale = d3.scaleLinear() .domain([0, 80]) .range([height, 0]); var xScale = d3.scaleBand() .domain(['t1', 't2', 't3']) .range([0, width]) .padding([.5]); var colorScale = d3.scaleOrdinal() .domain(subgroups) .range(["#003366", "#366092", "#4f81b9", "#95b3d7", "#b8cce4", "#e7eef8", "#a6a6a6", "#d9d9d9", "#ffffcc", "#f6d18b", "#e4a733", "#b29866", "#a6a6a6", "#d9d9d9", "#e7eef8", "#b8cce4", "#95b3d7", "#4f81b9", "#366092", "#003366"].reverse()); graphGroup.append("g") .selectAll("g") .data(stackedData) .enter().append("g") .attr("fill", function(d) { return colorScale(d.key); }) .selectAll("rect") .data(function(d) { return d; }) .enter().append("rect") .attr("x", function(d) { return xScale(d.data.period); }) .attr("y", function(d) { return yScale(d[1]); }) .attr("height", function(d) { return yScale(d[0]) - yScale(d[1]); }) .attr("width", xScale.bandwidth());
 <script src="https://d3js.org/d3.v5.min.js"></script>

With the data structure becoming significantly more complex after calling d3.stack() this has been a challenge for me.随着调用d3.stack()后数据结构变得更加复杂,这对我来说是一个挑战。 The task is akin to sorting the whole array of arrays based on object values within the nested arrays.该任务类似于根据嵌套数组中的对象值对整个数组数组进行排序。

My best attempt was:我最好的尝试是:

var sortTest = stackedData.sort(stackedData[1].sort((a, b) => a[0] - b[1]));

Which returned the error:返回错误:

Sort function must be a function or undefined排序函数必须是函数或未定义

This turned out to be much more challenging than I imagined, so I then tried to order the data before the stack but that resulted in an inaccurate stack, the relationships were lost.结果证明这比我想象的更具挑战性,所以我尝试在堆栈之前对数据进行排序,但这导致堆栈不准确,关系丢失。

There was a glimmer of hope with this similar question: Sorting a d3.js stacked bar chart这个类似的问题有一线希望: Sorting a d3.js stacked bar chart

However, as the approach did not use d3.stack() , the solution was not applicable to my particular case or any case using d3.stack() .但是,由于该方法未使用d3.stack() ,因此该解决方案不适用于我的特定情况或使用d3.stack()任何情况。

Question

What is the solution for sorting data by individual values when the data is in d3.stack() format?当数据为d3.stack()格式时,按单个值对数据进行排序的解决方案是什么?

I'd use a custom stack function, like below.我会使用自定义堆栈函数,如下所示。 I tried to get a similar data structure as the stacked bar chart, only I have grouped the values by key instead of by their index.我试图获得与堆积条形图类似的数据结构,只是我按键而不是按索引对值进行了分组。 This way, I could sort them more easily.这样,我可以更轻松地对它们进行排序。

 var margins = { top: 30, bottom: 50, left: 30, right: 30 }; var height = 300; var width = 600; var totalWidth = width + margins.left + margins.right; var totalHeight = height + margins.top + margins.bottom; var svg = d3.select('body') .append('svg') .attr('width', totalWidth) .attr('height', totalHeight); var graphGroup = svg.append('g') .attr('transform', "translate(" + margins.left + "," + margins.top + ")"); var data = [{ period: 't1', fmc1: 2, fmc2: 5, fmc3: 6, fmc4: 9, fmc5: 10 }, { period: 't2', fmc1: 3, fmc2: 4, fmc3: 9, fmc4: 8, fmc5: 11 }, { period: 't3', fmc1: 3, fmc2: 5, fmc3: 15, fmc4: 12, fmc5: 10 }, ]; var groups = data.map(function(d) { return d.period; }); var subgroups = Object.keys(data[0]).slice(1); var stackedData = data.map(function(d) { var orderedKeys = subgroups.slice().sort(function(a, b) { return d[a] - d[b]; }); var bottom = 0; var result = orderedKeys.map(function(key) { var value = d[key]; var result = [bottom, bottom + value]; result.data = d; result.key = key; bottom += value; return result; }); result.key = d.period; return result; }); console.log(stackedData); var yScale = d3.scaleLinear() .domain([0, 80]) .range([height, 0]); var xScale = d3.scaleBand() .domain(['t1', 't2', 't3']) .range([0, width]) .padding([.5]); var colorScale = d3.scaleOrdinal() .domain(subgroups) .range(["#003366", "#366092", "#4f81b9", "#95b3d7", "#b8cce4", "#e7eef8", "#a6a6a6", "#d9d9d9", "#ffffcc", "#f6d18b", "#e4a733", "#b29866", "#a6a6a6", "#d9d9d9", "#e7eef8", "#b8cce4", "#95b3d7", "#4f81b9", "#366092", "#003366"].reverse()); graphGroup.append("g") .selectAll("g") .data(stackedData) .enter() .append("g") .selectAll("rect") .data(function(d) { return d; }) .enter() .append("rect") .attr("fill", function(d) { return colorScale(d.key); }) .attr("x", function(d) { return xScale(d.data.period); }) .attr("y", function(d) { return yScale(d[1]); }) .attr("height", function(d) { return yScale(d[0]) - yScale(d[1]); }) .attr("width", xScale.bandwidth());
 <script src="https://d3js.org/d3.v5.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM