【发布时间】:2020-04-22 14:21:26
【问题描述】:
Vistas 在github 上有一个很好的示例,其中包含有关如何在 dc.js 中制作瀑布的设置。它使用第二个数据集来实际创建堆叠条形图的底部。但是,如果您在第一个数据集中进行过滤,它将无法正常工作,因为堆叠图表的底部值是固定的。
因此,我的问题是是否可以根据此公式计算 d.value,因此不需要第二个数据集(dummy_data):
Dummy value of current column = previous dummy value + previous real data value
其中第一列和最后一列的值设置为 0
代码
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0' name='viewport'>
<title>Waterfall Chart with DC.js</title>
<script src='js/d3.js' type='text/javascript'></script>
<script src='js/crossfilter.js' type='text/javascript'></script>
<script src='js/reductio.js' type='text/javascript'></script>
<script src='js/dc.js' type='text/javascript'></script>
<link href='css/dc.css' rel='stylesheet' type='text/css'>
</head>
<body>
<div class='pie-graph span6' id='dc-waterfall-chart'></div>
<script>
var waterfallChart = dc.barChart("#dc-waterfall-chart");
var original_data = [];
var dummy_data = [];
//creating example data - could easily be any data reading process from sources like CSV or JSON
original_data.push({item: "x0", value: 10});
original_data.push({item: "x1", value: 2});
original_data.push({item: "x2", value: -1});
original_data.push({item: "x3", value: -3});
original_data.push({item: "x4", value: 8});
//creating the dummy data, the invisible columns supporting the waterfall chart.
//This is going to be the first stack whereas the real data (original_data) is the
//second stack
dummy_data.push({item: "x0", value: 0});
dummy_data.push({item: "x1", value: 10});
dummy_data.push({item: "x2", value: 12});
dummy_data.push({item: "x3", value: 11});
dummy_data.push({item: "x4", value: 0});
//creating crossfilter based off of the real data. Again, you can have your own crossfilter creation process here.
var ndx = crossfilter(original_data);
var itemDimension = ndx.dimension(function (d) { return d.item; });
var reducerValue = reductio().count(true).sum(function(d) { return d.value; }).avg(true);
var itemGroup = itemDimension.group();
var grp = reducerValue(itemGroup);
// we should also have a similar cross filter on the dummy data
var ndx_dummy = crossfilter(dummy_data);
var itemDimension_dummy = ndx_dummy.dimension(function (d) { return d.item; });
var reducerValue_dummy = reductio().count(true).sum(function(d) { return d.value; }).avg(true);
var itemGroup_dummy = itemDimension_dummy.group();
var dummy_grp = reducerValue_dummy(itemGroup_dummy);
waterfallChart.width(600)
.height(400)
.margins({top: 5, right: 40, bottom: 80, left: 40})
.dimension(itemDimension)
.group(dummy_grp)
.valueAccessor(function (d) { // specific to reductio
return d.value.sum;
})
.title(function(d){
return (d.key + " (" + d.value.sum+ ")" );
})
.transitionDuration(1000)
.centerBar(false)
.gap(7)
.x(d3.scaleBand())
.xUnits(dc.units.ordinal)
.controlsUseVisibility(true)
.addFilterHandler(function(filters, filter) {return [filter];})
.elasticY(true)
.xAxis().tickFormat(function(v) {return v;});
waterfallChart.stack(grp,"x")
waterfallChart.on("pretransition",function (chart) {
//coloring the bars
chart.selectAll("rect.bar").style("fill", function(d){return "white";});
chart.selectAll("rect.bar").style("stroke", "#ccc");//change the color to white if you want a clean waterfall without dashed boundaries
chart.selectAll("rect.bar").style("stroke-dasharray", "1,0,2,0,1");
// stack._1 is your real data, whereas stack._0 is the dummy data. You want to treat the styling of these stacks differently
chart.selectAll("svg g g.chart-body g.stack._1 rect.bar").style("fill", function(d){console.log(d.data.value.sum);if (d.data.value.sum >0) return '#ff7c19'; else return '#7c7c7c';});
chart.selectAll("svg g g.chart-body g.stack._1 rect.bar").style("stroke", "white");
chart.selectAll("svg g g.chart-body g.stack._1 rect.bar").style("stroke-dasharray", "1");
// chose the color of deselected bars, but only for the real data.
chart.selectAll("svg g g.chart-body g.stack._1 rect.deselected").style("fill", function (d) {return '#ccc';});
chart.selectAll('g.x text').style('fill', '#8e8e8e');
chart.selectAll('g.y text').style('fill', '#777777');
chart.selectAll('g.x text').style('font-size', '10.5px');
chart.selectAll('g.y.axis g.tick line').style("stroke", "#f46542");
chart.selectAll('.domain').style("stroke","#c6c6c6");
chart.selectAll('rect.bar').on("contextmenu",function(d){d3.event.preventDefault();});
});
dc.renderAll();
</script>
</body>
</html>
【问题讨论】:
-
这个例子看起来不错,但它显然只适用于静态数据。这么多年过去了,我仍然不明白为什么有人会使用 dc.js 来制作没有过滤的静态图表。 (或者也许 repo 是在寻求帮助?)看起来应该有更好的解决方案使用假组,希望在下周找到时间。
-
再次感谢您的帮助,非常感谢。事实上,我真的很喜欢 DC.js 与 crossfilter 的结合。但是没有过滤的独立图表可能 d3.js 是更好的解决方案。希望您能再次帮助我进行过滤。
-
嗨,戈登,您是否已经抽出时间来看看这个例子?很抱歉匆忙,但我需要知道这个例子是否可以工作。再次感谢您的帮助。
-
我看了看,我看到了一个可能的解决方案,因为这是accumulation 的一种形式,在某些方面类似于Pareto chart,但我还没有编写任何代码。我还有很多其他的责任,这对我来说只是一个爱好,但我会尽快完成。
-
嗨@KeesdeJager,想知道你是否有机会看看我的回答。您的赏金即将到期。 :-)
标签: dc.js crossfilter