matplotlib (동일한 단위 길이) : '동일한'종횡비 사용 z 축이 x 및 y-와 같지 않음
3D 그래프에 대해 동일한 종횡비를 설정하면 z 축이 '동일'로 변경되지 않습니다. 그래서 이거:
fig = pylab.figure()
mesFig = fig.gca(projection='3d', adjustable='box')
mesFig.axis('equal')
mesFig.plot(xC, yC, zC, 'r.')
mesFig.plot(xO, yO, zO, 'b.')
pyplot.show()
나에게 다음을 제공합니다.
분명히 z 축의 단위 길이는 x 및 y 단위와 같지 않습니다.
세 축의 단위 길이를 어떻게 동일하게 만들 수 있습니까? 내가 찾을 수있는 모든 솔루션이 작동하지 않았습니다. 감사합니다.
나는 matplotlib가 아직 3D에서 정확하게 동일한 축을 설정하지 않았다고 생각합니다.하지만 몇 번 전에 그것을 사용하여 적응 한 트릭을 발견했습니다 (어디가 기억 나지 않습니다). 개념은 데이터 주위에 가짜 큐빅 경계 상자를 만드는 것입니다. 다음 코드로 테스트 할 수 있습니다.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
# Create cubic bounding box to simulate equal aspect ratio
max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max()
Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() + 0.5*(X.max()+X.min())
Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() + 0.5*(Y.max()+Y.min())
Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() + 0.5*(Z.max()+Z.min())
# Comment or uncomment following both lines to test the fake bounding box:
for xb, yb, zb in zip(Xb, Yb, Zb):
ax.plot([xb], [yb], [zb], 'w')
plt.grid()
plt.show()
z 데이터는 x 및 y보다 약 10 배 더 크지 만 동일한 축 옵션을 사용하더라도 matplotlib 자동 크기 조정 z 축 :
그러나 경계 상자를 추가하면 올바른 배율을 얻을 수 있습니다.
set_x/y/zlim
함수 를 사용하여 Remy F의 솔루션을 단순화했습니다 .
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max() / 2.0
mid_x = (X.max()+X.min()) * 0.5
mid_y = (Y.max()+Y.min()) * 0.5
mid_z = (Z.max()+Z.min()) * 0.5
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
ax.set_zlim(mid_z - max_range, mid_z + max_range)
plt.show()
위의 솔루션이 마음에 들지만 모든 데이터에 대한 범위와 평균을 추적하는 데 필요한 단점이 있습니다. 함께 그려 질 데이터 세트가 여러 개인 경우 이는 번거로울 수 있습니다. 이 문제를 해결하기 위해 ax.get_ [xyz] lim3d () 메서드를 사용하고 plt.show ()를 호출하기 전에 한 번만 호출 할 수있는 독립형 함수에 모든 것을 넣었습니다. 다음은 새 버전입니다.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
def set_axes_equal(ax):
'''Make axes of 3D plot have equal scale so that spheres appear as spheres,
cubes as cubes, etc.. This is one possible solution to Matplotlib's
ax.set_aspect('equal') and ax.axis('equal') not working for 3D.
Input
ax: a matplotlib axis, e.g., as output from plt.gca().
'''
x_limits = ax.get_xlim3d()
y_limits = ax.get_ylim3d()
z_limits = ax.get_zlim3d()
x_range = abs(x_limits[1] - x_limits[0])
x_middle = np.mean(x_limits)
y_range = abs(y_limits[1] - y_limits[0])
y_middle = np.mean(y_limits)
z_range = abs(z_limits[1] - z_limits[0])
z_middle = np.mean(z_limits)
# The plot bounding box is a sphere in the sense of the infinity
# norm, hence I call half the max range the plot radius.
plot_radius = 0.5*max([x_range, y_range, z_range])
ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
set_axes_equal(ax)
plt.show()
@karlo의 답변을 수정하여 일을 더욱 깔끔하게 만듭니다.
def set_axes_radius(ax, origin, radius):
ax.set_xlim3d([origin[0] - radius, origin[0] + radius])
ax.set_ylim3d([origin[1] - radius, origin[1] + radius])
ax.set_zlim3d([origin[2] - radius, origin[2] + radius])
def set_axes_equal(ax):
'''Make axes of 3D plot have equal scale so that spheres appear as spheres,
cubes as cubes, etc.. This is one possible solution to Matplotlib's
ax.set_aspect('equal') and ax.axis('equal') not working for 3D.
Input
ax: a matplotlib axis, e.g., as output from plt.gca().
'''
limits = np.array([
ax.get_xlim3d(),
ax.get_ylim3d(),
ax.get_zlim3d(),
])
origin = np.mean(limits, axis=1)
radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0]))
set_axes_radius(ax, origin, radius)
용법:
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal') # important!
# ...draw here...
set_axes_equal(ax) # important!
plt.show()
편집 : 이 답변은 존재하지 않는 오류를 수정하려고 시도했지만 user2525140의 코드는 완벽하게 작동합니다. 아래 대답은 중복 (대체) 구현 일뿐입니다.
def set_aspect_equal_3d(ax):
"""Fix equal aspect bug for 3D plots."""
xlim = ax.get_xlim3d()
ylim = ax.get_ylim3d()
zlim = ax.get_zlim3d()
from numpy import mean
xmean = mean(xlim)
ymean = mean(ylim)
zmean = mean(zlim)
plot_radius = max([abs(lim - mean_)
for lims, mean_ in ((xlim, xmean),
(ylim, ymean),
(zlim, zmean))
for lim in lims])
ax.set_xlim3d([xmean - plot_radius, xmean + plot_radius])
ax.set_ylim3d([ymean - plot_radius, ymean + plot_radius])
ax.set_zlim3d([zmean - plot_radius, zmean + plot_radius])
'Development Tip' 카테고리의 다른 글
컴포넌트와 디렉티브의 차이점은 무엇입니까? (0) | 2020.10.23 |
---|---|
Groovy에는 2 개의 맵을 병합하는 방법이 있습니까? (0) | 2020.10.23 |
dplyr은 각각을 나열하지 않고 여러 변수를 요약 할 수 있습니까? (0) | 2020.10.23 |
org.apache.http.HttpResponse에서 HTTP 코드 가져 오기 (0) | 2020.10.22 |
Visual Studio의 솔루션에서 * 모든 * Nuget 패키지를 제거하는 방법 (0) | 2020.10.22 |