使用rpy2+Streamlit构建应用时的PCA可视化报错求助
问题:Streamlit中使用rpy2调用R的FactoMineR绘制PCA方差直方图报错
我尝试用Python和rpy2构建应用,读取名为table_mean_plain.csv的文件后绘制PCA解释方差百分比的直方图,代码在Jupyter Notebook中运行正常,但在Streamlit中加载超时,且出现如下报错:
2022-10-25 17:08:05.231 Uncaught app exception Traceback (most recent call last): File "/opt/anaconda3/envs/XX/lib/python3.9/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 562, in _run_script exec(code, module.__dict__) File "/Users/XX/Documents/XX/pages/4_Visualisations.py", line 69, in <module> res_pca = FactoMineR.PCA(my_data) File "/opt/anaconda3/envs/XX/lib/python3.9/site-packages/rpy2/robjects/functions.py", line 201, in __call__ return (super(SignatureTranslatedFunction, self) File "/opt/anaconda3/envs/XX/lib/python3.9/site-packages/rpy2/robjects/functions.py", line 124, in __call__ res = super(Function, self).__call__(*new_args, **new_kwargs) File "/opt/anaconda3/envs/XX/lib/python3.9/site-packages/rpy2/rinterface_lib/conversion.py", line 45, in _ cdata = function(*args, **kwargs) File "/opt/anaconda3/envs/XX/lib/python3.9/site-packages/rpy2/rinterface.py", line 810, in __call__ raise embedded.RRuntimeError(_rinterface._geterrmessage()) rpy2.rinterface_lib.embedded.RRuntimeError: 在函数(...)中出错:无法创建目标设备quartz(),提供的类型可能不被支持 Assertion failed: (NSViewIsCurrentlyBuildingLayerTreeForDisplay() != currentlyBuildingLayerTree), function NSViewSetCurrentlyBuildingLayerTreeForDisplay, file NSView.m, line 13477. [9] 59974 illegal hardware instruction streamlit run 1_Workbench.py
原代码
from rpy2.robjects.packages import importr, data from rpy2.robjects.vectors import DataFrame from rpy2.ipython.ggplot import image_png import streamlit as st import matplotlib.pyplot as plt from rpy2 import robjects import matplotlib.image as mpimg utils = importr('utils') corrplot = importr('corrplot') FactoMineR = importr('FactoMineR') factoextra = importr('factoextra') my_datafile = 'table/plain/table_mean_plain.csv' #my_data = utils.read_csv(my_datafile) my_data = DataFrame.from_csvfile(my_datafile, row_names="X") #rownames(my_data = my_data$X #my_dataX = NULL # Do PCA # -------- res_pca = FactoMineR.PCA(my_data) # Eigen values / Variance # -------- eig_val = factoextra.get_eigenvalue(res_pca) st.pyplot(display(image_png(factoextra.fviz_eig(res_pca, addlabels = True))))
对应的CSV文件内容
,logistic-regression,svm-linear,svm-rbf,Gnb,decision-tree,random-forest,XGBoost,MLP,Ensemble,GEV,iForest,DevNet news,0.827,0.566,0.724,0.681,0.687,0.852,0.865,0.859,0.866,0.87,0.497,0.666 telE,0.761,0.552,0.623,0.756,0.86,0.944,0.957,0.915,0.95,0.941,0.399,0.717 bank,0.832,0.62,0.772,0.817,0.687,0.848,0.841,0.848,0.855,0.873,0.625,0.793 member,0.648,0.488,0.514,0.625,0.574,0.696,0.695,0.669,0.707,0.667,0.545,0.598 dsn,0.735,0.708,0.785,0.707,0.761,0.884,0.897,0.754,0.884,0.766,0.568,0.661 mobile,0.889,0.432,0.393,0.842,0.776,0.9,0.906,0.9,0.908,0.907,0.7,0.852 campaign,0.907,0.543,0.668,0.809,0.709,0.928,0.933,0.923,0.935,0.924,0.65,0.832 HR,0.85,0.766,0.841,0.762,0.615,0.809,0.797,0.825,0.838,0.827,0.589,0.72 sato,0.794,0.747,0.8,0.729,0.651,0.808,0.809,0.799,0.825,0.82,0.5,0.739 uci,0.854,0.586,0.897,0.859,0.818,0.901,0.905,0.847,0.913,0.91,0.663,0.793 TelC,0.844,0.632,0.797,0.814,0.658,0.819,0.825,0.842,0.841,0.85,0.295,0.784 median_AUC,0.832,0.586,0.772,0.762,0.687,0.852,0.866,0.847,0.866,0.87,0.568,0.739 Rank,5.67,10.67,7.5,8.08,9.0,4.0,3.25,5.0,1.83,2.67,11.42,8.92
问题原因
报错核心是R在Streamlit的无GUI服务器环境下无法创建默认的quartz绘图设备:Jupyter Notebook运行在有桌面GUI的交互式环境中,支持quartz设备;但Streamlit是服务器端运行,没有桌面图形环境,导致R无法初始化绘图设备,进而触发报错。
修复方案
1. 配置R使用非交互式绘图设备
在代码开头添加配置,强制R使用适用于无GUI环境的png设备(底层基于Agg),避免quartz设备的依赖:
from rpy2 import robjects robjects.r(''' options(device = "png") ''')
2. 调整Streamlit的图像显示逻辑
原代码中st.pyplot(display(image_png(...)))的用法错误:display()是IPython的交互显示函数,Streamlit不支持;直接用st.image()接收image_png()返回的字节流即可正确显示图像。
3. 可选:改用Pandas读取数据(提升兼容性)
rpy2内置的DataFrame.from_csvfile在部分场景下存在兼容性问题,改用Pandas读取CSV后转为R对象,稳定性更好:
import pandas as pd from rpy2.robjects import pandas2ri pandas2ri.activate() df = pd.read_csv(my_datafile, index_col=0) my_data = pandas2ri.py2rpy(df)
修改后的完整代码
from rpy2.robjects.packages import importr from rpy2.ipython.ggplot import image_png import streamlit as st from rpy2 import robjects import pandas as pd from rpy2.robjects import pandas2ri # 激活Pandas与R对象的转换 pandas2ri.activate() # 设置R使用非交互式绘图设备,避免quartz报错 robjects.r(''' options(device = "png") ''') # 导入所需R包 FactoMineR = importr('FactoMineR') factoextra = importr('factoextra') my_datafile = 'table/plain/table_mean_plain.csv' # 用Pandas读取CSV并转为R的DataFrame df = pd.read_csv(my_datafile, index_col=0) my_data = pandas2ri.py2rpy(df) # 执行PCA分析 res_pca = FactoMineR.PCA(my_data) # 生成方差解释直方图并在Streamlit中显示 img_bytes = image_png(factoextra.fviz_eig(res_pca, addlabels = True)) st.image(img_bytes)
内容的提问来源于stack exchange,提问作者glouis
相关产品推荐
相关产品推荐

