(python)绘制带有colormap的3d表面作为第四维,x,y,z的函数

时间:2015-09-08 15:15:34

标签: python matplotlib 3d

我正在尝试绘制一个三维表面,其中三个维度中的每个维度都在一个单独的数组中,每个坐标处的表面着色是x,y,z的函数。一种numpy.pcolormesh,但在4D,而不是3D。 3D图由下式给出:

{
  key: 'name.firstname',
  type: 'input',
  templateOptions:  {
    label: 'First Name'
  }
}

,其中

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.logspace(-1.,np.log10(5),50)
y = np.linspace(6,9,50)
z = np.linspace(-1,1,50)
colors = LikeBeta(y,range(50),range(50))
ax.plot_trisurf(x,y,z,cmap=colors,linewidth=0.2)

可能def LikeBeta(rho0,r0,beta): M0 = 10**rho0*r0_array[r0]**3 I = cst*M0*sigma_los_beta[beta,:,r0] S = dv**2+I res = (np.log(S) + (v-u)**2/S).sum() return res/2. 错了,但问题出在其他地方。我收到以下错误:

cmap=colors

确实----> 8 colors = LikeBeta(y,range(50),range(50)) ----> 4 I = cst*M0*sigma_los_beta[beta,:,r0] ValueError: operands could not be broadcast together with shapes (50,) (50,353) 是一个我单独评估的数组,其形状为sigma_los_beta,而那些353是我必须拥有的数据。

如何将此功能转换为与(50,353,50)的其他条目兼容的表单?

很抱歉,但我无法提供最小的工作代码,因为dv,v和u是数据。 非常感谢您的帮助。干杯

3 个答案:

答案 0 :(得分:8)

This回答解决了4d曲面问题。它使用matplotlib的plot_surface函数而不是plot_trisurf

基本上,您希望将x,y和z变量重塑为相同维度的2d数组。要将第四个维度添加为色彩映射,必须提供与轴变量具有相同维度的另一个二维数组。

下面是3d图的示例代码,其中colormap对应于x值。 facecolors参数用于根据您的喜好更改色彩映射。请注意,其值是从to_rgba()类中的matplotlib.cm.ScalarMappable函数获取的。

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

# domains
x = np.logspace(-1.,np.log10(5),50) # [0.1, 5]
y = np.linspace(6,9,50)             # [6, 9]
z = np.linspace(-1,1,50)            # [-1, 1]

# convert to 2d matrices
Z = np.outer(z.T, z)        # 50x50
X, Y = np.meshgrid(x, y)    # 50x50

# fourth dimention - colormap
# create colormap according to x-value (can use any 50x50 array)
color_dimension = X # change to desired fourth dimension
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
m = plt.cm.ScalarMappable(norm=norm, cmap='jet')
m.set_array([])
fcolors = m.to_rgba(color_dimension)

# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X,Y,Z, rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
fig.canvas.show()

我引用的答案(以及其他人)提到您应该规范化您的第四维数据。似乎可以通过显式设置色彩映射的限制来避免这种情况,就像我在代码示例中所做的那样。

答案 1 :(得分:0)

此代码基于trisurf演示 http://matplotlib.org/examples/mplot3d/trisurf3d_demo.html

我添加了一个基于SO Create own colormap using matplotlib and plot color scale

的函数make_colormap()

还添加了一个序列w = tan(-x * y),以灰度为基础生成基于该函数的颜色图。
您可以使用cdict的构造来添加更多颜色,但我认为灰度是一个很好的概念证明......

很抱歉,由于缺少最少的工作代码,我无法直接使用您的示例。

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

###################

def make_colormap(seq):
    """Return a LinearSegmentedColormap
    seq: a sequence of floats and RGB-tuples. The floats should be increasing
    and in the interval (0,1).
    """
    #%
    cdict = {'red': [], 'green': [], 'blue': []}

    # make a lin_space with the number of records from seq.     
    x = np.linspace(0,1, len(seq))
    #%
    for i in range(len(seq)):
        segment = x[i]
        tone = seq[i]
        cdict['red'].append([segment, tone, tone])
        cdict['green'].append([segment, tone, tone])
        cdict['blue'].append([segment, tone, tone])
    #%
    return mcolors.LinearSegmentedColormap('CustomMap', cdict)


#############################



n_angles = 36
n_radii = 8

# An array of radii
# Does not include radius r=0, this is to eliminate duplicate points
radii = np.linspace(0.125, 1.0, n_radii)

# An array of angles
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)

# Repeat all angles for each radius
angles = np.repeat(angles[...,np.newaxis], n_radii, axis=1)

# Convert polar (radii, angles) coords to cartesian (x, y) coords
# (0, 0) is added here. There are no duplicate points in the (x, y) plane
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())

# Pringle surface
z = np.sin(-x*y)



w = np.tan(-x*y)
colors = make_colormap(w)



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

ax.plot_trisurf(x, y, z, cmap=colors, linewidth=0.2)

plt.show()

答案 2 :(得分:0)

非常感谢@Frik出色的answer,它帮助我实现了OP要求的类似情节。

但是,我发现可以对代码进行一些简化,并且可能会引起人们的兴趣。片段和图如下。

func main() {
    c:=make(chan int,10)

    for i:=0;i<5;i++{
        go func(chanel chan int,i int){
            println("i",i)
            chanel <- 1
        }(c,i)
    }

    for x:=range c {
        println(x)
    }
    println("Done!")
}

enter image description here

最后,我也想评论@Frik的话:

  

我引用的答案(和其他答案)提到您应该对第四维数据进行规范化。似乎可以像我在代码示例中所做的那样,通过显式设置颜色图的限制来避免这种情况。

我发现此说法不正确。确实,如果人们看看to_rgba,就会发现有一个import matplotlib.pyplot as plt # This import registers the 3D projection, but is otherwise unused. from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import from mpl_toolkits.mplot3d.axes3d import get_test_data import numpy as np fig, ax = plt.subplots(subplot_kw={'projection': '3d'}) X, Y, Z = get_test_data(0.05) C = np.linspace(-5, 5, Z.size).reshape(Z.shape) scamap = plt.cm.ScalarMappable(cmap='inferno') fcolors = scamap.to_rgba(C) ax.plot_surface(X, Y, Z, facecolors=fcolors, cmap='inferno') fig.colorbar(scamap) plt.show() 关键字,默认情况下它设置为norm。这正是进行标准化的地方。还包括以下语句:

  

如果norm为False,则不对输入数据进行归一化,并假定其在(0-1)范围内。

您确实希望您的数据位于(0-1)中。