我正在尝试将数据集可视化以查看穿山甲贸易中的主要参与者。我希望每个国家都是y轴上的分类比例的一部分,而x轴是日期,我希望每个交易实例都表示为一个圆圈,x表示它发生的日期,y是该特定国家的位置,r是到目前为止累积的实例数(在我的数据中表示为r)。基本上我的数据是从2010年到2016年,包括导入或导出穿山甲的国家名称,计数(到此日期之前的累积交易实例)和日期(yyyy-mm-dd)。 以下是我的数据的一部分,我将其存储在变量交易中:
[{"date":"2010-10-22","country":"Thailand","rank":4,"count":1},{"date":"2010-10-28","country":"Malaysia","rank":2,"count":1},{"date":"2010-11-8","country":"Thailand","rank":4,"count":2},{"date":"2010-11-18","country":"Nepal","rank":7,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":1},{"date":"2010-11-22","country":"China","rank":5,"count":2},{"date":"2010-11-27","country":"India","rank":1,"count":1},{"date":"2010-11-28","country":"India","rank":1,"count":2},{"date":"2010-11-28","country":"India","rank":1,"count":3},{"date":"2010-11-30","country":"India","rank":1,"count":4},{"date":"2010-12-17","country":"Malaysia","rank":2,"count":2},{"date":"2010-12-22","country":"Vietnam","rank":3,"count":1},{"date":"2011-01-3","country":"Nepal","rank":7,"count":2},{"date":"2011-02-12","country":"Myanmar","rank":8,"count":1},{"date":"2011-02-25","country":"Malaysia","rank":2,"count":3},{"date":"2011-02-26","country":"Malaysia","rank":2,"count":4},{"date":"2011-03-2","country":"South Africa","rank":18,"count":1},{"date":"2011-03-2","country":"Rwanda","rank":35,"count":1},{"date":"2011-03-2","country":"Mozambique","rank":22,"count":1},{"date":"2011-03-2","country":"Kenya","rank":12,"count":1},{"date":"2011-03-3","country":"China","rank":5,"count":3},{"date":"2011-02-21","country":"Vietnam","rank":3,"count":2},{"date":"2011-03-24","country":"Malaysia","rank":2,"count":5},{"date":"2011-04-4","country":"Malaysia","rank":2,"count":6},{"date":"2011-03-25","country":"India","rank":1,"count":5},{"date":"2011-03-26","country":"Malaysia","rank":2,"count":7},{"date":"2011-04-2","country":"Nepal","rank":7,"count":3},{"date":"2011-04-20","country":"Thailand","rank":4,"count":3},{"date":"2011-05-11","country":"China","rank":5,"count":4},{"date":"2011-05-11","country":"China","rank":5,"count":5},{"date":"2011-05-26","country":"Indonesia","rank":6,"count":1},{"date":"2011-05-26","country":"India","rank":1,"count":6},{"date":"2011-05-29","country":"Indonesia","rank":6,"count":2},{"date":"2011-06-6","country":"India","rank":1,"count":7},{"date":"2011-06-7","country":"Mozambique","rank":22,"count":2},{"date":"2011-06-5","country":"India","rank":1,"count":8},{"date":"2011-06-12","country":"Malaysia","rank":2,"count":8},{"date":"2011-06-13","country":"Singapore","rank":21,"count":1},{"date":"2011-06-14","country":"Malaysia","rank":2,"count":9},{"date":"2011-06-17","country":"India","rank":1,"count":9},{"date":"2011-06-19","country":"India","rank":1,"count":10},{"date":"2011-06-26","country":"Thailand","rank":4,"count":4},{"date":"2011-06-30","country":"India","rank":1,"count":11},{"date":"2011-07-4","country":"Malaysia","rank":2,"count":10},{"date":"2011-07-5","country":"Zimbabwe","rank":14,"count":1},{"date":"2011-07-12","country":"Indonesia","rank":6,"count":3},{"date":"2011-07-18","country":"Indonesia","rank":6,"count":4},{"date":"2011-07-27","country":"Nepal","rank":7,"count":4},{"date":"2011-08-16","country":"Nepal","rank":7,"count":5},{"date":"2011-08-19","country":"Namibia","rank":33,"count":1},{"date":"2011-08-23","country":"India","rank":1,"count":12},{"date":"2010-09-17","country":"Myanmar","rank":8,"count":2},{"date":"2011-09-1","country":"Zimbabwe","rank":14,"count":2},{"date":"2011-09-13","country":"Indonesia","rank":6,"count":5},{"date":"2011-09-13","country":"Malaysia","rank":2,"count":11},{"date":"2011-09-13","country":"Myanmar","rank":8,"count":3},{"date":"2011-09-21","country":"Malaysia","rank":2,"count":12},{"date":"2011-09-26","country":"Thailand","rank":4,"count":5},{"date":"2011-09-30","country":"Indonesia","rank":6,"count":6},{"date":"2011-10-1","country":"Sri Lanka","rank":19,"count":1},{"date":"2011-10-6","country":"India","rank":1,"count":13},{"date":"2011-10-7","country":"India","rank":1,"count":14},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":7},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":8},{"date":"2011-10-18","country":"Indonesia","rank":6,"count":9},{"date":"2011-10-22","country":"India","rank":1,"count":15},{"date":"2011-10-24","country":"India","rank":1,"count":16},{"date":"2011-11-28","country":"United States","rank":32,"count":1},{"date":"2011-12-15","country":"Vietnam","rank":3,"count":3},{"date":"2011-12-27","country":"Thailand","rank":4,"count":6},{"date":"2012-01-4","country":"Philippines","rank":15,"count":1},{"date":"2012-01-5","country":"Kenya","rank":12,"count":2},{"date":"2012-01-6","country":"Philippines","rank":15,"count":2},{"date":"2012-01-17","country":"Philippines","rank":15,"count":3},{"date":"2012-01-24","country":"China","rank":5,"count":6},{"date":"2012-02-22","country":"Malaysia","rank":2,"count":13},{"date":"2012-03-1","country":"Malaysia","rank":2,"count":14},{"date":"2012-03-19","country":"Pakistan","rank":11,"count":1},{"date":"2012-03-21","country":"Malaysia","rank":2,"count":15},{"date":"2012-03-23","country":"Vietnam","rank":3,"count":4},{"date":"2012-04-27","country":"Vietnam","rank":3,"count":5},{"date":"2012-04-23","country":"Belgium","rank":31,"count":1},{"date":"2012-06-7","country":"Thailand","rank":4,"count":7},{"date":"2012-06-7","country":"Thailand","rank":4,"count":8}];
这是我的代码:
var margin = {left:120, top:20, right:0, bottom:50};
var width = 1000;
var height = 800;
var data=trade;
var tradeByCountry = d3.nest()
.key(function(d) { return d.country; })
.entries(trade);
console.log(tradeByCountry);
tradeByCountry.forEach(function(country){
country['number']=country.values.length;
console.log(country);
});
var country_colors = ["#393b79","#5254a3", '#6b6ecf', '#9c9ede', '#637939', '#8ca252','#b5cf6b','#cedb9c',
'#8c6d31','#bd9e39','#e7ba52','#e7cb94','#843c39','#ad494a','#d6616b','#e7969c','#7b4173','#a55194',
'#ce6dbd','#de9ed6', '#9467bd', '#c5b0d5','#3182bd', '#6baed6','#17becf','#9edae5','#e6550d','#fd8d3c','#fdae6b',
'#31a354','#74c476','#a1d99b','#d62728','#ff9896','#7f7f7f','#c7c7c7'];
var colors = d3.scale.ordinal()
.domain(d3.range(tradeByCountry.length))
.range(country_colors);
tradeByCountry.sort(function(x, y){
return d3.descending(x.number, y.number);
})
var countriesArray = [];
tradeByCountry.forEach(function(country){
countriesArray.push(country.key);
});
console.log(countriesArray);
var x = d3.time.scale()
.rangeRound([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var timeFormat = d3.time.format("%Y-%m-%d");
x.domain([timeFormat.parse('2010-10-22'),timeFormat.parse('2016-12-30')]);
y.domain(countriesArray);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("date");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "translate(35,-25)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("countries");
svg.selectAll(".dot")
.data(tradeByCountry)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 7)
.attr("cx", function(d) { return 0; })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
svg.selectAll("text.labels")
.data(tradeByCountry)
.enter()
.append("text")
.text(function(d) {return d.key})
.attr("x", 0)
.attr("y", function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("transform", "translate(-120,5)")
.attr("fill",function(d,i) { return colors(i); });
svg.selectAll('.line')
.data(tradeByCountry)
.enter().append('line')
.attr("x1", 0) // x position of the first end of the line
.attr("y1",function(d,i) { return (height/tradeByCountry.length)*i; })
.attr("x2", width) // x position of the second end of the line
.attr("y2", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("stroke",function(d,i) { return colors(i); })
.attr("id", function(d){return d.key});
//PROBLEM HERE!!!!!!!!!!!
var g = svg
.selectAll("g")
.data(tradeByCountry)
.enter().append("g")
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("id", function(d){ return d.count;})
.attr("r", function(d){return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
.style("fill", function(d,i) { return colors(i); });
我在代码的最后部分遇到了麻烦,在那里我无法得到所有的圆圈而不是正确的r,因为我希望随着交易的累积而增加对于一个国家而言,似乎r根据国家而不同:
答案 0 :(得分:1)
有两件事,首先在您的示例中.selectAll("g")
,在您标记为错误的位置拾取轴中的g元素,因此前几个国家/地区未显示其数据。在您的屏幕截图中,情况似乎并非如此,但鉴于您发布的代码,这种情况正在发生,因此我只使用g
类对这些.country
进行了限定。
第二件事,以及造成您特定问题的原因是这一行:
.attr("cy", function(d,i) { return (height/tradeByCountry.length)*i; })
我猜你认为这里的索引变量i
仍然与tradeByCountry数组相关联,它应该在selectAll("g.country").data(tradebyCountry)
之后,但此时我们已经制作了.selectAll(".dot")
上针对每个国家/地区的数据的嵌套选择d.values
,因此i
现在正在索引这些值列表。因此,上面的代码行将获取每个国家/地区的值,并将它们全部垂直分开,始终从顶行开始 - 实际上您希望它们位于同一行,只需按国家/地区分隔。
What you wanted (I = India, M = Malaysia, T = Thailand)
I--- I0 I1 I2
M--- M0M1 M2
T--- T0 T1 T2
What you were getting
I--- I0 M0 T0
M--- M1 I1 T1
T--- I2 T2 M2
事实也隐藏了这一点.attr(" fill")也有同样的错误,所以每行的颜色都是一致的(我使用d.rank
来修复它)。
解决方案1:为了确保值保持在同一条正确的行上,请先使用i
进行嵌套选择,这样它仍然会引用这样的国家/地区,这将使每个g
元素偏移正确的金额:
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
并简单地将cy
设置为零,以添加到此g
元素的所有内容,并且它们都在一条直线上(并在右侧)
问题在这里的完整代码!阶段:
var g = svg
.selectAll("g.country")
.data(tradeByCountry)
.enter().append("g")
.attr("class", "country")
.attr("transform", function(d,i) {
return "translate(0,"+(height/tradeByCountry.length)*i+")";
})
.selectAll(".dot")
.data(function(d) {return d.values;})
.enter().append("circle")
.attr("class", "dot")
.attr("id", function(d){ return d.country+"_"+d.date+"_"+d.count;})
.attr("r", function(d){ return d.count;})
.attr("cx", function(d,i) { console.log (d.date);return (x(timeFormat.parse(d.date))); })
.attr("cy", function(d,i) { return 0; })
.style("fill", function(d,i) { return colors(d.rank); });
http://jsfiddle.net/d4typ567/1/
解决方案2:d3维护嵌套选择的父索引变量(通常表示为ii
)也可以传递到大多数d3 .attr和.style函数中,这样你就可以了改为.attr("cy", function(d,i, ii) { return (height/tradeByCountry.length)*ii; })
,但偏移g元素只有1个操作,而这是针对每个圆圈完成的。请记住对颜色(填充)功能也这样做。