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;
        }

(calculateAxisScale source)

在每次渲染和重绘之前(间接)调用此代码。

这里有一些针对 elasticXelasticY 未完全满足您的要求的通用建议。我从未见过它失败! (这是在像 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;

不错!

fiddle

等等,条形图看起来是不是从图表的左侧延伸出来了?

使用 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 的宽度。

fiddle

太棒了!但是最后一个酒吧在哪里?嗯,我们取了前十个值作为最小值和最大值,所以第十个柱是最小值。

您必须找出适合自己的方法,但我发现查看前 20 个值后,前 10 个值的大小还不错:

var N = 20;
var topN = thischart.group().top(N);
var max = topN[0].value;
var min = topN[N-1].value;

final fiddle

这个 hack 不能很好地处理内置的过渡,所以我为这个图表关闭了它们:

chart.transitionDuration(0)

破解那部分需要做更多的工作,fix it in the chart itself