8

以下のコードは、強度を測定したポイントの 3D プロットを生成します。各ポイントに強度の値を付けてから、ポイント間を補間して、強度の高いポイントと低いポイントを示すカラー マップ/サーフェス プロットを生成したいと考えています。

これを行うには が必要scipy.interpolate.RectBivariateSplineだと思いますが、これがどのように機能するかはわかりません-私が見た例には3Dプロットが含まれていないためです。

編集:球を表面プロットとして表示したいのですがAxes3D、ポイントが均等に分布していないため(つまり、赤道の周りのポイントが互いに接近しているため)、これを使用してこれを行うことができるかどうかわかりません

どんな助けでも大歓迎です。

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

# Radius of the sphere
r = 0.1648

# Our theta vals
theta = np.array([0.503352956, 1.006705913, 1.510058869,
                  1.631533785, 2.134886741, 2.638239697]) 
# Our phi values
phi = np.array([  np.pi/4,   np.pi/2, 3*np.pi/4,   np.pi,
                5*np.pi/4, 3*np.pi/2, 7*np.pi/4, 2*np.pi])

# Loops over each angle to generate the points on the surface of sphere
def gen_coord():
    x = np.zeros((len(theta), len(phi)), dtype=np.float32)
    y = np.zeros((len(theta), len(phi)), dtype=np.float32)
    z = np.zeros((len(theta), len(phi)), dtype=np.float32)

    # runs over each angle, creating the x y z values
    for i in range(len(theta)): 
        for j in range(len(phi)):
            x[i,j] = r * np.sin(theta[i]) * np.cos(phi[j])
            y[i,j] = r * np.sin(theta[i]) * np.sin(phi[j])
            z[i,j] = r * np.cos(theta[i])

    x_vals = np.reshape(x, 48)
    y_vals = np.reshape(y, 48)
    z_vals = np.reshape(z, 48)

    return x_vals, y_vals, z_vals

# Plots the points on a 3d graph
def plot():
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    x, y, z = gen_coord()
    ax.scatter(x, y, z)
    plt.show()

ここに画像の説明を入力

編集: 更新: 最初の 8 つの値が theta の最初の値などに対応するように、データ配列 (ここでは v という名前) をフォーマットしました。何らかの理由で、グラフに対応するカラーバーは、電圧の値が負であることを示していますが、これは元のコードには示されていません。また、入力された値は、その位置であるべきポイントに必ずしも対応していないようです。なんらかのオフセットがあるのか​​、コードを間違って解釈したのかはわかりません。

from scipy.interpolate import RectSphereBivariateSpline
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.colorbar import ColorbarBase, make_axes_gridspec

r = 0.1648 
theta = np.array([0.503352956, 1.006705913, 1.510058869, 1.631533785, 2.134886741, 2.638239697]) #Our theta vals
phi = np.array([np.pi/4, np.pi/2, 3*np.pi/4, np.pi, 5*np.pi/4, 3*np.pi/2, 7*np.pi/4, 2*np.pi]) #Our phi values

v = np.array([0.002284444388889,0.003155555477778,0.002968888844444,0.002035555555556,0.001884444411111,0.002177777733333,0.001279999988889,0.002666666577778,0.015777777366667,0.006053333155556,0.002755555533333,0.001431111088889,0.002231111077778,0.001893333311111,0.001288888877778,0.005404444355556,0,0.005546666566667,0.002231111077778,0.0032533332,0.003404444355556,0.000888888866667,0.001653333311111,0.006435555455556,0.015311110644444,0.002453333311111,0.000773333333333,0.003164444366667,0.035111109822222,0.005164444355556,0.003671111011111,0.002337777755556,0.004204444288889,0.001706666666667,0.001297777755556,0.0026577777,0.0032444444,0.001697777733333,0.001244444411111,0.001511111088889,0.001457777766667,0.002159999944444,0.000844444433333,0.000595555555556,0,0,0,0]) #Lists 1A-H, 2A-H,...,6A-H
volt = np.reshape(v, (6, 8))

spl = RectSphereBivariateSpline(theta, phi, volt)

# evaluate spline fit on a denser 50 x 50 grid of thetas and phis
theta_itp = np.linspace(0, np.pi, 100)
phi_itp = np.linspace(0, 2 * np.pi, 100)
d_itp = spl(theta_itp, phi_itp)

x_itp = r * np.outer(np.sin(theta_itp), np.cos(phi_itp)) #Cartesian coordinates of sphere
y_itp = r * np.outer(np.sin(theta_itp), np.sin(phi_itp))
z_itp = r * np.outer(np.cos(theta_itp), np.ones_like(phi_itp))

norm = plt.Normalize()
facecolors = plt.cm.jet(norm(d_itp))

# surface plot
fig, ax = plt.subplots(1, 1, subplot_kw={'projection':'3d', 'aspect':'equal'})
ax.hold(True)
ax.plot_surface(x_itp, y_itp, z_itp, rstride=1, cstride=1, facecolors=facecolors)

#Colourbar
cax, kw = make_axes_gridspec(ax, shrink=0.6, aspect=15)
cb = ColorbarBase(cax, cmap=plt.cm.jet, norm=norm)
cb.set_label('Voltage', fontsize='x-large')


plt.show()

グラフ

4

1 に答える 1

4

たとえば、次を使用して、球座標空間で補間を行うことができますRectSphereBivariateSpline

from scipy.interpolate import RectSphereBivariateSpline

# a 2D array of intensity values
d = np.outer(np.sin(2 * theta), np.cos(2 * phi))

