在谷歌可视化API中使用分组聚合保留格式
Retain Formatting Using Group By Aggregation in Google Visualization API
使用Google的可视化API,我使用Google . Visualization .data.group根据我的原始数据创建子表。我的原始数据使用{v:"US", f:"United States"}的技巧来显示值以外的内容,但是当我使用聚合函数时,格式化被消除,只留下"US"部分。
是否有任何方法可以保留原始格式,或者简单的方法将其添加回使用组聚合创建的数据表?
样本数据:[2010, {v:"MA", f:"Morocco"}, {v:"002", f:"Africa"}, {v:"002", f:"Northern Africa"}, 21.12724],
[2010, {v:"AW", f:"Aruba"}, {v:"019", f:"Americas "}, {v:"019", f:"Caribbean"}, 0.98],
[2010, {v:"AF", f:"Afghanistan"}, {v:"142", f:"Asia"}, {v:"142", f:"Southern Asia"}, 0.9861],
[2010, {v:"AO", f:"Angola"}, {v:"002", f:"Africa"}, {v:"002", f:"Middle Africa"}, 5.11774],
聚合函数:
var countryData = google.visualization.data.group(
rawData,
[0, 1],
[{'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'}]
);
编辑:进一步考虑,可能不可能使用format进行分组,因为不能保证每个值的格式是一致的。考虑到这一点,最好(或唯一可能)编写一个函数,将格式添加到数据的每一列。所以问题就变成了,"我到底该怎么做?"
我真的不愿意将原始数据单独创建为未格式化的值,然后创建额外的表来查找每个值的格式。这将需要额外的2个表(一个用于28行的地区,一个用于240行以上的国家),然后创建两个函数来查看分组表中的每个值(将有30多年的数据,意味着数千行)添加值。
这似乎是个很复杂的解决方案。
是否有办法做到这一点与修饰符函数?我可以写一个函数来返回表中的每个值作为{v: "US", f: "United States"}格式的对象吗?或者是否有一种简单的方法来编写列格式化程序,它将在原始表中查找适当的值并采用该格式?哪种方法对我(编写程序的人)和用户(加载程序的人)来说最不头疼?
编辑2:看起来我应该能够为新表创建一个格式化器,使用如下所示:
function (dt, row) {
return {
v: (dt.getValue(row, 1) / 1000000),
f: (dt.getValue(row, 1) / 1000000) + 'M'
}
}
但是问题变成了,因为我不处理数字格式,我必须创建某种查找表来获取值,在查找表中查找它,然后返回适当的格式。而且看起来我可能需要逐行循环遍历整个表,这有数千行。
我无法想象没有暴力循环和赋值的简单方法来做到这一点。
编辑3:所以我尝试了一些棘手的事情。我没有将每一行设置为值/格式,而是将值/格式部分创建为字符串,然后在分组后使用eval()对对象求值。这很有效。以下是数据:
[2010, "{v: 'MA', f: 'Morocco'}", 21.13],
[2010, "{v: 'AW', f: 'Aruba'}", 0.98],
[2010, "{v: 'AF', f: 'Afghanistan'}", 0.99],
[2010, "{v: 'AO', f: 'Angola'}", 5.12],
下面是新代码:
var countryCount = countryData.getColumnRange(0).count;
for (var i = 0; i <= countryCount; i++) {
countryData.setValue(i, 1, eval('(' + countryData.getValue(i,1) + ')'));
};
问题是,当我将此输出到Google DataTable时,它显示{v: 'AE', f: 'United Arab Emirates'},尽管使用eval正确检查结果会给我:
>>> eval('(' + countryData.getValue(i,1) + ')')
Object v="AE" f="United Arab Emirates"
我哪里做错了?
好吧,我把这个弄明白了(它是多么令人讨厌的复杂)。
我尝试了一种新的方法。我重新格式化了我的数据,然后创建了一个函数来返回基于该字符串内的分隔符的值/格式。所以我的数据现在看起来像这样:[2010, "'MA'|'Morocco'", 21.13],
[2010, "'AW'|'Aruba'", 0.98],
[2010, "'AF'|'Afghanistan'", 0.99],
[2010, "'AO'|'Angola'", 5.12],
然后我使用这个来获取第1列的分隔符位置:
var countryCount = countryData.getNumberOfRows();
for (var i = 0; i <= countryCount; i++) {
var stringToSplit = countryData.getValue(i,1);
var dividerLocation = stringToSplit.indexOf("|");
alert("Divider: " + dividerLocation + ", String: " + stringToSplit);
countryData.setValue(i, 1, splitFormat(dividerLocation, stringToSplit));
};
然后我用这个函数拆分字符串:
function splitFormat(dividerLocation, stringToSplit) {
// alert("entered splitFormat Function");
var stringValue = "";
var formatValue = "";
stringValue = stringToSplit.substring(0, dividerLocation);
formatValue = stringToSplit.substring(dividerLocation + 1)
alert("v: " + stringValue + ", f: " + formatValue);
return {
v: stringValue,
f: formatValue
}
}
问题是,我定义的列1我的数据为'字符串',但firebug告诉我,从splitFormat()函数返回的对象是一个对象(因为它是一个数组我想)。即使我用v:和f:组件设置原始数据表,它也不想接受返回的数组对象值,因为FireBug给了我以下非常有用的建议:
"Error: Type mismatch. Value [object Object] does not match type string in column index 1 (table.I.js,137)"
问题是,虽然您可以使用{v:, f:}语法定义DataTable,但您不能将该语法返回到表中,因为该列的值被设置为字符串。相反,我使用了数据表的"setFormattedValue"属性来解决这个问题:
function drawVisualization() {
var countryTable = new google.visualization.Table(document.getElementById('table'));
var countryCount = countryData.getNumberOfRows() - 1;
for (var i = 0; i <= countryCount; i++) {
var stringToSplit = countryData.getValue(i,1);
var dividerLocation = stringToSplit.indexOf("|");
var stringValue = stringToSplit.substring(0, dividerLocation);
var stringFormat = stringToSplit.substring(dividerLocation + 1);
countryData.setValue(i, 1, stringValue);
countryData.setFormattedValue(i, 1, stringFormat);
};
这给了我两个合适的值,尽管对于大数据集来说有点密集。如果有人知道更简单的方法,我将非常乐意听到。
我自己刚刚遇到这个问题。我决定使用修饰符将值更改为使用原始dataTable查找格式化值的格式化值。这不是非常有效,但它可以工作,而且计算机速度很快。
首先创建一个查找函数:
function getFormatForValue(dataTable, column, value) {
// we need to spin through column in the dataTable looking
// for the matching value and then return the formatted value
var rowcount = dataTable.getNumberOfRows();
for (var i=0; i<rowcount; i++) {
if (dataTable.getValue(i, column) === value) {
// we found it, this will look much better
return dataTable.getFormattedValue(i, column);
}
}
// better than nothing
return value;
}
然后在修饰符中调用它,更改原始组调用:
var countryData = google.visualization.data.group(
rawData,
[
{
'column': 0,
'modifier': function(value) { return getFormatForValue(rawData, 0, value); },
'type': 'string'
},
{
'column': 1,
'modifier': function(value) { return getFormatForValue(rawData, 1, value); },
'type': 'string'
}
],
[{'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'}]
);
更新:似乎您需要保留值和格式化的值。在我显示饼状图的例子中,我并不关心保留原始值。我想这可能不适合你,但我将把这个答案留给其他可能有像我这样更简单的情况的人。
我花了几分钟在这上面,这里有一个替代方案,将复制格式化的值,同时保持原始单元格的值。
创建一个使用查找函数的复制函数:
function copyFormattedValues(oldDataTable, oldColumn, newDataTable, newColumn) {
var rowcount = newDataTable.getNumberOfRows();
for (var i=0; i<rowcount; i++) {
var value = newDataTable.getValue(i, newColumn);
var formatted = getFormatForValue(oldDataTable, oldColumn, value);
newDataTable.setFormattedValue(i, newColumn, formatted);
}
}
然后在您的示例中,为要复制的每个列调用一次。
copyFormattedValues(rawData, 0, countryData, 0);
copyFormattedValues(rawData, 1, countryData, 1);
源列和目标列是相同的,但在某些情况下它们可能不同。
当然,理想情况下,这一切都会自动发生。
- 分派点击事件并保留击键修饰符
- 防止Javascript注入(但保留文本格式和图像)
- ngTagsInput:保留原始数据提供者的数据格式
- 离开页面并返回页面时,不会保留 JS 页面格式
- HTML 保留字符串与 html 格式
- 从html中剥离邮件正文,并使用Javascript保留格式
- 如何在打印时保留存储在数据库中的文本格式
- 在setValue()之后未保留格式
- 使用javascript中的HTML保留缩进格式
- 将HTML复制到剪贴板,同时保留一些格式
- 保留jquery粘贴格式
- 如何在Java中迭代如下格式的日期范围25-12-2012到31-12-2012(应保留连字符)
- 在JavaScript代码片段区域保留格式
- 保留从数据库接收到的HTML格式的数据
- 在Angular绑定中保留HTML文本框换行格式
- 对 JSON 数据进行编码以保留 json 格式
- 从 DOM 保留换行符中提取无格式文本的最佳方法
- 使用带有可点击“更多”的 Jquery 修剪文本,但保留文本格式
- 如何在javascript编辑后使用JQuery Mobile刷新/保留HTML格式
- 在谷歌可视化API中使用分组聚合保留格式