dcjs 动态缩放以适应值的范围
dcjs dynamic zooming to fit range of values
我在 DCjs 中有一个行图,它绘制了给定参数的前 N 个值。但是,对于未过滤的数据,它们之间的差异非常小。
我不得不用它的唯一标识符标记每一行,因为我的随机生成器产生了两个相同的名称,这意味着如果我使用名称作为维度,我最终会得到一万个具有值的数据点之一大于 100%。
然而,这里的主要问题是每行之间的差异很小,可以在 0.0001 左右。
但是,如果我使用
放大 x 轴的那部分
var max = dim.top[1][0].value;
var min = dim.top(10)[9].value;
chart
.dimension(dim)
.group(group)
.x(d3.scaleLinear()
.range([-100, chart.width()])
.domain([min-(max-min)*0.1,max])
)
.cap(10)
.othersGrouper(null)
.colors(['#ff0000']);
首先我松开左边的ID标签。其次,因为我还必须使用 .elasticX(false) 来进行缩放,这意味着当我添加过滤器时,x 轴的范围不会随着值的变化而变化,例如
有没有办法实现动态缩放,使 x 轴的范围取决于所显示值的范围?
elasticX
是一个非常简单的功能,它几乎可以完成您的代码所做的工作,尽管它根据数据是正数还是负数将最小值或最大值锁定为零:
var extent = d3.extent(_rowData, _chart.cappedValueAccessor);
if (extent[0] > 0) {
extent[0] = 0;
}
if (extent[1] < 0) {
extent[1] = 0;
}
在每次渲染和重绘之前(间接)调用此代码。
这里有一些针对 elasticX
或 elasticY
未完全满足您的要求的通用建议。我从未见过它失败! (这是在像 dc.js 这样古怪的代码库中说了些什么。)
首先,禁用elasticX
。然后创建一个计算 X 域并设置它的函数:
function custom_elastic(chart) {
var max = chart.dimension().top[1][0].value;
var min = chart.dimension().top(10)[9].value;
chart.x().domain([min,max]);
}
为了通用性,我在图表上对其进行了参数化。
现在我们可以在 preRender and preRedraw events 上调用这个函数了。这些事件在触发时将通过图表:
chart.on('preRender', custom_elastic)
.on('preRedraw', custom_elastic);
应该就可以了!
顺便说一句,您可能不想设置比例范围 - 这是由图表自动设置的,它比您设置的要复杂一点,因为它考虑了边距。
调试最小值和最大值
看着 your fiddle 我意识到我没有再看一下你是如何计算最小值和最大值的。
我也没有注意到你的范围从 -100 开始。
记录它的第一步很好;它报告
min: 0.81, max: 0.82
这是不正确的。前十名是从0.96到1.
问题在于维度的键是 id
,因此 .top()
返回的行按字母顺序倒序排列("largest" 字符串)。
你又走在了正确的轨道上
console.log(Group.top(Infinity))
是的!该小组将按价值为您提供前 10 名。
var top10 = thischart.group().top(10);
var max = top10[0].value;
var min = top10[9].value;
不错!
等等,条形图看起来是不是从图表的左侧延伸出来了?
使用 renderlet 破解行图以从左边缘开始绘制条形图
好吧,很明显,行图不支持这个。这是将条形调整到左边缘的技巧:
chart.on('renderlet', function(chart) {
var transform = chart.select('g.row rect').attr('transform');
var tx = +transform.split('(')[1].split(',')[0];
chart.selectAll('g.row rect')
.attr('transform', null)
.attr('width', function(d) {
return +d3.select(this).attr('width') + tx;
})
chart.selectAll('g.row text.row')
.attr('transform', null);
})
所有的行矩形都将被一个大的负数抵消,我们在 tx
中首先获取它。然后我们从 rects 和文本中删除 transform
,并将 tx
添加到行 rects 的宽度。
太棒了!但是最后一个酒吧在哪里?嗯,我们取了前十个值作为最小值和最大值,所以第十个柱是最小值。
您必须找出适合自己的方法,但我发现查看前 20 个值后,前 10 个值的大小还不错:
var N = 20;
var topN = thischart.group().top(N);
var max = topN[0].value;
var min = topN[N-1].value;
这个 hack 不能很好地处理内置的过渡,所以我为这个图表关闭了它们:
chart.transitionDuration(0)
破解那部分需要做更多的工作,fix it in the chart itself。
我在 DCjs 中有一个行图,它绘制了给定参数的前 N 个值。但是,对于未过滤的数据,它们之间的差异非常小。
我不得不用它的唯一标识符标记每一行,因为我的随机生成器产生了两个相同的名称,这意味着如果我使用名称作为维度,我最终会得到一万个具有值的数据点之一大于 100%。
然而,这里的主要问题是每行之间的差异很小,可以在 0.0001 左右。
但是,如果我使用
放大 x 轴的那部分var max = dim.top[1][0].value;
var min = dim.top(10)[9].value;
chart
.dimension(dim)
.group(group)
.x(d3.scaleLinear()
.range([-100, chart.width()])
.domain([min-(max-min)*0.1,max])
)
.cap(10)
.othersGrouper(null)
.colors(['#ff0000']);
首先我松开左边的ID标签。其次,因为我还必须使用 .elasticX(false) 来进行缩放,这意味着当我添加过滤器时,x 轴的范围不会随着值的变化而变化,例如
有没有办法实现动态缩放,使 x 轴的范围取决于所显示值的范围?
elasticX
是一个非常简单的功能,它几乎可以完成您的代码所做的工作,尽管它根据数据是正数还是负数将最小值或最大值锁定为零:
var extent = d3.extent(_rowData, _chart.cappedValueAccessor);
if (extent[0] > 0) {
extent[0] = 0;
}
if (extent[1] < 0) {
extent[1] = 0;
}
在每次渲染和重绘之前(间接)调用此代码。
这里有一些针对 elasticX
或 elasticY
未完全满足您的要求的通用建议。我从未见过它失败! (这是在像 dc.js 这样古怪的代码库中说了些什么。)
首先,禁用elasticX
。然后创建一个计算 X 域并设置它的函数:
function custom_elastic(chart) {
var max = chart.dimension().top[1][0].value;
var min = chart.dimension().top(10)[9].value;
chart.x().domain([min,max]);
}
为了通用性,我在图表上对其进行了参数化。
现在我们可以在 preRender and preRedraw events 上调用这个函数了。这些事件在触发时将通过图表:
chart.on('preRender', custom_elastic)
.on('preRedraw', custom_elastic);
应该就可以了!
顺便说一句,您可能不想设置比例范围 - 这是由图表自动设置的,它比您设置的要复杂一点,因为它考虑了边距。
调试最小值和最大值
看着 your fiddle 我意识到我没有再看一下你是如何计算最小值和最大值的。
我也没有注意到你的范围从 -100 开始。
记录它的第一步很好;它报告
min: 0.81, max: 0.82
这是不正确的。前十名是从0.96到1.
问题在于维度的键是 id
,因此 .top()
返回的行按字母顺序倒序排列("largest" 字符串)。
console.log(Group.top(Infinity))
是的!该小组将按价值为您提供前 10 名。
var top10 = thischart.group().top(10);
var max = top10[0].value;
var min = top10[9].value;
不错!
等等,条形图看起来是不是从图表的左侧延伸出来了?
使用 renderlet 破解行图以从左边缘开始绘制条形图
好吧,很明显,行图不支持这个。这是将条形调整到左边缘的技巧:
chart.on('renderlet', function(chart) {
var transform = chart.select('g.row rect').attr('transform');
var tx = +transform.split('(')[1].split(',')[0];
chart.selectAll('g.row rect')
.attr('transform', null)
.attr('width', function(d) {
return +d3.select(this).attr('width') + tx;
})
chart.selectAll('g.row text.row')
.attr('transform', null);
})
所有的行矩形都将被一个大的负数抵消,我们在 tx
中首先获取它。然后我们从 rects 和文本中删除 transform
,并将 tx
添加到行 rects 的宽度。
太棒了!但是最后一个酒吧在哪里?嗯,我们取了前十个值作为最小值和最大值,所以第十个柱是最小值。
您必须找出适合自己的方法,但我发现查看前 20 个值后,前 10 个值的大小还不错:
var N = 20;
var topN = thischart.group().top(N);
var max = topN[0].value;
var min = topN[N-1].value;
这个 hack 不能很好地处理内置的过渡,所以我为这个图表关闭了它们:
chart.transitionDuration(0)
破解那部分需要做更多的工作,fix it in the chart itself。