我正在尝试创建一个类似的分组条形图,如下例所示:http://bl.ocks.org/mbostock/3887051 我的数据是来自MongoDB的JSON,我无法访问某些嵌套数据.我希望图表在Y轴上由buildFixTime设置,并且X轴是按时间排列的,并且条形图按"组"分组.这是一个示例记录:
{ "result" : [ { "_id" : { "month" : 1, "day" : 22, "year" : 2014, "group" : "Sales" }, "buildFixTime" : 3710497 }, { "_id" : { "month" : 1, "day" : 23, "year" : 2014, "group" : "Sales" }, "buildFixTime" : 79209205 }, { "_id" : { "month" : 1, "day" : 24, "year" : 2014, "group" : "Sales" }, "buildFixTime" : 35611663.4 }, { "_id" : { "month" : 1, "day" : 24, "year" : 2014, "group" : "Service" }, "buildFixTime" : 18273221.333333332 } ], "ok" : 1 }
加载JSON文件后,我有以下代码(不包括不重要的位):
// This adds new elements to the data object data.result.forEach(function(d) { d.group = d._id.group; d.date = new Date(d._id.year, d._id.month-1, d._id.day); }); // define the axis domains main_x0.domain(d3.extent(data.result, function(d) { return d.date; })); main_x1.domain(d3.ascending(data.result, function(d) { return d.group; } )); main_y.domain(d3.extent(data.result, function(d) { return (d.buildFixTime / 1000) / 60 / 60 + 2 ; })); // flatten out the data var nested = d3.nest() .key(function(d) { return d._id.group; }) .entries(data.result);
添加轴线等后,我有这个块,这就是问题所在.我认为我需要能够在转换/转换行中访问日期,但我不知道如何实现它 - 我应该创建另一个D3嵌套对象来进一步展平数据吗?谢谢您的帮助!
var bar = main.selectAll(".bars") .data(nested) .enter().append("g") .attr("class", "g") // This seems to be where part of my problem is .attr("transform", function(d) { console.log(d); return "translate(" + main_x0(d.values.date) + ",0)"; }); bar.selectAll("rect").append("rect") .data(function(d) { return d.values; }) .enter().append("rect") .attr("transform", function(d) { console.log(d.date); return "translate(" + main_x0(d.date) + ",0)"; }) .attr("width", main_x1.rangeBand()) .attr("x", function(d) { return main_x1(d.date); }) .attr("y", function(d) { return main_y(d.buildFixTime); }) .attr("height", function(d) { return main_height - main_y(d.buildFixTime); }) .style("fill", function(d) { return color(d.key); });
AmeliaBR.. 6
你似乎对你的两个x刻度,每个人做什么以及何时使用它们有点困惑.
使用链接示例中的变量名称,x0比例将页面上不同的条形簇空间隔开.
我并不完全清楚你的意思是"我想让X轴按时间排列,并且条形按'组'分组."我假设你希望每个月的所有"组"聚集在一起在一起,整个页面分布着不同的月份.如果您希望将每个"组"的所有日期聚集在一起,那么x0的域应该是您的组,而不是您的日期,并且您将不得不调整本讨论的其余部分.
因为日期可以被视为连续数字,所以您可以使用线性比例; 通过传入数据extent
(即最大值和最小值)而不是所有可能值的排序列表,这似乎就是您正在做的事情.但是,线性刻度并不是一种简单的方法来告诉您每个数据点之间有多少空间,我们需要这些空间来定位和调整条形.因此,为了使一切变得更容易,请将其设置为序数,并将其域设置为已排序的日期.
该X1尺度空间的各个条集群内,相对于该群集的起始位置.因此,域名是您希望在每个月列出的"群组".
看起来你没有设定这个比例的范围.x1比例的范围是每个聚类可用的宽度,由x0比例的带宽决定:如果你有很多聚类,每个聚类将更窄,所以单个条也必须更窄.
因此,您的轴设置将是(假设群集之间填充20%,并且各个条之间没有填充):
// initialization main_x0 = d3.scale.ordinal().rangeRoundBands([0, main_width], 0.2); main_x1 = d3.scale.ordinal(); main_y = d3.scale.linear().range([main_height, 0] ); // once you have the data main_x0.domain(data.result.map( function(d) { return d.date; } ) .sort(d3.ascending) ); main_x1.domain(data.result.map( function(d) { return d.group; } ) .sort(d3.ascending) ) .rangeRoundBands([0, main_x0.rangeBand() ], 0); main_y.domain(d3.extent(data.result, function(d) { return d.buildFixTime ; }));
(PS我不知道为什么你的y范围域上有各种各样的转换公式.你只buildFixTime
在绘制数据时使用raw ,这就是你想要的域.从毫秒到小时的转换应该是在你的tickFormat
功能中完成.)
然后,在您的图表方法中,您需要记住这main_x0
是您的日期 - 群集比例,而main_x1
您是每个日期比例范围内的组.每个条的水平位置通过首先将其移动到簇的开始然后再将其移动到该组在簇内的位置来确定.应用于日期的x0比例为您提供第一个班次,而应用于该组的x1比例则为您提供第二个班次.
换句话说,如果你想要这样的布局:
abcde abcde abcde abcde Jan. Feb. Mar. Apr. * >>>>|
然后要找到2月类别"e"的位置,您需要x0(2月)+ x1(e).第一个为您提供二月集群的开始(标记*
),第二个为您提供额外的班次以进入类别e(标记为>
).
您的数据嵌套在"group"中.因此,每个
元素都包含特定类别中的所有条形:所有a
s在一个中,所有b
s在另一个中.虽然您可以对
元素使用转换来根据组在每个群集中需要的移位来移动每个组的起点,但我认为这会使事情变得复杂.正如Lars所说,你可以在定位单个酒吧时完成所有工作.
所以你的代码看起来像:
var bar = main.selectAll(".bars") .data(nested) .enter().append("g") .attr("class", function(d){return d.key;}) //add a useful class based on the data //d.key is the value used to create the nested array //i.e., the group value for all the bars in the.style("fill", function(d) { return color(d.key); }); //Set the style here and it will be inherited by the bars //in the group. If you set it on the individual rectangles, //you will need to use d.group (the data property), //not d.key (the property created by the nest method) bar.selectAll("rect").append("rect") .data(function(d) { return d.values; }) //the nested sub-array for each group .enter().append("rect") .attr("transform", function(d) { return "translate(" + main_x0(d.date) + ",0)"; }) .attr("x", function(d) { return main_x1(d.group); }) //by using both a transform and an x-position, the two scales //are kept separate. But make sure that you pass in the correct //data variable for each scale! .attr("width", main_x1.rangeBand()) //the width is calculated from the x1 scale, which positions //the individual bars within a cluster .attr("y", function(d) { return main_y(d.buildFixTime); }) .attr("height", function(d) { return main_height - main_y(d.buildFixTime); }); //note that these functions are based on a y-scale with an inverted range, //one that goes from [main_height, 0], as I set up above
同样,如果您希望将条形图分组,则必须切换要使用的所有x0缩放函数d.group
,以及要使用的所有x1缩放函数d.date
.