You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义ggplot函数条件表达式列名引用失效,ggplotly悬浮标签异常

解决ggplotly悬浮提示显示函数代码而非实际值的问题

问题说明

自定义了生成ggplot柱状图的函数,支持将y轴设置为数值水平或百分比格式,通过if-else语句配置对应显示规则。但将图表转换为ggplotly交互式版本后,悬浮提示文本未显示实际y值,反而输出格式化函数的代码;若不用quote则会报错“对象values不存在”,说明函数执行时无法正确识别数据集中的列。

可复现代码如下:

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)) # 此处eval可正常工作
  
  
  return(barchart)
}

# ggplot图表可正常生成
gg <- barchart(bar_stat_type="money")
gg

# ggplotly的悬浮提示标签异常
ggplotly(gg)

解决方案

核心问题是aes中的text参数未在数据上下文里正确求值,quote的误用导致输出函数代码而非实际计算结果。通过提前在数据集中生成悬浮文本列的方式解决:

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

# 数据集
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=",")

# 修正后的绘图函数
barchart <- function( data_set = dataset,
                      x_var = geography_name, 
                      y_var = values, 
                      bar_stat_type=NULL) {
  
  # 提前生成悬浮文本列,确保在数据上下文里求值
  data_processed <- data_set %>%
    mutate(
      hover_text = case_when(
        bar_stat_type == "pct" ~ paste0({{x_var}}, "\nRate: ", perc_form({{y_var}}), "%"),
        bar_stat_type == "money" ~ paste0({{x_var}}, "\nLevel: £", value_form({{y_var}})),
        TRUE ~ paste0({{x_var}}, "\nValue: ", {{y_var}})
      )
    )
  
  # 确定y轴标签格式
  y_label_form <- if (bar_stat_type == "pct") {
    percent_format(accuracy=1)
  } else if (bar_stat_type == "money") {
    comma_format()
  } else {
    identity
  }
  
  # 生成图表
  barchart <- data_processed %>%  
    ggplot(mapping = aes(x = {{x_var}}, 
                         y = {{y_var}}, 
                         text = hover_text))+ 
    geom_bar(stat = "identity", position = position_dodge(), width = 0.4)+
    scale_y_continuous(labels = y_label_form)
  
  return(barchart)
}

# 测试
gg <- barchart(bar_stat_type="money")
gg
ggplotly(gg)

修改要点

  1. 提前生成悬浮文本:用dplyr::mutate结合case_when在数据集中创建hover_text列,直接在数据上下文里调用格式化函数,确保拿到实际计算后的数值。
  2. 简化轴格式处理:去掉不必要的eval,直接返回格式化函数给scale_y_continuous的labels参数。
  3. 避免quote误用:不再用quote包裹函数调用,而是直接在数据行上计算出最终文本。

内容的提问来源于stack exchange,提问作者Modern_ibex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:00:38