# instantiate the interpolator with the original angles and intensity values.
spl = RectSphereBivariateSpline(theta, phi, d)

# evaluate spline fit on a denser 50 x 50 grid of thetas and phis
theta_itp = np.linspace(0, np.pi, 50)
phi_itp = np.linspace(0, 2 * np.pi, 50)
d_itp = spl(theta_itp, phi_itp)

# in order to plot the result we need to convert from spherical to Cartesian
# coordinates. we can avoid those nasty `for` loops using broadcasting:
x_itp = r * np.outer(np.sin(theta_itp), np.cos(phi_itp))
y_itp = r * np.outer(np.sin(theta_itp), np.sin(phi_itp))
z_itp = r * np.outer(np.cos(theta_itp), np.ones_like(phi_itp))

# currently the only way to achieve a 'heatmap' effect is to set the colors
# of each grid square separately. to do this, we normalize the `d_itp` values
# between 0 and 1 and pass them to one of the colormap functions:
norm = plt.Normalize(d_itp.min(), d_itp.max())
facecolors = plt.cm.coolwarm(norm(d_itp))

# surface plot
fig, ax = plt.subplots(1, 1, subplot_kw={'projection':'3d', 'aspect':'equal'})
ax.hold(True)
ax.plot_surface(x_itp, y_itp, z_itp, rstride=1, cstride=1, facecolors=facecolors)

それははるかに完璧なソリューションです。特に、φ が 2π から 0 に「ラップアラウンド」するいくつかの見苦しいエッジ効果があります (以下の更新を参照)。

ここに画像の説明を入力


アップデート:

カラーバーに関する 2 番目の質問に対処するには、配列とカラーマップを指定するだけでなく、「ヒートマップ」効果を得るために各パッチの色を個別に設定する必要があったため、カラーバーを作成する通常の方法は機能しません。ColorbarBaseただし、クラスを使用してカラーバーを「偽造」することは可能です。

from matplotlib.colorbar import ColorbarBase, make_axes_gridspec

# create a new set of axes to put the colorbar in
cax, kw = make_axes_gridspec(ax, shrink=0.6, aspect=15)

# create a new colorbar, using the colormap and norm for the real data
cb = ColorbarBase(cax, cmap=plt.cm.coolwarm, norm=norm)
cb.set_label('Voltage', fontsize='x-large')

ここに画像の説明を入力


「球を平らにする」には、補間された強度値を ϕ と ϴ の関数として 2D ヒートマップにプロットできます。たとえば、次のように使用しpcolormeshます。

fig, ax = plt.subplots(1, 1)
ax.hold(True)

# plot the interpolated values as a heatmap
im = ax.pcolormesh(phi_itp, theta_itp, d_itp, cmap=plt.cm.coolwarm)

# plot the original data on top as a colormapped scatter plot
p, t = np.meshgrid(phi, theta)
ax.scatter(p.ravel(), t.ravel(), s=60, c=d.ravel(), cmap=plt.cm.coolwarm,
           norm=norm, clip_on=False)

ax.set_xlabel('$\Phi$', fontsize='xx-large')
ax.set_ylabel('$\Theta$', fontsize='xx-large')
ax.set_yticks(np.linspace(0, np.pi, 3))
ax.set_yticklabels([r'$0$', r'$\frac{\pi}{2}$', r'$\pi$'], fontsize='x-large')
ax.set_xticks(np.linspace(0, 2*np.pi, 5))
ax.set_xticklabels([r'$0$', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{4}$',
                    r'$2\pi$'], fontsize='x-large')
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(0, np.pi)
cb = plt.colorbar(im)
cb.set_label('Voltage', fontsize='x-large')
fig.tight_layout()

ここに画像の説明を入力

ここで奇妙な境界の問題がある理由がわかります。入力ポイントが ϕ = 0 に十分近くサンプリングされていないため、ϕ 軸に沿った振動の最初のフェーズをキャプチャできず、補間は強度値を 2π から0. この場合、単純な回避策は、補間を行う前に、入力ポイントを ϕ = 0 に対して ϕ = 2π で複製することです。

「球体をリアルタイムで回転させる」とはどういう意味かよくわかりません.3D軸をクリックしてドラッグすることで、すでにそれを行うことができるはずです。


更新 2

入力データには負の電圧が含まれていませんが、これは補間されたデータに含まれないことを保証するものではありません。スプライン フィットは非負になるように制約されておらず、補間された値がいくつかの場所で実際のデータを「アンダーシュート」することが予想されます。

print(volt.min())
# 0.0

print(d_itp.min())
# -0.0172434740677

私はあなたが何を意味するかを理解しているかどうかはよくわかりません

また、入力された値は、その位置であるべきポイントに必ずしも対応していないようです。

データを 2D ヒートマップとして表示すると、次のようになります。

ここに画像の説明を入力

散布点の色 (元の電圧値を表す) は、ヒート マップの補間値と正確に一致します。おそらく、補間における「オーバーシュート」/「アンダーシュート」の程度を指していますか? データセット内の入力ポイントが少ないことを考えると、これを避けるのは困難です。試してみることができることの 1 つは、sパラメーター to をいじることRectSphereBivariateSplineです。これを正の値に設定すると、補間ではなくスムージングを行うことができます。つまり、補間された値が入力ポイントを正確に通過しなければならないという制約を緩和できます。ただし、これを簡単に試してみたところ、見栄えの良い出力が得られませんでした。これは、おそらく入力ポイントが少なすぎるためです。

于 2015-11-07T01:16:59.003 に答える