Plotly R堆叠子图:如何保持图形与Y轴对齐消除零点偏移
问题:Plotly R堆叠子图轴对齐偏移
使用Plotly R绘制堆叠子图时,所有子图采用完全相同的数据,但第2至第4张子图的X轴向上偏移,Y轴刻度值(如数值2)也随之错位,导致各子图的零点位置不一致。尝试过设置anchor、scaleanchor(包括position=0和anchor='free'),调整fixedrange、autorange等参数均未解决问题。
问题示意图:顶部子图零点位置正常,下方三个子图的X轴明显上移,Y轴刻度与线条的相对位置错位,破坏了视觉对齐性。
解决方法
问题核心是子图Y轴范围未被统一锁定,且subplot未强制共享Y轴规则。尽管所有子图用相同的mgrid计算Y范围,但后续添加trace时可能触发Plotly自动重计算,加上默认未共享Y轴,导致轴对齐失效。
修正步骤:
- 每个子图创建时,设置
yaxis的autorange=FALSE,锁定计算好的mgrid范围,避免自动调整 - 在
subplot函数中添加shareY=TRUE,强制所有子图共享Y轴刻度与范围 - 移除子图布局中可能冲突的
anchor和scaleanchor设置,避免干扰轴共享逻辑
修改后的可复现代码
set.seed(2244) cols <- c('black','red','green','cyan','blue','magenta','yellow','gray') outlist <- list() nplots <- c(1,2,3,4) bounds <- 0 trials <- 0 M <- 1 N <- 50 i <- 1 y <- rnorm(N) chleaf <- rbinom(N, 1, 0.5) outmat <- matrix(0, nrow=N, ncol=6) outmat[,c(1,3)] <- rnorm(dim(outmat)[1]*2, 0, 1) outmat[,c(2,4)] <- outmat[,c(1,3)]^2 outmat[,c(5,6)] <- y - outmat[,c(1,3)] for (j in nplots) { mgrid <- NULL if ( bounds == 1 ) { mgrid <- c(min(outmat[,3]-2*sqrt(outmat[,4]))-0.5, max(outmat[,3]+2*sqrt(outmat[,4]))+0.5) } else { mgrid <- c(min(min(outmat[,3]), min(outmat[,5]), min(y))-0.5, max(max(outmat[,3]), max(outmat[,5]), max(y))+0.5) } outlist[[i]] <- plotly::plot_ly() %>% plotly::add_trace(x = 1:(M*N), y = outmat[,3], type = 'scatter', mode='lines', showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\mu_{t|t-1}'), line=list(color=cols[1], width=0.5)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,3]+2*sqrt(outmat[,4]), type='scatter', mode='markers', color=I(cols[1]), size=0.5, showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\Sigma_{t|t-1}'), marker=list(symbol='cross-thin'), visible=ifelse(bounds==1, TRUE, FALSE)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,3]-2*sqrt(outmat[,4]), type='scatter', mode='markers', color=I(cols[1]), size=0.5, showlegend=FALSE, marker=list(symbol='cross-thin'), visible=ifelse(bounds==1, TRUE, FALSE)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,1], type = 'scatter', mode='lines', showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\mu_{t|t}'), line=list(color=cols[2], width=0.5)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,1]+2*sqrt(outmat[,2]), type='scatter', mode='markers', color=I(cols[2]), size=0.5, showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\Sigma_{t|t}'), marker=list(symbol='cross-thin'), visible=ifelse(bounds==1, TRUE, FALSE)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,1]-2*sqrt(outmat[,2]), type='scatter', mode='markers', color=I(cols[2]), size=I(5), showlegend=FALSE, marker=list(symbol='cross-thin'), visible=ifelse(bounds==1, TRUE, FALSE)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,5], type = 'scatter', mode='lines', showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\hat{y}_{t}'), line=list(color=cols[3], width=0.5)) %>% plotly::add_trace(x = 1:(M*N), y = outmat[,6], type = 'scatter', mode='lines', showlegend=ifelse(i==1, TRUE, FALSE), name=TeX('\tilde{y}_{t}'), line=list(color=cols[4], width=0.5)) %>% plotly::config(mathjax='cdn') %>% plotly::layout( xaxis=list(title=list(text='Iterations', standoff=0), showline=T, showgrid=F, range = c(0, ifelse(N==1, M+0.25, N*M+0.5))), # 锁定Y轴范围,关闭自动调整 yaxis=list(showline=T, showgrid=F, range=mgrid, autorange=FALSE) ) rMe <- 0 for (n in 1:N) { rMe <- rMe+M nchleaf <- (M*(n-1)+1):(n*M)*chleaf[(M*(n-1)+1):(n*M)] xupdates <- nchleaf[which(nchleaf!=0)] yupdates <- as.vector(sapply(y[n], function(x){rep(x,length(xupdates))})) outlist[[i]] <- outlist[[i]] %>% plotly::add_trace(x = c(M*(n-1), n*M), y = c(y[n], y[n]), type = 'scatter', mode='lines', showlegend=ifelse((i==1 && n==1), TRUE, FALSE), name='y', line=list(color = cols[6], dash = ifelse(M==1, 'solid', 'dash'), width=0.5)) %>% plotly::add_trace(x = xupdates, y = yupdates, type='scatter', mode='markers', showlegend=ifelse((i==2&&n==1), TRUE, FALSE), name='Update', color=I(cols[5]), size=0.5) %>% plotly::add_trace(x = rMe, y = mgrid, type = 'scatter', mode='lines', visible=ifelse(trials==1, TRUE, FALSE), showlegend=ifelse((trials==1 && i==1 && n==1), TRUE, FALSE), name='Trial', line=list(color = cols[8], dash = 'dash', width=0.5)) } i <- i+1 } # 添加shareY=TRUE,强制共享Y轴 fig <- plotly::subplot(outlist, nrows=length(nplots), shareX=TRUE, shareY=TRUE, which_layout=c(1)) %>% plotly::config(staticPlot=T, mathjax='cdn', displayModeBar = F) fig <- fig %>% plotly::layout( showlegend=TRUE, legend=list(itemsizing='trace', orientation='h', xanchor='center', x=0.5), margin=list(b=70, l=45, r=30, t=80), title=list(text="Test Title") )
内容的提问来源于stack exchange,提问作者Fatm
相关产品推荐
相关产品推荐

