- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在过去的几周里,我在尝试创建一个简单的个人仪表板时经常使用 dc.js。
我成功地实现了一个弹出菜单来选择我想要用于对折线图的时间维度进行分组的时间粒度,并且感谢社区的帮助,我成功地大幅提高了性能。
现在我正在尝试动态更改对分组数据执行的聚合类型(总和、平均值、众数、最小值和最大值)。
我找到了这个example非常有帮助,但是,尽管如此,我并没有完全适应我的情况,也没有设法让它发挥作用。根据我的理解,在这种情况下,我只需要更改值访问器函数,然后重新绘制即可。事实上,valueAccessor 确定 y 轴像素位置,因此这是它应该更改的唯一部分。相反,当我处理组聚合中的更改时,我必须使用新分组重新设置整个图表...
现在这是我的代码,任何单选按钮位置都不会打印任何内容(仅实现了 sum 和 svg)。
如果我删除动态 valueAccessor 部分,默认的“sum”选择将正常工作。
这是代码:
// Disable it or dash_reduceAvgAdd will give an error with ++p!
//'use strict';
// TODO temp dirty workaround
var selectedAggr = 'sum';
// ### Create Chart Objects
// Create chart objects associated with the container elements identified by the css selector.
// Note: It is often a good idea to have these objects accessible at the global scope so that they can be modified or
// filtered by other page controls.
var stackChart = dc.lineChart("#stack-chart");
var volumeChart = dc.barChart('#volume-chart');
// Asynchronously load the data and only when finished build the charts
queue()
.defer(d3.json, "/data")
.await(makeGraphs);
// Function to elaborate the data and build the charts
function makeGraphs(error, recordsJson) {
// Clean data
var records = recordsJson;
// Works on d3-v4 only: var dateFormat = d3.timeFormat("%Y-%m-%d %H:%M:%S");
//var dateFormat = d3.time.format("%Y-%m-%d %H:%M");
console.log(Object.prototype.toString.call(records[0].date));
// Coerce values to number and create javascript Date objects
records.forEach(function(d) {
d.date = new Date(+d.date);
d.prodPow = +d.prodPow;
d.consPow = +d.consPow;
});
// Crossfilter instance
var ndx = crossfilter(records);
// Aggregation functions
// SUM mode
//function reduceAdd(attr) { return reduceSum(function (d) { return d[attr]; }); }
function dash_reduceSumAdd(attr) { return function (p, v) { return p + +v[attr]; }; }
function dash_reduceSumSub(attr) { return function (p, v) { return p - v[attr]; }; }
function dash_reduceInit() { return 0; }
// AVG mode
function dash_reduceAvgAdd(attr) {
return function (p, v) {
++p.count;
p.sum += v[attr];
p.avg = p.sum/p.count;
return p;
};
}
function dash_reduceAvgSub(attr) {
return function (p, v) {
--p.count;
p.sum -= v[attr];
p.avg = p.count ? p.sum / p.count : 0;
return p;
}
}
function dash_reduceAvgInit() {
return function () {
return {count:0, sum:0, avg:0};
}
}
function valAccSum(d) {
return d.value;
}
function valAccAvg(d) {
return d.value.avg;
}
// Map selector to correct map-reduce functions
var aggregators = {
sum: [dash_reduceSumAdd, dash_reduceSumSub, dash_reduceInit, valAccSum],
avg: [dash_reduceAvgAdd, dash_reduceAvgSub, dash_reduceAvgInit, valAccAvg]//,
//mode: reduceMode,
//min: reduceMin,
//max: reduceMax
};
// Granularities selectable values
var granularities = {
Hours: [d3.time.hour, d3.time.hours],
Days: [d3.time.day, d3.time.days],
Weeks: [d3.time.week, d3.time.weeks],
Months: [d3.time.month, d3.time.months],
Years: [d3.time.year, d3.time.years]
};
// Assign default granularity
d3.select('#granularity').selectAll('option')
.data(Object.keys(granularities))
.enter().append('option')
.text(function(d) { return d; })
.attr('selected', function(d) { return d === 'Days' ? '' : null; });
var dateDim, consPowByHour, prodPowByHour;
// Function to build the charts from the selected granularity
function setup(aggr) {
if (dateDim) {
dateDim.dispose();
consPowByHour.dispose();
prodPowByHour.dispose();
}
var gran = granularities[d3.select('#granularity')[0][0].value];
dateDim = ndx.dimension(function (d) { return gran[0](d.date); });
consPowByHour =
dateDim
.group(function (d) { return gran[0](d); })
.reduce(aggregators[aggr][0]('consPow'), aggregators[aggr][1]('consPow'), aggregators[aggr][2]);
//consPowByHour = dateDim.group(function (d) { return granularity[0](d); }).reduceSum();
prodPowByHour =
dateDim
.group(function (d) { return gran[0](d); })
.reduce(aggregators[aggr][0]('prodPow'), aggregators[aggr][1]('prodPow'), aggregators[aggr][2]);
// Min and max dates to be used in the charts
var minDate = gran[0](dateDim.bottom(1)[0]["date"]);
var maxDate = gran[0](dateDim.top(1)[0]["date"]);
// Charts customization
stackChart
.renderArea(true)
/* Make the chart as big as the bootstrap grid by not setting ".width(960)" */
.height(350)
.transitionDuration(1500)
.margins({top: 30, right: 50, bottom: 25, left: 40})
.dimension(dateDim)
/* Grouped data to represent and label to use in the legend */
.group(consPowByHour, "Consumed Power [kW]")
/* Function to access grouped-data values in the chart */
.valueAccessor(aggregators[aggr][2])
/* x-axis range */
.x(d3.time.scale().domain([minDate, maxDate]))
.xUnits(gran[1])
/* Auto-adjust axis */
.elasticY(true)
.renderHorizontalGridLines(true)
.legend(dc.legend().x(80).y(0).itemHeight(13).gap(5))
/* When on, you can't visualize values, when off you can filter data */
.brushOn(false)
/* Add another line to the chart; pass (i) group, (ii) legend label and (iii) value accessor */
.stack(prodPowByHour, "Produced Power [kW]", aggregators[aggr][2])
/* Range chart to link the brush extent of the range with the zoom focus of the current chart. */
.rangeChart(volumeChart)
/* dc.js bug, this should be true by default to turn on visibility for reset class */
.controlsUseVisibility(true)
;
volumeChart//.width(990)
.height(60)
.margins({top: 0, right: 50, bottom: 20, left: 40})
.dimension(dateDim)
.group(consPowByHour)
.centerBar(true)
.gap(1)
.x(d3.time.scale().domain([minDate, maxDate]))
.xUnits(gran[1])
.elasticY(true)
.alwaysUseRounding(true)
/* dc.js bug, this avoids the reset and filter to remain after resetting using the brush/focus */
.on('renderlet', function (chart) {
var rangeFilter = chart.filter();
var focusFilter = chart.focusChart().filter();
if (focusFilter && !rangeFilter) {
dc.events.trigger(function () {
chart.focusChart().replaceFilter(rangeFilter);
});
}
})
;
}
// First time build charts
setup(selectedAggr);
// Render all graphs
dc.renderAll();
// Listen for changes on granularities selection
d3.select('#granularity').on('change', function() {
setup(selectedAggr);
dc.redrawAll();
});
// Listen for changes on aggregation mode selection
d3.selectAll('#select-operation input')
.on('click', function() {
stackChart.valueAccessor(aggregators[this.value][3]);
selectedAggr = this.value;
//setup(this.value);
dc.redrawAll();
});
预先感谢,我真的不知道如何继续,因为我什至没有从控制台收到任何错误。
编辑:为了完成,这是我的 html 代码:
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<link rel="stylesheet" href="./static/css/bootstrap.min.css">
<link rel="stylesheet" href="./static/css/dc.css">
<link rel="stylesheet" href="./static/css/custom.css">
</head>
<body class="application">
<!-- Header bar on top -->
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="./">Dashboard</a>
</div>
</div>
</div>
<!-- Chart container page -->
<div class="container-fluid">
<!-- First row of charts (compensate on the left part the strange padding on right "trbl") -->
<div class="row" style="width:100%; padding: 0px 0px 0px 25px;">
<!-- Control Panel -->
<div class="col-sm-12">
<div class="chart-wrapper control-panel">
<div class="chart-title control-panel">
Control Panel
</div>
<div class="row">
<div class="col-sm-4">
<div class="chart-stage control-panel" style="height: 100px; border-right: 1px solid #e2e2e2;">
<div class="text-center" style="padding: 10px;">
<!--<div class="inner">-->
<strong>Granularity:</strong>
<select id="granularity" style="margin-left: 10px"></select>
<div id="select-operation" style="margin-top: 15px;">
<strong>Aggregation:</strong>
<label><input type=radio name="operation" value="sum" checked="checked" style="margin-left: 10px"> sum</label>
<label><input type=radio name="operation" value="avg"> average</label>
<label><input type=radio name="operation" value="mode"> mode</label>
<label><input type=radio name="operation" value="min"> min</label>
<label><input type=radio name="operation" value="max"> max</label>
</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="chart-stage control-panel" style="height: 100px; border-right: 1px solid #e2e2e2;">
Test
</div>
</div>
<div class="col-sm-4">
<div class="chart-stage control-panel" style="height: 100px;">
Test
</div>
</div>
</div>
</div>
</div>
<!-- Stack Chart and its Range Chart as a single bootstrap grid -->
<div class="col-sm-12">
<div class="chart-wrapper">
<div class="chart-title">
Stack Chart
</div>
<div class="chart-stage">
<!-- Stack Chart -->
<div class="row">
<div id="stack-chart" style="width:100%;">
<a class="reset"
href="javascript:stackChart.filterAll();volumeChart.filterAll();dc.redrawAll();"
style="visibility: hidden; float: right; margin-right: 15px;">
reset chart
</a>
<span class='reset'
style='visibility: hidden; float: right; margin-right: 15px; font-style: italic;'>
Current filter: <span class='filter'></span>
</span>
<div class="clearfix"></div> <!-- Use it when using the reset class for IE -->
</div>
</div>
<!-- Range Chart -->
<div class="row">
<div id="volume-chart" style="width:100%;"></div>
<p class="muted pull-right" style="margin-right: 15px;"><i>select a time range to zoom in</i></p>
</div>
</div>
</div>
</div> <!-- End of "col-sm-12" grid -->
</div> <!-- End of first row -->
</div>
</body>
</html>
最佳答案
我设法解决了有关reduce 函数的主要问题。
解决方案是只使用这些reduce函数:
// Custom reduce functions
function dash_reduceAdd(p, v) {
++p.count;
p.conSum += v.consPow;
p.prodSum += v.prodPow;
p.consAvg = p.conSum/p.count;
p.prodAvg = p.prodSum/p.count;
return p;
}
function dash_reduceSub(p, v) {
--p.count;
p.conSum -= v.consPow;
p.prodSum -= v.prodPow;
p.consAvg = p.count ? p.conSum / p.count : 0;
p.prodAvg = p.count ? p.prodSum / p.count : 0;
return p;
}
function dash_reduceInit() {
return { count:0, conSum:0, prodSum:0, consAvg:0, prodAvg:0 };
}
对“stackChart”和“volumeChart”使用唯一的分组维度。像这样:
powByTime =
dateDim
.group(function (d) { return gran[0](d); })
.reduce(dash_reduceAdd, dash_reduceSub, dash_reduceInit);
在 stackChart 的“构建”内部,消耗和生成的值访问器如下所示:
stackChart.valueAccessor(function(d) { return d.value.conSum; });
还有这个:
stackChart.stack(powByTime, "Produced Power [kW]", function(d) { return d.value.prodSum; })
最后只需在 valueAccessor 中进行选择,如下所示:
// Map the selected mode to the correct valueAccessor value
var accessors = {
sum: {consPow: 'conSum', prodPow: 'prodSum'},
avg: {consPow: 'consAvg', prodPow: 'prodAvg'}
};
// Listen for changes on the aggregation mode and update the valueAccessor
d3.selectAll('#select-operation input')
.on('click', function() {
var aggrMode = this.value;
stackChart.valueAccessor(function(d) { var sel = accessors[aggrMode]['consPow']; return d.value[sel]; });
dc.redrawAll();
});
现在这适用于我提出的问题,但如果您重复使用它(这就是我发布解决方案的原因),请注意这会引入其他问题:
我还不知道如何解决它们,如果我能解决,我会打开另一个线程以防万一,或者在将来发布完整的解决方案。希望这可以帮助其他人。
关于javascript - dc.js - 从单选按钮中选择减少功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41684874/
我正在构建一个 RCP 应用程序,其中每个季度都会更新功能/插件。因此,如果用户选择自动更新功能/插件,则会下载更新插件的新 jar,但旧插件仍在使用我不再使用的磁盘空间。 我厌倦了删除包含旧 jar
我如何从外部 Controller 功能中调用 Controller 内部的功能,例如电话间隙回调功能 这是 Controller 外部定义的功能 function onDeviceReady()
如果某个功能(例如 MediaSource)可用,我如何使用 Google Dart 检查。 new MediaSource() 抛出一个错误。如何以编程方式检查此类或功能是否存在?有任何想法吗?是否
我正在尝试运行 Azure Orchestrations,突然我开始从 statusQueryGetUri 收到错误: 协调器函数“UploadDocumentOrchestrator”失败:函数“U
我见过 iPhone 上的应用程序,如果在 3.0 上运行,将使用 3.0 功能/API,例如应用内电子邮件编辑器,如果在 2.x 上运行,则不使用这些功能,并退出应用程序以启动邮件相反。 这是怎么做
这是 DB 规范化理论中的一个概念: Third normal form is violated when a non-key field is a fact about another non-ke
如果我定义 #if SOMETHING #endif 而且我还没有在任何地方定义 SOMETHING。 #if 中的代码会编译吗? 最佳答案 当#if的参数表达式中使用的名称未定义为宏时(在所有其他宏
我刚刚澄清了 A* 路径查找应该如何在两条路径具有相等值的 [情况] 下运行,无论是在计算期间还是在结束时,如果有两条相等的短路径。 例如,我在我的起始节点,我可以扩展到两个可能的节点,但它们都具有相
Java有没有类似下面的东西 宏 一种遍历所有私有(private)字段的方法 类似于 smalltalk symbols 的东西——即用于快速比较静态字符串的东西? 请注意,我正在尝试为 black
这个程序应该将华氏度转换为摄氏度: #include int main() { float fahrenheit, celsius; int max, min, step;
当打开PC缓存功能后, 软件将采用先进先出的原则排队对示波器采集的每一帧数据, 进行帧缓存。 当发现屏幕中有感兴趣的波形掠过时, 鼠标点击软件的(暂停)按钮, 可以选择回看某一帧的波形
我有一个特殊的(虚拟)函数,我想在沙盒环境中使用它: disable.system.call eval(parse(text = 'model.frame("1 ~ 1")'), envir = e
使用新的 Service 实现,我是否必须为我的所有服务提供一个 Options 方法? 使用我的所有服务当前使用的旧 ServiceBase 方法,OPTIONS 返回 OK,但没有 Access-
我正在阅读 Fogus 的关于 Clojure 的喜悦的书,在并行编程章节中,我看到了一个函数定义,它肯定想说明一些重要的事情,但我不知道是什么。此外,我看不到这个函数有什么用 - 当我执行时,它什么
我有大量的 C 代码,大部分代码被注释掉和/或 #if 0。当我使用 % 键匹配 if-else 的左括号和右括号时,它也匹配注释掉的代码。 有没有办法或vim插件在匹配括号时不考虑注释掉或#if 0
我有这个功能: map(map(fn x =>[x])) [[],[1],[2,3,4]]; 产生: val it = [[],[[1]],[[2],[3],[4]]] 我不明白这个功能是如何工作的。
我使用 Visual Studio 代码创建了一个函数应用程序,然后发布了它。功能应用程序运行良好。我现在在功能门户中使用代码部署功能(KUDU)并跳过构建。下面是日志 9:55:46 AM
我有一个数据框df: userID Score Task_Alpha Task_Beta Task_Charlie Task_Delta 3108 -8.00 Easy Easy
我真的无法解决这个问题: 我有一个返回数据框的函数。但是,数据框仅打印在我的控制台中,尽管我希望将其存储在工作空间中。我怎样才能做到这一点? 样本数据: n <- 32640 t <- seq(3*p
有没有办法找出所有可能的激活器命令行选项? activator -help仅提供最低限度的可用选项/功能列表,但所有好的东西都隐藏起来,即使在 typesafe 网站在线文档中也不可用。 到目前为止,
我是一名优秀的程序员,十分优秀!