英文:
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值。
我一直在寻找正确的方法,我认为我应该以某种方式使用eval
,quote
或expression
,但不理解它们如何结合在一起。我知道的是,如果不使用例如quote
,我会收到一个错误,提示对象values
不存在,这表明函数的某部分在没有告知values
是我的数据集中的列的情况下被评估。
这是我的reprex(示例代码):
library(tidyverse) #for dplyr
library(ggplot2) #for chart
library(scales) #for axis label
library(plotly) #for interactive chart
# 数据集
dataset <- data.frame(geography_name=c("a","b","c","d","e","f"),
values=c(2,3,4,5,6,7))
# 自定义辅助函数
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=",")
# 生成ggplot图表的函数
barchart <- function( data_set = dataset,
x_var = geography_name,
y_var = values,
bar_stat_type=NULL) {
# 根据变量格式设置坐标轴类型
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())
}
# 图表
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)) #此评估有效
return(barchart)
}
# 生成的ggplot图表正常
gg <- barchart(bar_stat_type="money")
gg
# ggplotly图表的悬停标签不正确
ggplotly(gg)
<details>
<summary>英文:</summary>
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.
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'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.
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)
[ggplotly labels do not include actual y-variable value][1]
[1]: https://i.stack.imgur.com/uXJvP.png
</details>
# 答案1
**得分**: 0
以下是代码部分的翻译:
```R
不需要使用 `quote` 或 `eval`。只需将您的 `y_var_label` 函数定义好,然后可以在 `ggplot2` 代码中调用它们:
```R
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: ", percent_format(x), "%")
label_form <- percent_format(accuracy = 1)
} else if (bar_stat_type == "money") {
y_var_label <- function(x) paste0("Level: £", comma_format(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)
希望这对您有所帮助。如果有其他翻译或解释需求,请随时提问。
<details>
<summary>英文:</summary>
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)
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/gn2i2.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论