Javascript d3.js-根据其中一个序列的值对两个序列进行排序

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

我有两个从CSV文件加载的系列。我想按其中一个的y值在x轴上订购两个系列,但我的订购程序不起作用。有人知道如何订购这些系列吗

<!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
属性将一起排序。因此,我们必须