将强度附加到3D绘图

emc*_*636 7 python interpolation matplotlib scipy mplot3d

下面的代码生成我测量强度的点的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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

编辑:更新:我已经格式化了我的数据数组(此处命名为v),使得前8个值对应于theta的第一个值,依此类推.由于某种原因,对应于该图的颜色条表示I具有负电压值,其未在原始代码中示出.此外,输入的值似乎并不总是对应于应该作为其位置的点.我不确定是否存在某种偏移,或者我是否错误地解释了您的代码.

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()
Run Code Online (Sandbox Code Playgroud)

图http://i65.tinypic.com/2m61g8m.jpg

ali*_*i_m 4

您可以在球面坐标空间中进行插值,例如使用RectSphereBivariateSpline

\n
from scipy.interpolate import RectSphereBivariateSpline\n\n# a 2D array of intensity values\nd = np.outer(np.sin(2 * theta), np.cos(2 * phi))\n\n# instantiate the interpolator with the original angles and intensity values.\nspl = RectSphereBivariateSpline(theta, phi, d)\n\n# evaluate spline fit on a denser 50 x 50 grid of thetas and phis\ntheta_itp = np.linspace(0, np.pi, 50)\nphi_itp = np.linspace(0, 2 * np.pi, 50)\nd_itp = spl(theta_itp, phi_itp)\n\n# in order to plot the result we need to convert from spherical to Cartesian\n# coordinates. we can avoid those nasty `for` loops using broadcasting:\nx_itp = r * np.outer(np.sin(theta_itp), np.cos(phi_itp))\ny_itp = r * np.outer(np.sin(theta_itp), np.sin(phi_itp))\nz_itp = r * np.outer(np.cos(theta_itp), np.ones_like(phi_itp))\n\n# currently the only way to achieve a \'heatmap\' effect is to set the colors\n# of each grid square separately. to do this, we normalize the `d_itp` values\n# between 0 and 1 and pass them to one of the colormap functions:\nnorm = plt.Normalize(d_itp.min(), d_itp.max())\nfacecolors = plt.cm.coolwarm(norm(d_itp))\n\n# surface plot\nfig, ax = plt.subplots(1, 1, subplot_kw={\'projection\':\'3d\', \'aspect\':\'equal\'})\nax.hold(True)\nax.plot_surface(x_itp, y_itp, z_itp, rstride=1, cstride=1, facecolors=facecolors)\n
Run Code Online (Sandbox Code Playgroud)\n

这绝对是一个完美的解决方案。特别是,\xcf\x95 从 2\xcf\x80 到 0“环绕”时,会出现一些难看的边缘效应(请参阅下面的更新)。

\n

在此输入图像描述

\n
\n

更新:

\n

要解决有关颜色条的第二个问题:由于我必须单独设置每个补丁的颜色以获得“热图”效果,而不是仅仅指定数组和颜色图,因此创建颜色条的常规方法将获胜不工作。但是,可以使用以下ColorbarBase类“伪造”颜色条:

\n
from matplotlib.colorbar import ColorbarBase, make_axes_gridspec\n\n# create a new set of axes to put the colorbar in\ncax, kw = make_axes_gridspec(ax, shrink=0.6, aspect=15)\n\n# create a new colorbar, using the colormap and norm for the real data\ncb = ColorbarBase(cax, cmap=plt.cm.coolwarm, norm=norm)\ncb.set_label(\'Voltage\', fontsize=\'x-large\')\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n
\n

要“展平球体”,您可以将插值强度值绘制为 2D 热图中 \xcf\x95 和 \xcf\xb4 的函数,例如使用pcolormesh

\n
fig, ax = plt.subplots(1, 1)\nax.hold(True)\n\n# plot the interpolated values as a heatmap\nim = ax.pcolormesh(phi_itp, theta_itp, d_itp, cmap=plt.cm.coolwarm)\n\n# plot the original data on top as a colormapped scatter plot\np, t = np.meshgrid(phi, theta)\nax.scatter(p.ravel(), t.ravel(), s=60, c=d.ravel(), cmap=plt.cm.coolwarm,\n           norm=norm, clip_on=False)\n\nax.set_xlabel(\'$\\Phi$\', fontsize=\'xx-large\')\nax.set_ylabel(\'$\\Theta$\', fontsize=\'xx-large\')\nax.set_yticks(np.linspace(0, np.pi, 3))\nax.set_yticklabels([r\'$0$\', r\'$\\frac{\\pi}{2}$\', r\'$\\pi$\'], fontsize=\'x-large\')\nax.set_xticks(np.linspace(0, 2*np.pi, 5))\nax.set_xticklabels([r\'$0$\', r\'$\\frac{\\pi}{2}$\', r\'$\\pi$\', r\'$\\frac{3\\pi}{4}$\',\n                    r\'$2\\pi$\'], fontsize=\'x-large\')\nax.set_xlim(0, 2*np.pi)\nax.set_ylim(0, np.pi)\ncb = plt.colorbar(im)\ncb.set_label(\'Voltage\', fontsize=\'x-large\')\nfig.tight_layout()\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

您可以看到为什么这里存在奇怪的边界问题 - 没有采样到足够接近 \xcf\x95 = 0 的输入点来捕获沿 \xcf\x95 轴振荡的第一阶段,并且插值不是“包裹” \' 强度值从 2\xcf\x80 到 0。在这种情况下,一个简单的解决方法是在进行插值之前复制 \xcf\x95 = 2\xcf\x80 处的输入点(对于 \xcf\x95 = 0)。

\n

我不太清楚“实时旋转球体”是什么意思 - 您应该已经可以通过单击并拖动 3D 轴来做到这一点。

\n
\n

更新2

\n

尽管您的输入数据不包含任何负电压,但这并不能保证插值数据不会包含任何负电压。样条拟合不限于非负,并且您可以预期插值在某些地方“低于”真实数据:

\n
print(volt.min())\n# 0.0\n\nprint(d_itp.min())\n# -0.0172434740677\n
Run Code Online (Sandbox Code Playgroud)\n

我不太确定我明白你的意思

\n
\n

此外,输入的值似乎并不总是与其位置对应的点相对应。

\n
\n

这是您的数据的 2D 热图:

\n

在此输入图像描述

\n

散点的颜色(代表原始电压值)与热图中的插值完全匹配。也许您指的是插值中“过冲”/“下冲”的程度?考虑到数据集中的输入点很少,这是很难避免的。您可以尝试的一件事是使用s参数 to RectSphereBivariateSpline。通过将其设置为正值,您可以进行平滑而不是插值,即您可以放宽插值必须精确通过输入点的约束。然而,我快速尝试了一下,但无法获得漂亮的输出,可能是因为输入点太少了。

\n