Python 3D Plots over non-rectangular domain

后端 未结 2 1214
挽巷
挽巷 2020-12-04 00:16

I have some z=f(x,y) data which i would like to plot. The issue is that (x,y) are not part of a \"nice\" rectangle, but rather arbitrary parallelog

相关标签:
2条回答
  • 2020-12-04 00:32

    Abritrary points can be supplied as 1D arrays to matplotlib.Axes3D.plot_trisurf. It doesn't matter whether they follow a specific structure.

    Other methods which would depend on the structure of the data would be

    • Interpolate the points on a regular rectangular grid. This can be accomplished using scipy.interpolate.griddata. See example here
    • Reshape the input arrays such that they live on a regular and then use plot_surface(). Depending on the order by which the points are supplied, this could be a very easy solution for a grid with "parallelogramic" shape.
      As can be seen from the sphere example, plot_surface() also works in cases of very unequal grid shapes, as long as it's structured in a regular way.

    Here are some examples:

    For completeness, find here the code that produces the above image:

    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    import numpy as np
    
    f = lambda x,y: np.sin(x+0.4*y)*0.23+1
    
    fig = plt.figure(figsize=(5,6))
    plt.subplots_adjust(left=0.1, top=0.95,wspace=0.01)
    
    
    ax0 = fig.add_subplot(322, projection="3d")
    
    ma = 6*(np.random.rand(100)-0.5)
    mb = 6*(np.random.rand(100)-0.5)
    phi = np.pi/4
    x = 1.7*ma*np.cos(phi) + 1.7*mb*np.sin(phi)
    y = -1.2*ma*np.sin(phi) +1.2* mb*np.cos(phi)
    z = f(x,y)
    ax0.plot_trisurf(x,y,z)
    
    ax1 = fig.add_subplot(321)
    ax0.set_title("random plot_trisurf()")
    ax1.set_aspect("equal")
    ax1.scatter(x,y, marker="+", alpha=0.4)
    for i  in range(len(x)):
        ax1.text(x[i],y[i], i  , ha="center", va="center", fontsize=6)
    
    
    n = 10
    a = np.linspace(-3, 3, n)
    ma, mb = np.meshgrid(a,a)
    phi = np.pi/4
    xm = 1.7*ma*np.cos(phi) + 1.7*mb*np.sin(phi)
    ym = -1.2*ma*np.sin(phi) +1.2* mb*np.cos(phi)
    shuf = np.c_[xm.flatten(), ym.flatten()]
    np.random.shuffle(shuf)
    x = shuf[:,0]
    y = shuf[:,1]
    z = f(x,y)
    
    ax2 = fig.add_subplot(324, projection="3d")
    ax2.plot_trisurf(x,y,z)
    
    ax3 = fig.add_subplot(323)
    ax2.set_title("unstructured plot_trisurf()")
    ax3.set_aspect("equal")
    ax3.scatter(x,y, marker="+", alpha=0.4)
    for i  in range(len(x)):
        ax3.text(x[i],y[i], i  , ha="center", va="center", fontsize=6)
    
    
    x = xm.flatten()
    y = ym.flatten()
    z = f(x,y)
    
    X = x.reshape(10,10)
    Y = y.reshape(10,10)
    Z = z.reshape(10,10)
    
    ax4 = fig.add_subplot(326, projection="3d")
    ax4.plot_surface(X,Y,Z)
    
    ax5 = fig.add_subplot(325)
    ax4.set_title("regular plot_surf()")
    ax5.set_aspect("equal")
    ax5.scatter(x,y, marker="+", alpha=0.4)
    for i  in range(len(x)):
        ax5.text(x[i],y[i], i  , ha="center", va="center", fontsize=6)
    
    
    for axes in [ax0, ax2,ax4]:
        axes.set_xlim([-3.5,3.5])
        axes.set_ylim([-3.5,3.5])
        axes.set_zlim([0.9,2.0])
        axes.axis("off")
    plt.savefig(__file__+".png")
    plt.show()
    
    0 讨论(0)
  • 2020-12-04 00:43

    If your data is in order, and you know the size of the parallgram, a reshape will probably suffice:

    ax.surface(x.reshape(10, 10), y.reshape(10, 10), z.reshape(10, 10))
    

    Will work if the parallelogram has 10 points on each side, and the points are ordered in a zigzag pattern

    0 讨论(0)
提交回复
热议问题