Javascript d3.js-根据其中一个序列的值对两个序列进行排序
我有两个从CSV文件加载的系列。我想按其中一个的y值在x轴上订购两个系列,但我的订购程序不起作用。有人知道如何订购这些系列吗Javascript d3.js-根据其中一个序列的值对两个序列进行排序,javascript,csv,d3.js,Javascript,Csv,D3.js,我有两个从CSV文件加载的系列。我想按其中一个的y值在x轴上订购两个系列,但我的订购程序不起作用。有人知道如何订购这些系列吗 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>D3 Teste Template</title> <script type="text/javascript" src="d3/d
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Teste Template</title>
<script type="text/javascript" src="d3/d3.js"></script>
<style type="text/css">
div.bar {
display: inline-block;
width: 20px;
height: 75px; /* We'll override height later */
background-color: teal;
margin-right: 2px;
}
</style>
</head>
<body>
<p>Click to sort!!</p>
<script type="text/javascript">
var w = 800;
var h = 500;
var padding = 30;
//Define scale
var x = d3.scaleLinear().range([padding, w-padding*2]);
var y = d3.scaleLinear().range([h-padding, padding]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
var xAxis = d3.axisBottom().scale(x).ticks(10);
var yAxis = d3.axisLeft().scale(y).ticks(5);
//Define Canvas
var svg = d3.select("body").append("svg")
.attr("width",w).attr("height", h)
//Define clipping path
svg.append("clipPath").attr("id", "chart-area").append("rect")
.attr("x", padding).attr("y", padding)
.attr("width", w - padding*3).attr("height", h - padding*2);
//Loading CSV
d3.csv("eval_silver_standard.csv", function(error, data){
if (error) throw error;
// Extract yn using key
var seriesNames = d3.keys(data[0])
.filter(function(d) { return d !== "x"; })
.sort();
// Map data to cartesian tuple {x,y}
var series = seriesNames.map(function(series) {
return data.map(function(d) {
return {x: +d.x, y: +d[series]};
});
});
// Compute domains
x.domain(d3.extent(d3.merge(series), function(d) {
return d.x; })).nice();
y.domain(d3.extent(d3.merge(series), function(d) {
return d.y; })).nice();
// X axis.
svg.append("g").attr("class", "axis").attr("transform",
"translate(0," + (h - padding) + ")").call(xAxis)
// Y axis.
svg.append("g").attr("class", "axis").attr("transform",
"translate(" + padding + ",0)").call(yAxis)
// Append circles
svg.selectAll(".series")
.data(series)
.enter().append("g")
.attr("class", "series")
.style("fill", function(d, i) { return z(i); })
.selectAll(".point")
.data(function(d) { return d; })
.enter().append("circle")
.attr("class", "point")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", 4);
//On click, update order
d3.select("p").on("click", function() {
// Order circles
// Code goes here
});
});
</script>
</body>
</html>
我的排序功能没有正常工作,我不知道为什么会这样。好吧,如果你有一个用于在x轴上定位圆的点刻度,这可能会容易得多。因为你有一个线性刻度,我写的函数有一些麻烦的部分 首先:您必须创建一个函数来重新绘制SVG中的元素。在下面的演示中,它被命名为
draw
,我们将series
数组传递给该函数
然而,最重要的部分是排序系列
数组。例如,这是对蓝色圆点进行排序并相应地重新排列橙色圆点的功能:
d3.select("#button1").on("click", function() {
series[0] = series[0].sort(function(a, b) {
return d3.ascending(a.y, b.y)
}).map(function(e, i) {
return {
x: i,
fx: e.fx,
y: e.y,
u: e.u
}
});
series[1].forEach(function(d, i, arr) {
d.x = order0.indexOf(d.fx)
});
draw(series);
});
如您所见,单独排序不起作用,因为x
属性将一起排序。因此,我们必须根据y
进行排序,然后将x
从0重新分配到10
为了保持对象的恒定性,我使用Math.random()
创建了一个名为u
的属性。两个属性具有相同值的可能性很小。但是,我建议您在每个对象中创建自己独特的属性(否则无法保持对象的恒定性)。fx
属性仅用于跟踪原始序列,order0
/order1
是每个序列的有序序列的数组
这是一个演示,使用了大部分代码,但创建了draw
并减小了SVG的大小,以便更好地适应堆栈片段。单击按钮进行排序:
var data=d3.csvParse(d3.select(“#csv”).text());
var w=600;
var h=200;
var=30;
//定义比例
var x=d3.scaleLinear().range([padding,w-padding*2]);
var y=d3.scaleLinear().range([h-填充,填充]);
Varz=d3.scaleOrdinal(d3.schemeCategory10);
var xAxis=d3.axisBottom().scale(x)、ticks(10);
var yAxis=d3.axisLeft().scale(y)、ticks(5);
//定义画布
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,w)。attr(“高度”,h)
//定义裁剪路径
svg.append(“clipPath”).attr(“id”,“图表区”).append(“rect”)
.attr(“x”,填充).attr(“y”,填充)
.attr(“宽度”,w-填充*3)。attr(“高度”,h-填充*2);
//使用密钥提取yn
var seriesNames=d3.keys(数据[0])
.过滤器(功能(d){
返回d!=“x”;
})
.sort();
//将数据映射到笛卡尔元组{x,y}
var series=seriesNames.map(函数(系列){
返回data.map(函数(d,i){
返回{
x:+d.x,
外汇:+d.x,
y:+d[系列],
u:数学随机
};
});
});
var order0=系列[0]。排序(函数(a,b){
返回d3。升序(a.y,b.y)
}).map(功能(e){
返回e.x
});
var order1=系列[1]。排序(函数(a,b){
返回d3。升序(a.y,b.y)
}).map(功能(e){
返回e.x
});
//计算域
x、 域(d3.范围(d3.合并(系列)、函数(d){
返回d.x;
})).nice();
y、 域(d3.范围(d3.合并(系列)、函数(d){
返回d.y;
})).nice();
//X轴。
svg.append(“g”).attr(“class”、“axis”).attr(“transform”,
“translate(0,”+(h-padding)+“))。调用(xAxis)
//Y轴。
svg.append(“g”).attr(“class”、“axis”).attr(“transform”,
“translate(“+padding+”,0)”)。调用(yAxis);
绘画(系列);
函数图(数据){
//附加圆
var groups=svg.selectAll(“.series”)
.数据(数据);
var groupsEnter=groups.enter()
.附加(“g”)
.attr(“类”、“系列”)
.样式(“填充”,功能(d,i){
返回z(i);
});
var circleCenter=groupsEnter.selectAll(“.point”)
.数据(功能(d){
返回d;
},功能(e){
返回欧盟
}).enter().append(“圆”)
.attr(“类”、“点”)
.attr(“cx”,功能(d){
返回x(d.x);
})
.attr(“cy”,函数(d){
返回y(d.y);
})
.attr(“r”,4);
分组。选择全部(“.point”)。数据(函数(d){
返回d;
},功能(e){
返回欧盟
})
.transition()
.持续时间(2500)
.attr(“cx”,功能(d){
返回x(d.x);
})
.attr(“cy”,函数(d){
返回y(d.y);
})
.attr(“r”,4);
}
//单击,更新订单
d3.选择(“#按钮1”)。在(“单击”,函数()上{
系列[0]=系列[0]。排序(函数(a,b){
返回d3。升序(a.y,b.y)
}).map(功能(e,i){
返回{
x:我,
fx:e.fx,
y:e.y,
u:e.u
}
});
系列[1]。forEach(函数(d,i,arr){
d、 x=order0.indexOf(d.fx)
});
绘画(系列);
});
d3.选择(“#按钮2”)。在(“单击”,函数()上{
系列[1]=系列[1]。排序(函数(a,b){
返回d3。升序(a.y,b.y)
}).map(功能(e,i){
返回{
x:我,
fx:e.fx,
y:e.y,
u:e.u
}
});
系列[0]。forEach(函数(d,i,arr){
d、 x=order1.indexOf(d.fx)
});
绘画(系列);
});代码>
pre{
显示:无;
}
钮扣{
右边距:5px;
}
单击按蓝色排序单击按橙色排序
x、 y1,y2
0,0.85337,0.10198
1,0,0.30274
2,0.85311,0.08623
3,0.82759,0.08711
4,0.89602,0.03472
5,0.8,0.16295
6,0,0.27028
7,0.76167,0.2155
8,0.75,0.08359
9,0.81775,0.16535
10,0,0.2311
好吧,如果你有一个在x轴上定位圆的点刻度,这可能会更容易。因为你有一个线性刻度,我写的函数有一些麻烦的部分
首先:您必须创建一个函数来重新绘制SVG中的元素。在下面的演示中,它被命名为draw
,我们将series
数组传递给该函数
然而,最重要的部分是排序系列
数组。例如,这是对蓝色圆点进行排序并相应地重新排列橙色圆点的功能:
d3.select("#button1").on("click", function() {
series[0] = series[0].sort(function(a, b) {
return d3.ascending(a.y, b.y)
}).map(function(e, i) {
return {
x: i,
fx: e.fx,
y: e.y,
u: e.u
}
});
series[1].forEach(function(d, i, arr) {
d.x = order0.indexOf(d.fx)
});
draw(series);
});
如您所见,单独排序不起作用,因为x
属性将一起排序。因此,我们必须