R生成图表时存在0值导致报错的调整解决方法
问题根因
当查询2021-07-03、分类为ABC的数据时,所有DR0系列字段的数值均为0,代码会删除所有DR0开头的计算字段,导致最终生成的datas对象中Days和Numbers列全为NA,计算坐标轴范围时返回非有限值(Inf)触发报错。
核心修改点
- 给
datas对象增加全NA场景的兜底逻辑,自动填充0值和默认天数 - 坐标轴范围计算增加非有限值兜底,避免
plot函数报错 - 优化0值场景的绘图逻辑,保证0值红线和标记点正常渲染
修改后完整代码
library(dplyr) library(tidyr) library(lubridate) library(readr) df1 <- structure( list(date1= c("2021-06-28","2021-06-28","2021-06-28"), date2 = c("2021-07-01","2021-07-02","2021-07-03"), Category = c("BCE","ABC","ABC"), Week= c("Wednesday","Thursday","Friday"), DR1 = c(11,5,0), DR01 = c(10,4,0), DR02= c(2,4,0),DR03= c(0,5,0), DR04 = c(2,4,0),DR05 = c(1,6,0)), class = "data.frame", row.names = c(NA, -3L)) f1 <- function(dmda, CategoryChosse) { x<-df1 %>% select(starts_with("DR0")) x<-cbind(df1, setNames(df1$DR1 - x, paste0(names(x), "_PV"))) PV<-select(x, date2,Week, Category, DR1, ends_with("PV")) med<-PV %>% group_by(Category,Week) %>% summarize(across(ends_with("PV"), median), .groups = "drop") SPV<-df1 %>% inner_join(med, by = c('Category', 'Week')) %>% mutate(across(matches("^DR0\\d+$"), ~.x + get(paste0(cur_column(), '_PV')), .names = '{col}_{col}_PV')) %>% select(date1:Category, DR01_DR01_PV:last_col()) SPV<-data.frame(SPV) mat1 <- df1 %>% filter(date2 == dmda, Category == CategoryChosse) %>% select(starts_with("DR0")) %>% pivot_longer(cols = everything()) %>% arrange(desc(row_number())) %>% mutate(cs = cumsum(value)) %>% filter(cs == 0) %>% pull(name) (dropnames <- paste0(mat1,"_",mat1, "_PV")) SPV <- SPV %>% filter(date2 == dmda, Category == CategoryChosse) %>% select(-any_of(dropnames)) if(length(grep("DR0", names(SPV))) == 0) { SPV[head(mat1, 20)] <- NA_real_ } datas <-SPV %>% filter(date2 == ymd(dmda)) %>% group_by(Category) %>% summarize(across(starts_with("DR0"), sum), .groups = "drop") %>% pivot_longer(cols= -Category, names_pattern = "DR0(.+)", values_to = "val") %>% mutate(name = parse_number(name)) colnames(datas)[-1]<-c("Days","Numbers") # 全NA兜底处理 if(all(is.na(datas$Numbers))){ # 按现有数据的DR0字段数量生成默认天数,数值设为0 datas$Days <- 1:length(grep("^DR0\\d+$", names(df1))) datas$Numbers <- 0 } else { datas <- datas %>% group_by(Category) %>% slice((as.Date(dmda) - min(as.Date(df1$date1) [ df1$Category == first(Category)])):max(Days)+1) %>% ungroup } m<-df1 %>% group_by(Category,Week) %>% summarize(across(starts_with("DR1"), mean), .groups = "drop") m<-subset(m, Week == df1$Week[match(ymd(dmda), ymd(df1$date2))] & Category == CategoryChosse)$DR1 # 坐标轴范围兜底 maxrange <- range(0, datas$Numbers, na.rm = TRUE) if(!is.finite(maxrange[2])) maxrange[2] <- 20 else maxrange[2] <- max(datas$Numbers)+ 20 max_days <- max(datas$Days, na.rm = TRUE) if(!is.finite(max_days)) max_days <- length(grep("^DR0\\d+$", names(df1))) max <- max_days + 1 # 绘图 plot(Numbers ~ Days, xlim= c(0,max), ylim= c(0,maxrange[2]), xaxs='i',data = datas,main = paste0(dmda, "-", CategoryChosse)) # 适配0值场景的红线和点绘制 if (nrow(datas)<=2 || m == 0){ abline(h=m,lwd=2, col = "red") points(0, m, col = "red", pch = 19, cex = 2, xpd = TRUE) text(.1,m+ .5, round(m,1), cex=1.1,pos=4,offset =1,col="black") } } # 所有测试用例均可正常运行 f1("2021-07-01", "BCE") f1("2021-07-02", "ABC") f1("2021-07-03", "ABC")
效果说明
修改后三类测试场景均可正常生成图表,全0值场景会在0值位置显示对应标记点,同时绘制红色0值水平线,和正常场景的展示效果一致。
内容的提问来源于stack exchange,提问作者user16774617
相关产品推荐
相关产品推荐

