使用花括号来引用自定义函数内部有条件定义的表达式中的列名是无效的。

huangapple go评论91阅读模式
英文:

R: using curly braces referring to column name within a conditionally-defined expression inside custom function does not work

问题

我已经定义了一个函数,该函数生成一个ggplot图表,其中y变量可以是级别或百分比,因此我已经包含了一个if-else来适当地修改选项。然后,我通过ggplotly运行图表以生成交互式版本,但悬停文本标签不按预期工作。如图所示,标签只是打印我的函数,而不是显示预期的y值。

我一直在寻找正确的方法,我认为我应该以某种方式使用evalquoteexpression,但不理解它们如何结合在一起。我知道的是,如果不使用例如quote,我会收到一个错误,提示对象values不存在,这表明函数的某部分在没有告知values是我的数据集中的列的情况下被评估。

这是我的reprex(示例代码):

  1. library(tidyverse) #for dplyr
  2. library(ggplot2) #for chart
  3. library(scales) #for axis label
  4. library(plotly) #for interactive chart
  5. # 数据集
  6. dataset <- data.frame(geography_name=c("a","b","c","d","e","f"),
  7. values=c(2,3,4,5,6,7))
  8. # 自定义辅助函数
  9. perc_form = function(x, d=1) sprintf(paste0("%1.",d,"f"), x)
  10. value_form = function(x,s=2,d= -1) format(signif(round(as.numeric(x), d),s), big.mark=",")
  11. # 生成ggplot图表的函数
  12. barchart <- function( data_set = dataset,
  13. x_var = geography_name,
  14. y_var = values,
  15. bar_stat_type=NULL) {
  16. # 根据变量格式设置坐标轴类型
  17. if (bar_stat_type=="pct") {
  18. y_var_label <- paste0("Rate: ",quote(perc_form({{y_var}})),"%")
  19. label_form <- (percent_format(accuracy=1))
  20. } else if (bar_stat_type=="money") {
  21. y_var_label <- paste0("Level: £",quote(value_form({{y_var}})))
  22. label_form <- (comma_format())
  23. }
  24. # 图表
  25. barchart <- data_set %>%
  26. ggplot(mapping = aes(x = {{x_var}},
  27. y = {{y_var}},
  28. text = paste0(geography_name, "\n",
  29. eval(y_var_label), "\n")))+
  30. geom_bar(stat = "identity", position = position_dodge(), width = 0.4)+
  31. scale_y_continuous(labels = eval(label_form)) #此评估有效
  32. return(barchart)
  33. }
  34. # 生成的ggplot图表正常
  35. gg <- barchart(bar_stat_type="money")
  36. gg
  37. # ggplotly图表的悬停标签不正确
  38. ggplotly(gg)

ggplotly标签不包括实际的y变量值

  1. <details>
  2. <summary>英文:</summary>
  3. I have defined a function which produces a ggplot chart, where the y-variable can either be a level or a percentage, so I have included an if-else to amend the options appropriately. I then run the chart through ggplotly to produce an interactive version, but the hover-over text label does not work as intended. As shown in the picture, the label just prints my function instead of showing the y-value as intended.
  4. I have struggled to find the right approach and think that I am supposed to use `eval`, `quote` or `expression` in some way, but don&#39;t understand how it all fits together. What I do know is that without using e.g. `quote`, I get an error saying the object `values` does not exist, which suggests that part of the function is evaluated without being told `values` is a column within my dataset.
  5. Here is my reprex:

library(tidyverse) #for dplyr
library(ggplot2) #for chart
library(scales) #for axis label
library(plotly) #for interactive chart

dataset

dataset <- data.frame(geography_name=c("a","b","c","d","e","f"),
values=c(2,3,4,5,6,7))

custom helper functions

perc_form = function(x, d=1) sprintf(paste0("%1.",d,"f"), x)

value_form = function(x,s=2,d= -1) format(signif(round(as.numeric(x), d),s), big.mark=",")

function producing ggplot chart

