ggplotly中dynamicTicks = T不遵循position属性的解决求助
问题
我用ggplot创建了一个调整过点位置的图表,但设置dynamicTicks = TRUE属性后,点的位置恢复成默认状态了。有没有办法覆盖这个设置,保留我指定的点位置?
(图:dynamicTicks = FALSE时的效果)
(图:dynamicTicks = TRUE时的效果)
可复现代码
library(tidyverse) library(plotly) df <- structure(list(SerialNumber = c("634", "634", "567", "634", "634", "562", "567", "567", "562", "562", "634", "569", "634", "634", "634", "634", "634", "634", "634", "634", "634", "634", "561", "634", "569", "569", "634", "634", "634", "567", "567", "567", "634", "634", "567", "567", "567", "634", "562", "569"), `_device` = c("module1", "module1", "module1", "module1", "module2", "module4", "module2", "module2", "module4", "module1", "module1", "module4", "module1", "module1", "module1", "module1", "module1", "module1", "module3", "module1", "module1", "module3", "module2", "module1", "module1", "module1", "module1", "module1", "module2", "module1", "module1", "module3", "module1", "module1", "module1", "module1", "module1", "module1", "module1", "module4"), `_source_program` = c("program1", "program2", "program3", "program2", "program4", "program2", "program2", "program1", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "ONprogram3", "program1", "program3", "ONprogram3", "program6", "program1", "program6", "program2", "program4", "program6", "program4", "program6", "program6", "ONprogram3", "program6", "program2", "program4", "program6", "program6", "program2", "program6", "program2"), date = structure(c(18891, 18906, 18937, 18940, 18943, 18949, 18952, 18956, 18966, 18972, 18983, 18981, 19007, 19023, 19036, 19036, 19037, 19066, 19072, 19082, 19082, 19088, 19086, 19091, 19106, 19106, 19115, 19109, 19122, 19142, 19145, 19151, 19149, 19149, 19157, 19157, 19169, 19175, 19185, 19192), class = "Date")), row.names = c(NA, -40L), spec = structure(list(cols = list(SerialNumber = structure(list(), class = c("collector_double", "collector")), `_device` = structure(list(), class = c("collector_character", "collector")), `_source_program` = structure(list(), class = c("collector_character", "collector")), date = structure(list(format = ""), class = c("collector_date", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame")) programs <- unique(df$`_source_program`) nudgeAmounts <- "" for (i in 1:length(programs)) { if (i == 1) { nudgeAmounts <- ifelse(df$`_source_program` == programs[i],as.double(paste0("0.", i)), 0) } else { nudgeAmounts <- ifelse(df$`_source_program` == programs[i],as.double(paste0("0.", i)), nudgeAmounts) } } shapes <- c(15,16,17,18,7,8) names(shapes) <- programs g <- ggplot(df, aes(date, SerialNumber, shape = `_source_program` , color =`_device`)) + geom_point(position = position_nudge(y = nudgeAmounts), size = 3 ) + theme_bw() + expand_limits(y = c(1, length(levels(as.factor(df$SerialNumber))) + 1)) + labs(y = "Serial Number", x = "Date") + scale_shape_manual(values = shapes) g ggplotly(g, dynamicTicks = TRUE)
解决方案
问题根源在于dynamicTicks = TRUE会让plotly重新计算y轴的坐标映射,直接覆盖ggplot中position_nudge的偏移效果。要解决这个问题,不在绘图层做偏移,而是直接修改数据里的y值,这样不管plotly是否启用动态刻度,都会基于修改后的坐标渲染点。
具体操作:
- 将
SerialNumber转换为数值类型,方便添加偏移量 - 给每个
_source_program对应的行添加固定的小偏移,生成新的y列(比如y_adjusted) - 用新的y列绘图,同时通过
scale_y_continuous设置刻度标签为原SerialNumber的值
修改后的完整代码
library(tidyverse) library(plotly) df <- structure(list(SerialNumber = c("634", "634", "567", "634", "634", "562", "567", "567", "562", "562", "634", "569", "634", "634", "634", "634", "634", "634", "634", "634", "634", "634", "561", "634", "569", "569", "634", "634", "634", "567", "567", "567", "634", "634", "567", "567", "567", "634", "562", "569"), `_device` = c("module1", "module1", "module1", "module1", "module2", "module4", "module2", "module2", "module4", "module1", "module1", "module4", "module1", "module1", "module1", "module1", "module1", "module1", "module3", "module1", "module1", "module3", "module2", "module1", "module1", "module1", "module1", "module1", "module2", "module1", "module1", "module3", "module1", "module1", "module1", "module1", "module1", "module1", "module1", "module4"), `_source_program` = c("program1", "program2", "program3", "program2", "program4", "program2", "program2", "program1", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "program2", "ONprogram3", "program1", "program3", "ONprogram3", "program6", "program1", "program6", "program2", "program4", "program6", "program4", "program6", "program6", "ONprogram3", "program6", "program2", "program4", "program6", "program6", "program2", "program6", "program2"), date = structure(c(18891, 18906, 18937, 18940, 18943, 18949, 18952, 18956, 18966, 18972, 18983, 18981, 19007, 19023, 19036, 19036, 19037, 19066, 19072, 19082, 19082, 19088, 19086, 19091, 19106, 19106, 19115, 19109, 19122, 19142, 19145, 19151, 19149, 19149, 19157, 19157, 19169, 19175, 19185, 19192), class = "Date")), row.names = c(NA, -40L), spec = structure(list(cols = list(SerialNumber = structure(list(), class = c("collector_double", "collector")), `_device` = structure(list(), class = c("collector_character", "collector")), `_source_program` = structure(list(), class = c("collector_character", "collector")), date = structure(list(format = ""), class = c("collector_date", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame")) # 1. 给每个program分配偏移量,直接在数据层面处理 programs <- unique(df$`_source_program`) nudge_map <- setNames(seq(0.1, length(programs)*0.1, by=0.1), programs) # 2. 转换SerialNumber为数值,并添加偏移得到新的y列 df <- df %>% mutate( SerialNumber_num = as.numeric(SerialNumber), y_adjusted = SerialNumber_num + nudge_map[`_source_program`] ) shapes <- c(15,16,17,18,7,8) names(shapes) <- programs # 3. 用调整后的y_adjusted绘图,设置刻度为原SerialNumber的值 g <- ggplot(df, aes(date, y_adjusted, shape = `_source_program`, color = `_device`)) + geom_point(size = 3) + theme_bw() + scale_y_continuous( breaks = unique(df$SerialNumber_num), labels = unique(df$SerialNumber), limits = range(df$y_adjusted) + c(-0.5, 0.5) ) + labs(y = "Serial Number", x = "Date") + scale_shape_manual(values = shapes) g ggplotly(g, dynamicTicks = TRUE)
内容的提问来源于stack exchange,提问作者Zoe
相关产品推荐
相关产品推荐

