在 DT 中舍入货币格式的数字
Rounding currency formatted numbers in DT
我正在尝试获取货币格式的数字,然后将它们四舍五入,但我从 DT
(v 0.1) 得到了意外的行为。
我希望将看起来像 808084.227872401
的值转换为 £808,084.2
代码如下:
library(DT)
m <- structure(list(A = c(808084.227872401, 1968554.9592654, 751271.053745238,
-248530.769710688, 1022891.09543523, -407303.626363765), B = c(143073.342325492,
-1440469.87343229, -590080.736184761, -608299.78907882, 1167155.65688074,
803870.898483576), C = c(-447086.9382469, 606572.488852836, 89371.3745637198,
-1496047.6143101, -410103.544644035, 1106358.3287006), D = c(0.754009573487565,
0.364774209912866, 0.525769896339625, 0.44853704655543, 0.909551323624328,
0.439131782157347), E = c(98.8604132297185, 98.9055931760521,
99.3795062166865, 98.5895350315005, 101.194549174315, 102.325111315431
)), .Names = c("A", "B", "C", "D", "E"), row.names = c(NA, -6L
), class = "data.frame")
根据 documentation 这应该有效:
datatable(m) %>% formatCurrency("A", "£", digits = 1)
但我收到以下错误:
Error in formatCurrency(., "A", "£", digits = 1) :
unused argument (digits = 1)
然后我尝试了另一个命令:
datatable(m) %>% formatCurrency("A", "£") %>% formatRound("A", 1)
但它只格式化了货币,没有四舍五入。
有什么想法吗?
PS。我知道 答案,但我不想显示字符串,因为我想在显示 datatable
.
时对数字进行排序
我的结论是,您不能将 2 个格式化程序添加到 DT
的同一列,当然我可能是错的。
请注意,即使 DT
的文档中未明确说明这一点,也只能为每列添加一个格式化程序 table。另请注意,在您提供的 link 中的示例中,或者当您键入 ?formatCurrency
时,当它们包含两个管道 %>%
时,它们总是影响两个不同的列。
在你的例子中,当你这样做时
datatable(m) %>% formatRound("A", digits=1) %>% formatCurrency("A", currency="£")
结果是 1 位数字,没有货币,如果你这样做
datatable(m) %>% formatCurrency("A", currency="£") %>% formatRound("A", digits=1)
结果是没有四舍五入的货币。
我对 R 如何与 js 集成的知识非常有限,但查看 the package in cran 的 R 源代码,看起来管道中的每个格式化命令都附加了一个格式化程序,但由于某种原因只有一个格式化程序发挥作用:
formatCurrency = function(table, columns, currency = '$', interval = 3, mark = ',') {
formatColumns(table, columns, tplCurrency, currency, interval, mark)
}
formatRound = function(table, columns, digits = 2) {
formatColumns(table, columns, tplRound, digits)
}
formatColumns = function(table, columns, template, ...) {
...
x$options$rowCallback = appendFormatter(
x$options$rowCallback, columns, colnames, rownames, template, ...
)
...
}
appendFormatter = function(js, name, names, rownames = TRUE, template, ...) {
...
JS(append(
js, after = 1,
template(i, ...)
))
}
其中每个格式化程序最终使用不同的 template
调用 formatColumns
,并且 i
解析列的 id。正如我所说,我不知道这是因为追加操作覆盖了格式化程序,还是与执行有关。
编辑:抱歉,我不小心按下了 post 按钮,被打断了。我实际上实现了一个接受更多参数的格式化程序。该解决方案有点复杂,但它有效。这是一个接受货币和数字的格式化程序:
tplRound2 = function(cols, currency, digits) {
sprintf(
"var d = parseFloat(data[%d]); $(this.api().cell(row, %s).node()).html(isNaN(d) ? '' : '%s' + d.toFixed(%d).toString());",
cols, cols, currency, digits
)
}
您需要将所有这些功能添加到您的会话中:
formatRound2 = function(table, columns, currency, digits = 2) {
formatColumns2(table, columns, tplRound2, currency, digits)
}
formatColumns2 = function(table, columns, template, ...) {
if (inherits(columns, 'formula')) columns = all.vars(columns)
x = table$x
colnames = base::attr(x, 'colnames', exact = TRUE)
rownames = base::attr(x, 'rownames', exact = TRUE)
x$options$rowCallback = appendFormatter2(
x$options$rowCallback, columns, colnames, rownames, template, ...
)
table$x = x
table
}
name2int = function(name, names) {
if (is.numeric(name)) {
return(if (all(name > 0)) name else seq_along(names)[name])
}
names = setNames(seq_along(names), names)
unname(names[name])
}
appendFormatter2 = function(js, name, names, rownames = TRUE, template, ...) {
js = if (length(js) == 0) c('function(row, data) {', '}') else {
unlist(strsplit(as.character(js), '\n'))
}
i = name2int(name, names)
if (is.character(name) || (is.numeric(name) && !rownames)) i = i - 1
if (any(is.na(i))) stop(
'You specified the columns: ', paste(name, collapse = ', '), ', ',
'but the column names of the data are ', paste(names, collapse = ', ')
)
JS(append(
js, after = 1,
template(i, ...)
))
}
然后您可以 运行 使用新的格式化程序来获得所需的结果:
datatable(m) %>% formatRound2("A", "£", digits=1)
(但是这不会每 3 个数字添加 ,
,如果您真的需要它,我可以将它添加到格式化程序中...)
EDIT2 评论后:
这将是使用货币和位数的格式化程序函数,加上“,”标记:
tplRound3 = function(cols, currency, digits, interval, mark) {
sprintf(
"var d = parseFloat(data[%d]); $(this.api().cell(row, %s).node()).html(isNaN(d) ? '' : '%s' + d.toFixed(%d).toString().replace(/\B(?=(\d{%d})+(?!\d))/g, '%s'));",
cols, cols, currency, digits, interval, mark
)
}
formatRound3 = function(table, columns, currency, digits = 2, interval=3, mark=',') {
formatColumns2(table, columns, tplRound3, currency, digits, interval, mark)
}
要使用它,只需键入
datatable(m) %>% formatRound3("A", "£", digits=1)
经过一番研究后,我发现可以在 formatCurrency()
内完成此操作
将代码更改为以下将解决问题:
datatable(m) %>% formatCurrency("A", '\U20AC', digits = 1)
我正在尝试获取货币格式的数字,然后将它们四舍五入,但我从 DT
(v 0.1) 得到了意外的行为。
我希望将看起来像 808084.227872401
的值转换为 £808,084.2
代码如下:
library(DT)
m <- structure(list(A = c(808084.227872401, 1968554.9592654, 751271.053745238,
-248530.769710688, 1022891.09543523, -407303.626363765), B = c(143073.342325492,
-1440469.87343229, -590080.736184761, -608299.78907882, 1167155.65688074,
803870.898483576), C = c(-447086.9382469, 606572.488852836, 89371.3745637198,
-1496047.6143101, -410103.544644035, 1106358.3287006), D = c(0.754009573487565,
0.364774209912866, 0.525769896339625, 0.44853704655543, 0.909551323624328,
0.439131782157347), E = c(98.8604132297185, 98.9055931760521,
99.3795062166865, 98.5895350315005, 101.194549174315, 102.325111315431
)), .Names = c("A", "B", "C", "D", "E"), row.names = c(NA, -6L
), class = "data.frame")
根据 documentation 这应该有效:
datatable(m) %>% formatCurrency("A", "£", digits = 1)
但我收到以下错误:
Error in formatCurrency(., "A", "£", digits = 1) : unused argument (digits = 1)
然后我尝试了另一个命令:
datatable(m) %>% formatCurrency("A", "£") %>% formatRound("A", 1)
但它只格式化了货币,没有四舍五入。
有什么想法吗?
PS。我知道 datatable
.
我的结论是,您不能将 2 个格式化程序添加到 DT
的同一列,当然我可能是错的。
请注意,即使 DT
的文档中未明确说明这一点,也只能为每列添加一个格式化程序 table。另请注意,在您提供的 link 中的示例中,或者当您键入 ?formatCurrency
时,当它们包含两个管道 %>%
时,它们总是影响两个不同的列。
在你的例子中,当你这样做时
datatable(m) %>% formatRound("A", digits=1) %>% formatCurrency("A", currency="£")
结果是 1 位数字,没有货币,如果你这样做
datatable(m) %>% formatCurrency("A", currency="£") %>% formatRound("A", digits=1)
结果是没有四舍五入的货币。
我对 R 如何与 js 集成的知识非常有限,但查看 the package in cran 的 R 源代码,看起来管道中的每个格式化命令都附加了一个格式化程序,但由于某种原因只有一个格式化程序发挥作用:
formatCurrency = function(table, columns, currency = '$', interval = 3, mark = ',') {
formatColumns(table, columns, tplCurrency, currency, interval, mark)
}
formatRound = function(table, columns, digits = 2) {
formatColumns(table, columns, tplRound, digits)
}
formatColumns = function(table, columns, template, ...) {
...
x$options$rowCallback = appendFormatter(
x$options$rowCallback, columns, colnames, rownames, template, ...
)
...
}
appendFormatter = function(js, name, names, rownames = TRUE, template, ...) {
...
JS(append(
js, after = 1,
template(i, ...)
))
}
其中每个格式化程序最终使用不同的 template
调用 formatColumns
,并且 i
解析列的 id。正如我所说,我不知道这是因为追加操作覆盖了格式化程序,还是与执行有关。
编辑:抱歉,我不小心按下了 post 按钮,被打断了。我实际上实现了一个接受更多参数的格式化程序。该解决方案有点复杂,但它有效。这是一个接受货币和数字的格式化程序:
tplRound2 = function(cols, currency, digits) {
sprintf(
"var d = parseFloat(data[%d]); $(this.api().cell(row, %s).node()).html(isNaN(d) ? '' : '%s' + d.toFixed(%d).toString());",
cols, cols, currency, digits
)
}
您需要将所有这些功能添加到您的会话中:
formatRound2 = function(table, columns, currency, digits = 2) {
formatColumns2(table, columns, tplRound2, currency, digits)
}
formatColumns2 = function(table, columns, template, ...) {
if (inherits(columns, 'formula')) columns = all.vars(columns)
x = table$x
colnames = base::attr(x, 'colnames', exact = TRUE)
rownames = base::attr(x, 'rownames', exact = TRUE)
x$options$rowCallback = appendFormatter2(
x$options$rowCallback, columns, colnames, rownames, template, ...
)
table$x = x
table
}
name2int = function(name, names) {
if (is.numeric(name)) {
return(if (all(name > 0)) name else seq_along(names)[name])
}
names = setNames(seq_along(names), names)
unname(names[name])
}
appendFormatter2 = function(js, name, names, rownames = TRUE, template, ...) {
js = if (length(js) == 0) c('function(row, data) {', '}') else {
unlist(strsplit(as.character(js), '\n'))
}
i = name2int(name, names)
if (is.character(name) || (is.numeric(name) && !rownames)) i = i - 1
if (any(is.na(i))) stop(
'You specified the columns: ', paste(name, collapse = ', '), ', ',
'but the column names of the data are ', paste(names, collapse = ', ')
)
JS(append(
js, after = 1,
template(i, ...)
))
}
然后您可以 运行 使用新的格式化程序来获得所需的结果:
datatable(m) %>% formatRound2("A", "£", digits=1)
(但是这不会每 3 个数字添加 ,
,如果您真的需要它,我可以将它添加到格式化程序中...)
EDIT2 评论后:
这将是使用货币和位数的格式化程序函数,加上“,”标记:
tplRound3 = function(cols, currency, digits, interval, mark) {
sprintf(
"var d = parseFloat(data[%d]); $(this.api().cell(row, %s).node()).html(isNaN(d) ? '' : '%s' + d.toFixed(%d).toString().replace(/\B(?=(\d{%d})+(?!\d))/g, '%s'));",
cols, cols, currency, digits, interval, mark
)
}
formatRound3 = function(table, columns, currency, digits = 2, interval=3, mark=',') {
formatColumns2(table, columns, tplRound3, currency, digits, interval, mark)
}
要使用它,只需键入
datatable(m) %>% formatRound3("A", "£", digits=1)
经过一番研究后,我发现可以在 formatCurrency()
将代码更改为以下将解决问题:
datatable(m) %>% formatCurrency("A", '\U20AC', digits = 1)