barchart <- function( data_set = dataset,
x_var = geography_name,
y_var = values,
bar_stat_type=NULL) {

Set axis type dependent on variable format

if (bar_stat_type=="pct") {
y_var_label <- paste0("Rate: ",quote(perc_form({{y_var}})),"%")
label_form <- (percent_format(accuracy=1))
} else if (bar_stat_type=="money") {
y_var_label <- paste0("Level: £",quote(value_form({{y_var}})))
label_form <- (comma_format())
}

Chart

barchart <- data_set %>%
ggplot(mapping = aes(x = {{x_var}},
y = {{y_var}},
text = paste0(geography_name, "\n",
eval(y_var_label), "\n")))+
geom_bar(stat = "identity", position = position_dodge(), width = 0.4)+
scale_y_continuous(labels = eval(label_form)) #this evaluation works

return(barchart)
}

ggplot chart is produced fine

gg <- barchart(bar_stat_type="money")
gg

ggplotly chart does not have correct hover-over labels

ggplotly(gg)

  1. [ggplotly labels do not include actual y-variable value][1]
  2. [1]: https://i.stack.imgur.com/uXJvP.png
  3. </details>
  4. # 答案1
  5. **得分**: 0
  6. 以下是代码部分的翻译:
  7. ```R
  8. 不需要使用 `quote` 或 `eval`。只需将您的 `y_var_label` 函数定义好,然后可以在 `ggplot2` 代码中调用它们:
  9. ```R
  10. library(ggplot2)
  11. library(scales)
  12. library(plotly)
  13. barchart <- function(data_set = dataset,
  14. x_var = geography_name,
  15. y_var = values,
  16. bar_stat_type = NULL) {
  17. if (bar_stat_type == "pct") {
  18. y_var_label <- function(x) paste0("Rate: ", percent_format(x), "%")
  19. label_form <- percent_format(accuracy = 1)
  20. } else if (bar_stat_type == "money") {
  21. y_var_label <- function(x) paste0("Level: £", comma_format(x))
  22. label_form <- comma_format()
  23. }
  24. data_set %>%
  25. ggplot(mapping = aes(
  26. x = {{ x_var }},
  27. y = {{ y_var }},
  28. text = paste0(
  29. geography_name, "\n",
  30. y_var_label({{ y_var }}), "\n"
  31. )
  32. )) +
  33. geom_bar(stat = "identity", position = position_dodge(), width = 0.4) +
  34. scale_y_continuous(labels = label_form)
  35. }
  36. gg <- barchart(bar_stat_type = "money")
  37. ggplotly(gg)
  1. 希望这对您有所帮助。如果有其他翻译或解释需求,请随时提问。
  2. <details>
  3. <summary>英文:</summary>
  4. There is no need for `quote` or `eval`. Simply make you `y_var_label`s functions which can be called inside your `ggplot2` code:

library(ggplot2)
library(scales)
library(plotly)

barchart <- function(data_set = dataset,
x_var = geography_name,
y_var = values,
bar_stat_type = NULL) {
if (bar_stat_type == "pct") {
y_var_label <- function(x) paste0("Rate: ", perc_form(x), "%")
label_form <- percent_format(accuracy = 1)
} else if (bar_stat_type == "money") {
y_var_label <- function(x) paste0("Level: £", value_form(x))
label_form <- comma_format()
}

data_set %>%
ggplot(mapping = aes(
x = {{ x_var }},
y = {{ y_var }},
text = paste0(
geography_name, "\n",
y_var_label({{ y_var }}), "\n"
)
)) +
geom_bar(stat = "identity", position = position_dodge(), width = 0.4) +
scale_y_continuous(labels = label_form)
}

gg <- barchart(bar_stat_type = "money")

ggplotly(gg)

  1. [![enter image description here][1]][1]
  2. [1]: https://i.stack.imgur.com/gn2i2.png
  3. </details>

huangapple
  • 本文由 发表于 2023年2月8日 23:48:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75388303.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定