gpt4 book ai didi

dc.js 动态瀑布图

转载 作者:行者123 更新时间:2023-12-04 10:10:12 25 4
gpt4 key购买 nike

Vistas 在 github 上有一个很好的例子关于如何在 dc.js 中制作瀑布的设置。它使用第二个数据集来实际创建堆积条形图的底部。但是,如果您在第一个数据集中进行过滤,它将无法正常工作,因为堆叠图表的底部值是固定的。

因此,我的问题是是否可以根据此公式计算 d.value,因此不需要第二个数据集 (dummy_data):

Dummy value of current column = previous dummy value + previous real data value

其中第一列和最后一列的值设置为 0

JSFiddle

代码
<!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>

最佳答案

我们可以使用 fake group以基线和最终值所需的方式累积值:

  function waterfall_group(group, endkey, acc) {
acc = acc || (x => x);
return {
all: () => {
let cumulate = 0;
let all = group.all().map(({key,value}) => {
value = acc(value)
const kv = {
key,
value: {
baseline: cumulate,
data: value
}
};
cumulate += value;
return kv;
});
return all.concat([{key: endkey, value: {baseline: 0, data: cumulate}}]);
}
};
}

此函数采用最终“总和”条的键和一个访问器函数,这里需要它,因为reductio 将值包装在一个额外的对象中。

它返回一组值 {baseline,data} ,其中 baseline是不可见堆栈所需的虚拟值, data是条形的值。

构建假组像
var waterfall_group = waterfall_group(grp, 'x5', x => x.sum);

并将其传递给 .group().stack()使用访问器获取子值:
waterfallChart
.group(waterfall_group, 'baseline', kv => kv.value.baseline)
.stack(waterfall_group, 'data', kv => kv.value.data)

我还更改了着色代码以获取新的数据格式:
chart.selectAll("svg g g.chart-body g.stack._1 rect.bar")
.style("fill", function(d){if (d.data.value.data >0) return '#ff7c19'; else return '#7c7c7c';});

为了测试它,我添加了另一个“类别”字段和一个饼图。请注意,瀑布图可能会进入一些带有负值和零值的奇怪状态(例如单击“C”),但它们看起来是正确的。

waterfall shot

Fork of your fiddle .

请注意,由于最后一项(此处为 x5)纯粹是合成的,并且与任何基础数据无关,因此通过单击该项目进行过滤将导致其他图表空白。我不确定如何禁用对某个特定项目的点击。

关于dc.js 动态瀑布图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61367480/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com