Streamlit中图例尺寸适配求助:自定义滚动功能部署后失效
问题:Matplotlib滚动图例在Streamlit部署后失效
本地使用Matplotlib绘制饼图时,针对大量取值的图例实现了鼠标滚轮滚动功能,本地运行正常,但部署到Streamlit后,图例始终完整显示在页面上,无法截断启用滚动,调整图表和图例尺寸后问题仍未解决,图例已延伸至页面下方。
相关代码
fig1 = plt.figure(figsize=(7, 3)) axx = fig.add_axes([0.1, 0.6, 0.3, 0.3]) p1 = volcanos["Country"].value_counts() fig1, axx = plt.subplots() axx.pie(p1, labels=p1.keys(), autopct='%1.1f%%', shadow=True, startangle=90) legend = axx.legend(loc="upper left", bbox_to_anchor=(1.02, 0, 0.07, 1)) # pixels to scroll per mousewheel event d = {"down" : 30, "up" : -30} def func(evt): if legend.contains(evt): bbox = legend.get_bbox_to_anchor() bbox = Bbox.from_bounds(bbox.x0, bbox.y0+d[evt.button], bbox.width, bbox.height) tr = legend.axes.transAxes.inverted() legend.set_bbox_to_anchor(bbox.transformed(tr)) fig1.canvas.draw_idle() fig1.canvas.mpl_connect("scroll_event", func) st.pyplot(fig1)
原因分析
Streamlit的st.pyplot()并非直接渲染Matplotlib的交互式canvas,而是将其转换为静态图像或简化渲染层,导致你绑定的scroll_event这类Matplotlib原生交互事件无法触发,动态调整图例bbox的逻辑也无法生效。
解决方案
方案1:改用Plotly实现带滚动图例的饼图
Plotly的图例原生支持滚动,且在Streamlit中兼容性良好,无需手动绑定事件:
import plotly.express as px import streamlit as st # 处理数据格式 p1 = volcanos["Country"].value_counts().reset_index() p1.columns = ["Country", "Count"] # 绘制饼图并配置滚动图例 fig = px.pie(p1, values='Count', names='Country', title='火山分布按国家统计') fig.update_layout( legend=dict( yanchor="top", y=0.99, xanchor="left", x=1.02, bgcolor="white", bordercolor="black", borderwidth=1, height=400 # 限制图例高度,超出部分自动出现滚动条 ) ) st.plotly_chart(fig, use_container_width=True)
方案2:用mpld3将Matplotlib交互图嵌入Streamlit
通过mpld3将Matplotlib图转换为带交互的HTML,再用Streamlit的组件嵌入,保留原有的滚轮滚动逻辑:
import mpld3 import streamlit as st import matplotlib.pyplot as plt from matplotlib.transforms import Bbox # 数据处理 p1 = volcanos["Country"].value_counts() # 绘制饼图并绑定滚动事件 fig1, axx = plt.subplots(figsize=(7, 3)) axx.pie(p1, labels=p1.keys(), autopct='%1.1f%%', shadow=True, startangle=90) legend = axx.legend(loc="upper left", bbox_to_anchor=(1.02, 0, 0.07, 1)) d = {"down" : 30, "up" : -30} def func(evt): if legend.contains(evt): bbox = legend.get_bbox_to_anchor() bbox = Bbox.from_bounds(bbox.x0, bbox.y0+d[evt.button], bbox.width, bbox.height) tr = legend.axes.transAxes.inverted() legend.set_bbox_to_anchor(bbox.transformed(tr)) fig1.canvas.draw_idle() fig1.canvas.mpl_connect("scroll_event", func) # 转换为交互式HTML并嵌入 html_str = mpld3.fig_to_html(fig1) st.components.v1.html(html_str, height=600, scrolling=True)
注意:需先安装mpld3(pip install mpld3),部分环境可能存在兼容性差异。
方案3:用Streamlit滑块模拟图例滚动
通过滑块控制图例的垂直偏移,静态更新图表来模拟滚动效果:
import streamlit as st import matplotlib.pyplot as plt from matplotlib.transforms import Bbox p1 = volcanos["Country"].value_counts() # 添加滑块控制图例偏移 y_offset = st.slider("调整图例位置", min_value=-len(p1)*10, max_value=0, value=0, step=10) # 绘制饼图并应用偏移 fig1, axx = plt.subplots(figsize=(7, 3)) axx.pie(p1, labels=p1.keys(), autopct='%1.1f%%', shadow=True, startangle=90) legend = axx.legend(loc="upper left", bbox_to_anchor=(1.02, y_offset/100, 0.07, 1)) st.pyplot(fig1)
内容的提问来源于stack exchange,提问作者Conor Segreti
相关产品推荐
相关产品推荐

