Plotly子图添加背景矩形后消除第二子图白边与白区
Plotly子图样式修复方案
问题说明
使用Plotly构建带矩形背景的子图时,遇到两个样式问题:
- 第二张子图x轴上方存在白色线条
- 第二张子图y轴附近有未被背景覆盖的白色区域
原实现代码如下:
import pandas as pd def save_fig(fig,pngname): fig.write_image(pngname,format="png",width=600,height=400, scale=1) print("[[%s]]"%pngname) #fig.show() return from plotly.subplots import make_subplots import plotly.graph_objects as go def plot(df1,df2,pngname): title = "my title" xlabel = "x1" ylabel = "y" xlabel2 = "x2" color = "blue" df2 = df2[df2['ts'].diff()>=0] fig = make_subplots( #x_title=xlabel, y_title=ylabel, rows=1, cols=2, column_widths=[0.80,0.20], row_heights=[1], shared_yaxes=True, horizontal_spacing=0) fig.add_trace( go.Scattergl( x=df1['name'], y=df1['value'], error_y=error_bar(df1['value']), marker=dict(color=color,size=1), mode='markers'), row=1, col=1) update_axis(fig,xlabel,1,1) add_bgcolor(fig) fig.add_trace( go.Scattergl( x=df2['value'], y=df2['ts'], error_x=error_bar(df2['value']), marker=dict(color=color,size=.1), #fill='tozeroy', mode='markers'), row=1, col=2) update_axis(fig,xlabel2,1,2) fig.update_layout( title_text=title, showlegend=False, legend=dict(y=1, x=0.1), margin=dict(l=40,t=40,r=0,b=0), title_x=0.5, #title_y=1, paper_bgcolor='white', plot_bgcolor='white', ) save_fig(fig,pngname) return def add_bgcolor(fig): bgcolor=dict( type="rect", xref="x2", yref="paper", x0=0, y0=0, x1=100, y1=1, fillcolor="pink", opacity=0.5, layer="below", line_width=0, ) fig.add_shape(bgcolor) return def error_bar(arrayminus): error=dict( type='data', symmetric=False, arrayminus=arrayminus, array=[0] * len(arrayminus), thickness=5, width=0, ) return error def update_axis(fig,xlabel,row,col): fig.update_xaxes( title=xlabel, tickangle=25, side='bottom', showline=True, linewidth=.5, linecolor='black', gridcolor="rgba(38,38,38,0.15)",row=row,col=col ) fig.update_yaxes( automargin=True, side="left", showline=True, linewidth=.5, linecolor='black', gridcolor="rgba(38,38,38,0.15)",row=row,col=col ) return def main(): data1 = [ ['AAA',10], ['BBB',20], ['CCC',30], ['DDD',40], ['EEE',50], ] df1 = pd.DataFrame(data1,columns=['name','value']) data2 = [ [30,10], [40,20], [50,30], [60,40], [70,50] ] df2 = pd.DataFrame(data2,columns=['ts','value']) pngname = "/media/sf_work/demo.png" plot(df1,df2,pngname) return main()
修复方案
1. 移除第二张子图x轴上方的白色线条
原update_axis函数对所有子图的x轴启用了showline=True,这会同时显示x轴的上下边框。我们需要单独对第二张子图的x轴设置showtop=False,只保留底部轴线:
在调用update_axis(fig,xlabel2,1,2)之后,添加以下代码:
# 隐藏第二张子图x轴顶部的线条 fig.update_xaxes(showtop=False, row=1, col=2)
2. 移除第二张子图y轴附近的白色区域
该区域是因为第二张子图的y轴默认边距导致的,结合shared_yaxes=True,我们可以直接隐藏第二张子图的y轴,同时调整背景矩形的参考系,让它完全覆盖第二张子图的绘图区域:
修改点1:隐藏第二张子图的y轴
同样在调用update_axis(fig,xlabel2,1,2)之后添加:
# 隐藏第二张子图的y轴,消除左侧白色区域 fig.update_yaxes(visible=False, row=1, col=2)
修改点2:调整背景矩形的参考范围
修改add_bgcolor函数,将xref改为domain参考系,确保背景覆盖整个第二张子图的宽度:
def add_bgcolor(fig): bgcolor=dict( type="rect", xref="domain", # 修改为domain参考系,覆盖第二张子图的整个宽度 yref="paper", x0=0.8, # 对应column_widths中的0.8,即第二张子图的起始位置 y0=0, x1=1, y1=1, fillcolor="pink", opacity=0.5, layer="below", line_width=0, ) fig.add_shape(bgcolor) return
完整修复后代码
import pandas as pd def save_fig(fig,pngname): fig.write_image(pngname,format="png",width=600,height=400, scale=1) print("[[%s]]"%pngname) #fig.show() return from plotly.subplots import make_subplots import plotly.graph_objects as go def plot(df1,df2,pngname): title = "my title" xlabel = "x1" ylabel = "y" xlabel2 = "x2" color = "blue" df2 = df2[df2['ts'].diff()>=0] fig = make_subplots( #x_title=xlabel, y_title=ylabel, rows=1, cols=2, column_widths=[0.80,0.20], row_heights=[1], shared_yaxes=True, horizontal_spacing=0) fig.add_trace( go.Scattergl( x=df1['name'], y=df1['value'], error_y=error_bar(df1['value']), marker=dict(color=color,size=1), mode='markers'), row=1, col=1) update_axis(fig,xlabel,1,1) add_bgcolor(fig) fig.add_trace( go.Scattergl( x=df2['value'], y=df2['ts'], error_x=error_bar(df2['value']), marker=dict(color=color,size=.1), #fill='tozeroy', mode='markers'), row=1, col=2) update_axis(fig,xlabel2,1,2) # 修复问题1:隐藏第二张子图x轴顶部线条 fig.update_xaxes(showtop=False, row=1, col=2) # 修复问题2:隐藏第二张子图y轴,消除左侧白色区域 fig.update_yaxes(visible=False, row=1, col=2) fig.update_layout( title_text=title, showlegend=False, legend=dict(y=1, x=0.1), margin=dict(l=40,t=40,r=0,b=0), title_x=0.5, #title_y=1, paper_bgcolor='white', plot_bgcolor='white', ) save_fig(fig,pngname) return def add_bgcolor(fig): bgcolor=dict( type="rect", xref="domain", # 修改为domain参考系,覆盖第二张子图整个宽度 yref="paper", x0=0.8, # 对应column_widths的0.8,第二张子图起始位置 y0=0, x1=1, y1=1, fillcolor="pink", opacity=0.5, layer="below", line_width=0, ) fig.add_shape(bgcolor) return def error_bar(arrayminus): error=dict( type='data', symmetric=False, arrayminus=arrayminus, array=[0] * len(arrayminus), thickness=5, width=0, ) return error def update_axis(fig,xlabel,row,col): fig.update_xaxes( title=xlabel, tickangle=25, side='bottom', showline=True, linewidth=.5, linecolor='black', gridcolor="rgba(38,38,38,0.15)",row=row,col=col ) fig.update_yaxes( automargin=True, side="left", showline=True, linewidth=.5, linecolor='black', gridcolor="rgba(38,38,38,0.15)",row=row,col=col ) return def main(): data1 = [ ['AAA',10], ['BBB',20], ['CCC',30], ['DDD',40], ['EEE',50], ] df1 = pd.DataFrame(data1,columns=['name','value']) data2 = [ [30,10], [40,20], [50,30], [60,40], [70,50] ] df2 = pd.DataFrame(data2,columns=['ts','value']) pngname = "/media/sf_work/demo.png" plot(df1,df2,pngname) return main()
内容的提问来源于stack exchange,提问作者lucky1928
相关产品推荐
相关产品推荐

