Matplotlib绘图仅返回Line2D对象无图形显示问题求助
问题解决:Matplotlib图形无法显示的修复
问题描述
定义efficient_frontier函数返回Matplotlib的axes对象,在该对象上添加新元素后执行绘图,仅输出<matplotlib.lines.Line2D at 0x273b82d3f50>,图形无法正常显示。环境为Python 3.11,已配置%matplotlib inline并导入matplotlib.pyplot。
核心错误分析
- 未定义标识符错误:代码中
w_msr=erk.msr_weight(er, cov,rf)一行使用了未定义的erk前缀,实际应为直接调用自定义的msr_weight函数,该错误会导致代码中断,后续绘图逻辑无法执行。 - 函数注释与实际返回值不符:
efficient_frontier函数注释标注返回DataFrame,但实际返回的是绘图的axes对象,虽不影响功能,但易造成混淆。
修正后的完整代码
import akshare as ak import pandas as pd import numpy as np from scipy.optimize import minimize %matplotlib inline import matplotlib.pyplot as plt def get_ind_returns(symbol_list,start_date,end_date): """ 使用akshare工具获取行业指数收益率 参数: symbol_list: 行业名称列表 start_date: 起始日期 end_date: 结束日期 返回: 以行业指数为列的收益率DataFrame """ stock_board_industry_index=ak.stock_board_industry_index_ths(symbol=symbol_list[0] , start_date=start_date, end_date=end_date)["日期"].to_frame() for i in range(len(symbol_list)): stock_board_industry_index_pct=ak.stock_board_industry_index_ths(symbol=symbol_list[i] , start_date=start_date, end_date=end_date)["收盘价"].pct_change() stock_board_industry_index.insert(i+1,symbol_list[i],stock_board_industry_index_pct,True) stock_board_industry_index.index=pd.to_datetime(stock_board_industry_index['日期'],format='%Y%m%d') stock_board_industry_index.drop("日期",axis=1,inplace=True) return stock_board_industry_index def annualized_returns(returns,periods_per_year): """ 计算年化收益率 参数: returns: 收益率序列 periods_per_year: 每年的周期数(日频为365,月频为12) 返回: 年化收益率 """ compound_growth_rate=(1+returns).prod() n_of_periods=returns.shape[0] annualized_return=(compound_growth_rate**(periods_per_year/n_of_periods)-1) return annualized_return def portfolio_return(weights,returns): """ 计算组合收益率 参数: weights: 资产权重数组 returns: 资产预期收益率数组 返回: 组合收益率 """ return weights.T @ returns def portfolio_vol(weights,cov_matrix): """ 计算组合波动率 参数: weights: 资产权重数组 cov_matrix: 资产协方差矩阵 返回: 组合波动率 """ return (weights.T @ cov_matrix @ weights)**0.5 def minimize_vol_weight(target_return,er,cov): """ 给定目标收益率,求解最小波动率对应的资产权重 参数: target_return: 目标组合收益率 er: 资产预期收益率数组 cov: 资产协方差矩阵 返回: 最小波动率对应的权重数组 """ n=er.shape[0] initial_guess=np.repeat(1/n,n) bounds=((0,1),)*n return_is_target={ 'type':'eq', 'args':(er,), 'fun':lambda weights,er:target_return-portfolio_return(weights, er) } weights_sum_to_1={ 'type':'eq', 'fun':lambda weights:np.sum(weights)-1 } minimize_result=minimize(portfolio_vol,initial_guess,args=(cov,) ,method="SLSQP",bounds=bounds, constraints=([return_is_target,weights_sum_to_1]), options={'disp':False} ) return minimize_result.x def optimal_weights(er,cov,n_points): """ 生成一系列目标收益率对应的最优权重列表 参数: er: 资产预期收益率数组 cov: 资产协方差矩阵 n_points: 绘图的点数 返回: 各目标收益率对应的最优权重列表 """ target_returns=np.linspace(er.min(),er.max(),n_points) optimal_weights=[minimize_vol_weight(target_return, er, cov) for target_return in target_returns] return optimal_weights def efficient_frontier(er,cov,n_points,style=".-"): """ 绘制多资产有效前沿,并返回绘图的axes对象 参数: er: 资产预期收益率数组 cov: 资产协方差矩阵 n_points: 绘图的点数 style: 绘图样式 返回: 绘图的Matplotlib axes对象 """ weights=optimal_weights(er,cov,n_points) rets=[portfolio_return(w ,er) for w in weights] vols=[portfolio_vol(w, cov) for w in weights] ef_df=pd.DataFrame({'Weights':weights,'R':rets,"Vol":vols}) return ef_df.plot.line(x="Vol", y="R", style=style) def msr_weight(er,cov,riskfree_rate): """ 求解最大夏普比率对应的资产权重 参数: er: 资产预期收益率数组 cov: 资产协方差矩阵 riskfree_rate: 无风险收益率 返回: 最大夏普比率对应的权重数组 """ n=er.shape[0] initial_guess=np.repeat(1/n,n) bounds=((0,1),)*n weights_sum_to_1={ 'type':'eq', 'fun':lambda weights:np.sum(weights)-1 } negative_sharpe= lambda weights,riskfree_rate,er,cov: -(portfolio_return(weights, er)-riskfree_rate)/portfolio_vol(weights, cov) msr_result=minimize(negative_sharpe,initial_guess,args=(riskfree_rate,er,cov,) ,method="SLSQP",bounds=bounds, constraints=(weights_sum_to_1), options={'disp':False} ) return msr_result.x # 主逻辑 symbol_list=['半导体及元件','房地产开发','消费电子','油气开采及服务','银行'] ind=get_ind_returns(symbol_list, '20150101', '20240108') er=annualized_returns(ind["2010":"2024"], 365) cov=ind.cov() rf=0.03 # 修正:直接调用自定义的msr_weight函数 w_msr=msr_weight(er, cov,rf) ax=efficient_frontier(er, cov, 20) ax.set_xlim(left=0) r_msr=portfolio_return(w_msr,er) vol_msr=portfolio_vol(w_msr, cov) # 绘制资本市场线(CML) cml_x=[0,vol_msr] cml_y=[rf, r_msr] ax.plot(cml_x,cml_y,color='green',marker='o',linestyle='dashed',linewidth=2,markersize=12) plt.show()
其他注意事项
- 确保akshare库已正确安装并能正常获取数据,若数据获取失败,需检查网络连接或akshare的版本兼容性。
- 在Jupyter环境中,
%matplotlib inline需放在导入matplotlib.pyplot之前执行,确保绘图能嵌入单元格显示。
内容的提问来源于stack exchange,提问作者Chen LIU
相关产品推荐
相关产品推荐

