Matplotlib Mplot3d plot_surface报错:'list'无'ndim'属性求助
解决
plot_surface的AttributeError及代码逻辑问题 首先,咱们先拆解你遇到的问题:AttributeError: 'list' object has no attribute 'ndim'是因为matplotlib的plot_surface函数要求Z必须是二维numpy数组,但你现在传入的Z是一维列表,同时你的循环逻辑还有几个小错误,导致数据结构完全不符合3D绘图的要求。
问题点逐一修复
循环逻辑错误
- 内层循环你写的是
for j in (0,80,5),这是一个只有3个元素的元组,不是你想要的从0到80步长5的序列,应该改成range(0,80,5)。 - 内层循环里你把NH4的 uptake设成了
-i,这会导致内层循环中NH4的取值不会变化,应该改成-j。 - 每次修改反应的上下界后,你没有重新调用
model.optimize(),所以solution.f一直是最开始的计算结果,不会随边界变化更新。
- 内层循环你写的是
Z数组结构错误
当前你的growth_rate是一维列表,但meshgrid生成的X和Y是二维数组,所以Z必须是对应的二维结构。我们可以把growth_rate改成二维列表,每次内层循环结束后,把当前这一组的生长率添加进去,最后再转成numpy数组。
修改后的完整代码
import cobra import os from os.path import join import matplotlib.pyplot as plt import numpy as np from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D data_dir ='/Users/stephenchapman/Documents/research/FBA_algae_digesate/COBRApy/iCZ843/iCZ843_models' model = cobra.io.read_sbml_model(join(data_dir, "iCZ843_hetero.xml")) # 设置反应边界 model.reactions[15].upper_bound = 0 #ammonia model.reactions[15].lower_bound = -98.3 model.reactions[27].upper_bound = 0 #acetate model.reactions[27].lower_bound = -3.3 model.reactions[14].upper_bound = 0 #phosphate model.reactions[14].lower_bound = -10 model.reactions[16].upper_bound = 0 #nitrate model.reactions[16].lower_bound = -30.3 model.reactions[20].upper_bound = 0 #magnesium model.reactions[20].lower_bound = -0.56 model.reactions[18].upper_bound = 0 #iron model.reactions[18].lower_bound = -2.16 model.objective = model.reactions[63] # 先优化一次初始状态 solution = model.optimize() model.summary() # 改成二维列表存储生长率 growth_rate = [] ac_uptake_range = range(0,85,5) nh4_uptake_range = range(0,80,5) for i in ac_uptake_range: # 设置acetate的uptake model.reactions[27].lower_bound = -i model.reactions[27].upper_bound = -i # 存储当前acetate对应的所有生长率 current_growth = [] for j in nh4_uptake_range: # 设置NH4的uptake,这里用j而不是i! model.reactions[15].lower_bound = -j model.reactions[15].upper_bound = -j # 重新优化模型 solution = model.optimize() current_growth.append(solution.f) # 将当前组的生长率添加到二维列表 growth_rate.append(current_growth) # 转换为numpy数组 X, Y = np.meshgrid(list(ac_uptake_range), list(nh4_uptake_range)) Z = np.array(growth_rate) fig = plt.figure() ax = Axes3D(fig) ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.viridis) # 可以加上轴标签让图更清晰 ax.set_xlabel('Acetate Uptake') ax.set_ylabel('NH4 Uptake') ax.set_zlabel('Growth Rate') plt.show()
额外说明
- 我把
ac_uptake和NH4_uptake的列表换成了直接用range对象,这样更简洁,也避免重复创建列表。 - 添加了轴标签,让你的3D图更容易理解。
- 注意我把反应的
upper_bound从-0改成了0,因为-0和0在数值上没有区别,这样写更规范。
内容的提问来源于stack exchange,提问作者Stephen Chapman
相关产品推荐
相关产品推荐

