我正在尝试使用类似于此示例的工作,但使用分组条形图:http://bl.ocks.org/mbostock/1667367
我真的不太了解刷牙是如何工作的(我还没有找到任何好的教程),所以我对于出了什么问题感到有些不知所措。我将尝试在下面包含相关的代码。该图表跟踪按天修复损坏的构建的时间,然后按投资组合分组。到目前为止,刷子已创建,用户可以移动并拖动它,但主图表中的条形图被奇怪地重新绘制,x轴根本不会更新。您将给予的任何帮助将不胜感激。谢谢。
// x0 is the time scale on the X axis
var main_x0 = d3.scale.ordinal().rangeRoundBands([0, main_width-275], 0.2);
var mini_x0 = d3.scale.ordinal().rangeRoundBands([0, main_width-275], 0.2);
// x1 is the portfolio scale on the X axis
var main_x1 = d3.scale.ordinal();
var mini_x1 = d3.scale.ordinal();
// Define the X axis
var main_xAxis = d3.svg.axis()
.scale(main_x0)
.tickFormat(dateFormat)
.orient("bottom");
var mini_xAxis = d3.svg.axis()
.scale(mini_x0)
.tickFormat(dateFormat)
.orient("bottom");
绑定数据后......
// define the axis domains
main_x0.domain(data.result.map( function(d) { return d.date; } )
.sort(d3.ascending));
mini_x0.domain(data.result.map( function(d) { return d.date; } )
.sort(d3.ascending));
main_x1.domain(data.result.map( function(d) { return d.portfolio; } )
.sort(d3.ascending))
.rangeRoundBands([0, main_x0.rangeBand() ], 0);
mini_x1.domain(data.result.map( function(d) { return d.portfolio; } )
.sort(d3.ascending))
.rangeRoundBands([0, main_x0.rangeBand() ], 0);
// Create brush for mini graph
var brush = d3.svg.brush()
.x(mini_x0)
.on("brush", brushed);
添加轴等后
// Create the bars
var bar = main.selectAll(".bars")
.data(nested)
.enter().append("g")
.attr("class", function(d) { return d.key + "-group bar"; })
.attr("fill", function(d) { return color(d.key); } );
bar.selectAll("rect").append("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("class", function(d) { return d.portfolio; })
.attr("transform", function(d) { return "translate(" + main_x0(d.date) + ",0)"; })
.attr("width", function(d) { return main_x1.rangeBand(); })
.attr("x", function(d) { return main_x1(d.portfolio); })
.attr("y", function(d) { return main_y(d.buildFixTime); })
.attr("height", function(d) { return main_height - main_y(d.buildFixTime); });
这是刷子功能(尝试几种不同的选项)......
function brushed() {
main_x1.domain(brush.empty() ? mini_x1.domain() : brush.extent());
//main.select("rect")
//.attr("x", function(d) { return d.values; })
//.attr("width", function(d) { return d.values; });
bar.select("rect")
.attr("width", function(d) { return main_x1.rangeBand(); })
.attr("x", function(d) { return main_x1(d.portfolio); });
//.attr("y", function(d) { console.log(d); return main_y(d.buildFixTime); })
//.attr("height", function(d) { return main_height - main_y(d.buildFixTime); });
main.select(".x.axis").call(main_xAxis);
}
答案 0 :(得分:18)
当您的x-scale是序数比例时,问题来自于尝试使用画笔来设置x-scale域。换句话说,x轴的预期域是一个类别列表,而不是max-min数值范围。所以问题就在刷牙功能的顶部:
function brushed() {
main_x0.domain(brush.empty() ? mini_x0.domain() : brush.extent());
brush.extent()
设置的域名是两个数字的数组,然后完全抛弃你的序数。
According to the wiki,如果附加到画笔函数的其中一个音阶是序数音阶,则brush.extent()
返回的值是输出范围中的值,而不是输入域中的值。 Ordinal scales don't have an invert()
method将范围值转换为域值。
因此,您有一些选择如何继续:
您可以使用主x轴的线性时间刻度而不是序数刻度来重新绘制整个图形。但是你必须编写自己的函数来计算该轴上每天的宽度,而不是能够使用.rangeBand()
。
您可以创建自己的“反转”功能,以确定mini_x0.domain
返回的范围中包含哪些分类值(brush.extent()
上的日期)。然后你必须两个重置main_x0.domain
以仅在轴上包含那些日期,和过滤掉你的矩形以仅绘制那些矩形。
或您可以保留main_x0.
的域,并改为更改范围。通过使图形的范围更大,可以使条形更大。结合剪切路径来切断绘图区域外的条形图,这样做的效果是只显示某个条形子集,无论如何都是这样。
但新范围应该是什么? brush.extent()
返回的范围是刷牙矩形的起始位置和结束位置。如果您将这些值用作主图上的范围,则整个图形将被压缩到该宽度。这与你想要的相反。您想要的是图形区域最初填充要拉伸的宽度以填充整个绘图区域。
因此,如果您的原始x范围是[0,100],并且画笔覆盖了区域[20,60],那么您需要一个满足这些条件的新范围:
因此,
现在你可以做所有的代数来自己搞清楚这个转换。但这实际上只是另一种缩放方程式,所以为什么不创建一个 new 缩放函数来在旧范围和放大范围之间进行转换。
具体来说,我们需要一个线性比例,其输出范围设置为绘图区域的实际范围。然后根据我们想要拉伸的拉丝区域的范围设置域以覆盖绘图区域。最后,我们通过使用线性比例来计算出序数比例的范围,以计算出距离屏幕原始最大值和最小值的距离。从那里,我们可以调整其他顺序尺度并重新定位所有矩形。
在代码中:
//Initialization:
var main_xZoom = d3.scale.linear()
.range([0, main_width - 275])
.domain([0, main_width - 275]);
//Brushing function:
function brushed() {
var originalRange = main_xZoom.range();
main_xZoom.domain(brush.empty() ?
originalRange:
brush.extent() );
main_x0.rangeRoundBands( [
main_xZoom(originalRange[0]),
main_xZoom(originalRange[1])
], 0.2);
main_x1.rangeRoundBands([0, main_x0.rangeBand()], 0);
bar.selectAll("rect")
.attr("transform", function (d) {
return "translate(" + main_x0(d.date) + ",0)";
})
.attr("width", function (d) {
return main_x1.rangeBand();
})
.attr("x", function (d) {
return main_x1(d.portfolio);
});
main.select("g.x.axis").call(main_xAxis);
}
根据您的简化代码工作小提琴(注意:您仍然需要在主图上设置剪裁矩形):
http://fiddle.jshell.net/CjaD3/1/