具有自定义颜色数组的plot_trisurface

Max*_*ers 3 python matplotlib triangulation

我基本上想在其支持上“imshow”三维狄利克雷分布的pdf。下面的函数simplex计算该支撑上的常规点,这些点存储在数组 中sim。该数组pdf保存 中每一行的标量密度sim

我首先想到的是使用三角测量。然而,color的参数plot_trisurface仅支持所有三角形使用一种颜色。根据 z 坐标值设置cmap三角形的颜色(见图 1)。也plot_trisurface忽略了facecolorskwarg。然而,我想要的是基于 为表面着色pdf

图 1. 在plot_trisurface 中使用颜色参数(左)和 cmap 参数(右)的差异

作为一种解决方法,我发现可以将表面插值为 3d 散点图。这通常会给出所需的可视化效果,但我清楚地看到它是一个散点图;特别是在边界上。(见图 2。)

通过散点图插值的表面

有没有办法将 pdf 的投影绘制到单纯形上?

import itertools
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats


def simplex(n_vals):
    base = np.linspace(0, 1, n_vals, endpoint=False)
    coords = np.asarray(list(itertools.product(base, repeat=3)))
    return coords[np.isclose(coords.sum(axis=-1), 1.0)]


sim = simplex(20)
pdf = stats.dirichlet([1.1, 1.5, 1.3]).pdf(sim.T)

fig1 = plt.figure()
ax1 = fig1.add_subplot(1, 2, 1, projection='3d', azim=20)
ax2 = fig1.add_subplot(1, 2, 2, projection='3d', azim=20)
ax1.plot_trisurf(x, y, z, color='k')
ax2.plot_trisurf(x, y, z, cmap='Spectral')

fig2 = plt.figure()
ax21 = fig2.add_subplot(projection='3d', azim=20)
ax21.scatter3D(*sim.T, s=50, alpha=.5, c=pdf, cmap='Spectral')
Run Code Online (Sandbox Code Playgroud)

gbo*_*ffi 5

该图包含一个colorbar,

\n

在此输入图像描述

\n

由以下脚本 \xe2\x80\x94 生成map_colors,在脚本末尾定义的函数可能会引起一般读者的兴趣。

\n
import numpy as np\nimport matplotlib.pyplot as plt\nfrom scipy import stats\nfrom itertools import product as \xce\xa0\n\n# the distribution that we want to study\ndirichlet = stats.dirichlet([1.1, 1.5, 1.3])\n\n# generate the "mesh"\nN = 30 # no. of triangles along an edge\ns = np.linspace(0, 1, N+1)\nx, y, z = np.array([(x,y,1-x-y) for x,y in \xce\xa0(s,s) if x+y<1+1E-6]).T\n\n# plot as usual\nfig = plt.figure() \nax = fig.add_subplot(1, 1, 1, projection=\'3d\', azim=20) \np3dc = ax.plot_trisurf(x, y, z)\n\n########## change the face colors ####################\nmappable = map_colors(p3dc, dirichlet.pdf, \'Spectral\')\n# ####################################################\n\n# possibly add a colormap\nplt.colorbar(mappable, shrink=0.67, aspect=16.7)\n\n# we are done\nplt.show()\n\ndef map_colors(p3dc, func, cmap=\'viridis\'):\n    """\nColor a tri-mesh according to a function evaluated in each barycentre.\n\n    p3dc: a Poly3DCollection, as returned e.g. by ax.plot_trisurf\n    func: a single-valued function of 3 arrays: x, y, z\n    cmap: a colormap NAME, as a string\n\n    Returns a ScalarMappable that can be used to instantiate a colorbar.\n    """\n    \n    from matplotlib.cm import ScalarMappable, get_cmap\n    from matplotlib.colors import Normalize\n    from numpy import array\n\n    # reconstruct the triangles from internal data\n    x, y, z, _ = p3dc._vec\n    slices = p3dc._segslices\n    triangles = array([array((x[s],y[s],z[s])).T for s in slices])\n\n    # compute the barycentres for each triangle\n    xb, yb, zb = triangles.mean(axis=1).T\n    \n    # compute the function in the barycentres\n    values = func(xb, yb, zb)\n\n    # usual stuff\n    norm = Normalize()\n    colors = get_cmap(cmap)(norm(values))\n\n    # set the face colors of the Poly3DCollection\n    p3dc.set_fc(colors)\n\n    # if the caller wants a colorbar, they need this\n    return ScalarMappable(cmap=cmap, norm=norm)\n
Run Code Online (Sandbox Code Playgroud)\n