簡體   English   中英

有沒有辦法在 matplotlib 中標記多個 3d 表面?

[英]Is there a way to label multiple 3d surfaces in matplotlib?

我試圖用線性約束解決非線性數學優化問題。 為此,我試圖在 3d 中可視化約束以了解正在發生的事情以及為什么我為約束中的某些參數而不是其他參數獲得了可行的解決方案。

為了實現這一點,我想使用 python 中的matplotlib來生成 3d 表面(平面,因為我的所有約束都是線性的)。

但是,如果沒有圖內標記,則很難確定哪個曲面屬於哪個約束。 這讓我想尋找一種方法來在情節內添加帶有顏色的圖例。

我認識到已經有一種方法可以在 2D 中執行此操作,在方法ax.plot()ax.scatter() ,但是嘗試執行相同操作對ax.plot_surface(X, Y, Z, label = 'mylabel')

完整腳本如下:


from mpl_toolkits import mplot3d
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np


fig = plt.figure()
ax = plt.axes(projection='3d')

plt.rcParams['legend.fontsize'] = 10


# First constraint
g2 = np.linspace(-5,5,2)
g3 = np.linspace(-5,5,2)
G2,G3 = np.meshgrid(g2,g3)
G4_1 = -1.18301270189222 - 0.5*G2 + 0.5*G3
ax = fig.gca(projection='3d')
c1 = ax.plot_surface(G2, G3, G4_1, label = "c1")

# Second
G3, G4 = np.meshgrid(g2, g3)
G2 = G3
c2 = ax.plot_surface(G2, G3, G4, label = "c2")

# Third
G2,G3 = np.meshgrid(g2,g3)
G4 = (0.408248290463863*G2 + 0.408248290463863*G3 -0.707106781186548)/1.63299316185545
c3 = ax.plot_surface(G2, G3, G4, label = "c3")

# And forth
G4 = (1.04903810567666 - (0.288675134594813*G2 + 0.288675134594813*G3))/0.577350269189626
c4 = ax.plot_surface(G2, G3, G4, label="c4")



ax.legend() # -> error : 'AttributeError: 'Poly3DCollection' object has no attribute '_edgecolors2d''


# labeling the figure
fig.suptitle("Constraints")
#plt.xlabel('g2', fontsize=14)
#plt.ylabel('g3', fontsize=14)
ax.set_xlabel(r'$g_2$', fontsize=15, rotation=60)
ax.set_ylabel('$g_3$', fontsize=15, rotation=60)
ax.set_zlabel('$g_4$', fontsize=15, rotation=60)
plt.savefig('Constraints.jpg')
plt.show()

結果如下圖。

陰謀

正如您可能已經看到的那樣,無法分辨哪個表面屬於哪個約束,而我想要實現的是一個圖例,就像這里

我通讀了這個問題的答案,但它在這里不起作用,因為我有多個表面。 嘗試后,它一直只顯示一個標簽,而不是四個。

所以我的問題是,有沒有辦法向我的ax.plot_surface或任何其他合適的黑客添加圖例?

你去吧。

解決方案是這里的錯誤: ax.legend() # -> error : 'AttributeError: 'Poly3DCollection' object has no attribute '_edgecolors2d''
我相信這是一個錯誤。

如果您探索任何表面對象(例如c1 ),您可以看到它們具有屬性'_edgecolors3d' ,這是創建圖例時應調用的屬性。

因此,我們只需創建一個名為'_edgecolors2d'的新屬性,其內容與'_edgecolors3d'相同。

一旦解決了'_edgecolors2d'問題,您將遇到一個帶有'_facecolors2d'的新問題。 我們重復相同的程序,我們就完成了。


fig = plt.figure()
ax = plt.axes(projection='3d')

plt.rcParams['legend.fontsize'] = 10


# First constraint
g2 = np.linspace(-5,5,2)
g3 = np.linspace(-5,5,2)
G2,G3 = np.meshgrid(g2,g3)
G4_1 = -1.18301270189222 - 0.5*G2 + 0.5*G3
ax = fig.gca(projection='3d')
c1 = ax.plot_surface(G2, G3, G4_1, label = "c1")
c1._facecolors2d=c1._facecolors3d
c1._edgecolors2d=c1._edgecolors3d

# Second
G3, G4 = np.meshgrid(g2, g3)
G2 = G3
c2 = ax.plot_surface(G2, G3, G4, label = "c2")
c2._facecolors2d=c2._facecolors3d
c2._edgecolors2d=c2._edgecolors3d

# Third
G2,G3 = np.meshgrid(g2,g3)
G4 = (0.408248290463863*G2 + 0.408248290463863*G3 -0.707106781186548)/1.63299316185545
c3 = ax.plot_surface(G2, G3, G4, label = "c3")
c3._facecolors2d=c3._facecolors3d
c3._edgecolors2d=c3._edgecolors3d

# And forth
G4 = (1.04903810567666 - (0.288675134594813*G2 + 0.288675134594813*G3))/0.577350269189626
c4 = ax.plot_surface(G2, G3, G4, label="c4")

c4._facecolors2d=c4._facecolors3d
c4._edgecolors2d=c4._edgecolors3d

ax.legend() # -> error : 'AttributeError: 'Poly3DCollection' object has no attribute '_edgecolors2d''


# labeling the figure
fig.suptitle("Constraints")
#plt.xlabel('g2', fontsize=14)
#plt.ylabel('g3', fontsize=14)
ax.set_xlabel(r'$g_2$', fontsize=15, rotation=60)
ax.set_ylabel('$g_3$', fontsize=15, rotation=60)
ax.set_zlabel('$g_4$', fontsize=15, rotation=60)
plt.savefig('Constraints.jpg')
plt.show()

輸出

這是對@Gio 答案的更新。 matplotlib 3.3.3_facecolors3d_edgecolors3d不存在。 所以,而不是這個:

c1._facecolors2d = c1._facecolors3d
c1._edgecolors2d = c1._edgecolors3d

這會導致類似的AttributeError ,試試這個:

c1._facecolors2d = c1._facecolor3d
c1._edgecolors2d = c1._edgecolor3d

由於低代表,我不得不將其作為答案,而不是評論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM