javascript - D3 堆积线段图,按总计排序
问题描述
在过去的几天里,我一直在尝试创建一个堆叠的分段图表,并且在所有三角函数和键堆叠之间,应用似乎是最基本的调整对我来说确实是一场噩梦。目前,我的分段图表具有基于降序排序的数据Active equity
。我想更改它以使数据按total
.
const csvData = `State,Active equity,Passive equity,Fixed income,Mixed assets
BlackRock,1,17,0,0
Fidelity,13,2,0,0
SSgA,12,0,0,0
Hang Seng,11,0,0,0
UBS,9,0,0,1
Schroders,6,0,2,1
JP Morgan,5,2,0,1
Value Partners,1,0,6,0
First State,5,0,0,0
Invesco,4,1,0,0
HSBC,1,1,1,1
DBS,0,2,1,0
BOCI,1,1,1,0
CSOP,0,2,1,0
Principal,1,1,0,0
Allianz,2,1,0,0
Yuanta,0,2,1,0
Manulife,1,0,1,0
Aberdeen,2,0,0,0
Mirae,1,1,0,0
,0,0,0,0`;
//const data = d3.csvParse(csvData, d3.autoType);
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(250,250)");
var x = d3.scaleBand()
.range([0, 2 * Math.PI])
.align(0);
var y = d3.scaleRadial()
.range([innerRadius, outerRadius]);
var z = d3.scaleOrdinal()
.range(["#003366", "#4f81b9", "#95b3d7", "#f6d18b"]);
d3.csv("csvData", function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}, function(error, data) {
if (error) throw error;
weave(data, function(a, b) { return b[data.columns[6]] - a[data.columns[6]]; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })*1.3]);
z.domain(data.columns.slice(1));
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc2")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius+2)
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.90; })
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class','bg-arc2')
.attr('fill','none')
.attr('stroke-width','4px')
.attr('stroke','#003366');
graphGroup.append('circle')
.attr('cx',0)
.attr('cy',0)
.attr('r',200)
.style('fill','#d9d9d9');
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.95; })
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class','bg-arc')
.attr('fill','#fff');
graphGroup.append('circle')
.attr('cx',0)
.attr('cy',0)
.attr('r',innerRadius)
.style('fill','#fff');
var stackedData = d3.stack().keys(data.columns.slice(1))(data);
var stackedData2 = stackedData.sort(function(a,b) { return d3.descending(a[0].data.total, b[0].data.total)});
console.log(stackedData[0][0].data.total)
console.log(stackedData2);
graphGroup.append("g")
.selectAll("g")
.data(stackedData)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("path")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(function(d) { return y(d[0]); })
.outerRadius(function(d) { return y(d[1]); })
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.95; })
.padAngle(0.04)
.padRadius(innerRadius));
var label = graphGroup.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "rotate(" + ((x(d.State) + x.bandwidth() / 2) * 180 / Math.PI - 90) + ")translate(" + (outerRadius+25) + ",0)"; });
label.append("text")
.attr("transform", function(d) { return (x(d.State) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)"; })
.text(function(d) { return d.State; });
var yAxis = graphGroup.append("g")
.attr("text-anchor", "end");
var yTick = yAxis
.selectAll("g")
.data(y.ticks(10).slice(1))
.enter().append("g");
});
function weave(array, compare) {
var i = -1, j, n = array.sort(compare).length, weave = new Array(n);
while (++i < n) weave[i] = array[(j = i << 1) >= n ? (n - i << 1) - 1 : j];
while (--n >= 0) array[n] = weave[n];
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://gist.githubusercontent.com/mbostock/3686329aa6e1f5938df8eef12ec353fe/raw/1ab722df937c3ac86cac8292e34cfc7279b017f8/d3-scale-radial.js"></script>
相关代码在这里:
var stackedData = d3.stack().keys(data.columns.slice(1))(data);
var stackedData2 = stackedData.sort(function(a,b) { return d3.descending(a[0].data.total, b[0].data.total)});
console.log(stackedData[0][0].data.total)
console.log(stackedData2);
我通过控制台日志检查以确保我在正确的位置进行切片,正如我所确认的那样,console.log(stackedData[0][0].data.total)
它返回了正确的18
.
但是我不能根据需要应用排序。数据仍然按Active equity
而不是总计排序。
问题
堆叠径向图的默认排序似乎是第一个变量。在我的情况下,它是Active equity
. 考虑到这一点,根据我上面的进展,是什么阻止我应用降序排序data.total
而不是默认排序?
解决方案
您的问题不清楚:您是在谈论对每个切片中的片段进行排序,还是在谈论对切片本身进行排序?
对于第一种情况,有一个名为 的方法order
,您可以将其与堆栈生成器一起使用(链接转到 v5 文档,它与 v4 有点不同)。但是,因为您说“我想更改 [顺序] 以使数据按总计排序”,所以在我看来,您是在谈论对切片进行排序。如果这是正确的,有两个观察结果:它不是按 排序的Active equity
,现在它只是原始数据数组中对象的顺序。
对于排序,total
您只需要更改该数组:
data.sort(function(a, b) {
return b.total - a.total;
});
此外,摆脱该weave
功能。
结果如下:
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("d3-scale")) :
typeof define === "function" && define.amd ? define(["exports", "d3-scale"], factory) :
(factory(global.d3 = global.d3 || {}, global.d3));
}(this, function(exports, d3Scale) {
'use strict';
function square(x) {
return x * x;
}
function radial() {
var linear = d3Scale.scaleLinear();
function scale(x) {
return Math.sqrt(linear(x));
}
scale.domain = function(_) {
return arguments.length ? (linear.domain(_), scale) : linear.domain();
};
scale.nice = function(count) {
return (linear.nice(count), scale);
};
scale.range = function(_) {
return arguments.length ? (linear.range(_.map(square)), scale) : linear.range().map(Math.sqrt);
};
scale.ticks = linear.ticks;
scale.tickFormat = linear.tickFormat;
return scale;
}
exports.scaleRadial = radial;
Object.defineProperty(exports, '__esModule', {
value: true
});
}));
const csvData = `State,Active equity,Passive equity,Fixed income,Mixed assets
BlackRock,1,17,0,0
Fidelity,13,2,0,0
SSgA,12,0,0,0
Hang Seng,11,0,0,0
UBS,9,0,0,1
Schroders,6,0,2,1
JP Morgan,5,2,0,1
Value Partners,1,0,6,0
First State,5,0,0,0
Invesco,4,1,0,0
HSBC,1,1,1,1
DBS,0,2,1,0
BOCI,1,1,1,0
CSOP,0,2,1,0
Principal,1,1,0,0
Allianz,2,1,0,0
Yuanta,0,2,1,0
Manulife,1,0,1,0
Aberdeen,2,0,0,0
Mirae,1,1,0,0
,0,0,0,0`;
const data = d3.csvParse(csvData, function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
});
data.sort(function(a, b) {
return b.total - a.total;
});
var margins = {
top: 20,
bottom: 300,
left: 30,
right: 100
};
var height = 600;
var width = 900;
var totalWidth = width + margins.left + margins.right;
var totalHeight = height + margins.top + margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(250,250)");
var x = d3.scaleBand()
.range([0, 2 * Math.PI])
.align(0);
var y = d3.scaleRadial()
.range([innerRadius, outerRadius]);
var z = d3.scaleOrdinal()
.range(["#003366", "#4f81b9", "#95b3d7", "#f6d18b"]);
x.domain(data.map(function(d) {
return d.State;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
}) * 1.3]);
z.domain(data.columns.slice(1));
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc2")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius + 2)
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .90;
})
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class', 'bg-arc2')
.attr('fill', 'none')
.attr('stroke-width', '4px')
.attr('stroke', '#003366');
graphGroup.append('circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 200)
.style('fill', '#d9d9d9');
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .95;
})
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class', 'bg-arc')
.attr('fill', '#fff');
graphGroup.append('circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', innerRadius)
.style('fill', '#fff');
var stackedData = d3.stack()
.keys(data.columns.slice(1))
(data);
graphGroup.append("g")
.selectAll("g")
.data(stackedData)
.enter().append("g")
.attr("fill", function(d) {
return z(d.key);
})
.selectAll("path")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(function(d) {
return y(d[0]);
})
.outerRadius(function(d) {
return y(d[1]);
})
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .95;
})
.padAngle(0.04)
.padRadius(innerRadius));
var label = graphGroup.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + ((x(d.State) + x.bandwidth() / 2) * 180 / Math.PI - 90) + ")translate(" + (outerRadius + 25) + ",0)";
});
label.append("text")
.attr("transform", function(d) {
return (x(d.State) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)";
})
.text(function(d) {
return d.State;
});
var yAxis = graphGroup.append("g")
.attr("text-anchor", "end");
var yTick = yAxis
.selectAll("g")
.data(y.ticks(10).slice(1))
.enter().append("g");
function weave(array, compare) {
var i = -1,
j, n = array.sort(compare).length,
weave = new Array(n);
while (++i < n) weave[i] = array[(j = i << 1) >= n ? (n - i << 1) - 1 : j];
while (--n >= 0) array[n] = weave[n];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
推荐阅读
- java - 从现有数据库生成 Angular 5 和 Spring mvc CRUD 应用程序
- c++ - 为什么移动 std::optional 不会重置状态
- c++ - 无法在 Visual Studio Community 2017 v.15.7.6 中打开文本文件 - 尝试了一切
- java - 如何查看在 Spring boot 中使用 Cassandra 时生成的 CQL
- arrays - 将数组从 React 客户端传递到 MongoDB
- neo4j - 合并从 CSV 中的两个 geohash 列创建的节点
- python - 存在的键上的 Python3 键错误?
- crystal-reports - Crystal Reports - 将带有变量的查询下推到服务器
- javascript - SVG 点击和切换
- python - Boost.Python 因静态库而失败