简体   繁体   中英

Plotting 2D picture on 3D plot in Python

I would like to present some 3D spatial data with Python, but with the geometry of the setup plotted for each direction. So for the XY plane, I would have at z=0 the view from above, same for XZ and YZ.

I saw that other posts asked a similar question, but here, the data would not be coordinates and colors, but rather a real picture.

My idea, based on other posts was the following:

import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
import numpy as np
import matplotlib.image as mpimg

fig = plt.figure()
fig.add_subplot(111, projection="3d")

# 3D data
X = np.random.uniform(0,100,100)
Y = np.random.uniform(0,100,100)
Z = np.random.uniform(0,100,100)
values = np.random(100)
# XY
img = mpimg.imread('/home/geometryXY')
imgplot = plt.imshow(img, zdir='x', aspect='auto')
# XZ
img = mpimg.imread('/home/geometryXZ')
imgplot = plt.imshow(img, zdir='y', aspect='auto')
# YZ
img = mpimg.imread('/home/geometryYZ')
imgplot = plt.imshow(img, zdir='z', aspect='auto')
plt.show()

Any image file would work. Indeed, for now, what interests me is to see if we can put a 2D image on a 3D axis and overlap a 3D plot on it.

At least the idea would be that. However, the 'zdir' option does not seem to exist. Would you have any tip?

Thanks

EDIT:

Based on blunova's answer, I changed several things. First I added where I want to see the plot with the val argument, and scaling parameters for each axis xlim and ylim . To make it work, for some reason, I also had to swap the x and y axes of the imread object and to flip the y axis.

Several problems are still here.

The first one is that the process is very slow. Showing the 2D picture with imshow would take less few seconds (images are 3000*5000 pixels large), but here I stopped the function after few minutes because it was too slow. I therefore changed the rstride and cstride , and mutliplied them by 15, which is huge (does it mean I reduce my quality by 15^2?) just to make it barely ok (2 minutes to plot 3 images). What I don't understand why there is such a difference between the normal imshow and the plot_surface routines.

The second is that the images "cut" the 3D data in foreground, even though I added the 3D plot afterwards, and even if the zorder for the images is set to -1000. The 3D data should show a full cylinder, and no value is lower than the -144 value shown in the code.

There also seems to be a problem with the lighting which is strange.

For your reference, here is the current state of this plot.

def plot_image(ax, image, axis, xlim, ylim, val, rstride=15, cstride=15):
    array = plt.imread(image)
    array = np.swapaxes(array, 0, 1)
    array = np.flip(array, 1)
    step_x, step_y = np.diff(xlim) / array.shape[0], np.diff(ylim) / array.shape[1]
    x_1 = np.arange(xlim[0], xlim[1], step_x)
    y_1 = np.arange(ylim[0], ylim[1], step_y)
    y_1, x_1 = np.meshgrid(y_1, x_1)
    vals = np.ones((array.shape[0], array.shape[1]))*val
    if axis == "x":
        ax.plot_surface(vals, x_1, y_1, rstride=rstride, cstride=cstride, facecolors=array, zorder=-1000)
    elif axis == "y":
        ax.plot_surface(x_1, vals, y_1, rstride=rstride, cstride=cstride, facecolors=array, zorder=-1000)
    elif axis == "z":
        ax.plot_surface(x_1, y_1, vals, rstride=rstride, cstride=cstride, facecolors=array,zorder=-1000)

fig = plt.figure(figsize=(10,15))
fig.add_subplot(111, projection="3d")

# Plot geometry in background
plot_image(plt.gca(), '/home/yryves/serpent_cases/domain_decomposition_dvlpt/test_stl2/Plots/input_geom1_bu1.png','x', xlim=[-144,144], ylim=[0,487.528], val=-144)
plot_image(plt.gca(), '/home/yryves/serpent_cases/domain_decomposition_dvlpt/test_stl2/Plots/input_geom2_bu1.png','y', xlim=[-144,144], ylim=[0,487.528], val=144)
plot_image(plt.gca(), '/home/yryves/serpent_cases/domain_decomposition_dvlpt/test_stl2/Plots/input_geom3_bu1.png','z', xlim=[-144,144], ylim=[-144,144], val=0)

# 3D data plot
pbed.plot3D('z', new_fig=False)

plt.savefig('geometry.png')

当前几何

Based on this answer , I came up with the following solution. I have used three cryptopunks images centered at the origin and lying in the x=0 , y=0 and z=0 planes.


import matplotlib.pyplot as plt
import numpy as np


def main():
    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')

    x = np.random.uniform(-5, 5, 100)
    y = np.random.uniform(-5, 5, 100)
    z = np.random.uniform(-5, 5, 100)
    ax.scatter(x, y, z)

    plot_image(ax, "1.png", "x")
    plot_image(ax, "2.png", "y")
    plot_image(ax, "3.png", "z")

    plt.show()


def plot_image(ax, image, axis):

    array = plt.imread(image)
    step_x, step_y = 10. / array.shape[0], 10. / array.shape[1]

    x_1 = np.arange(-5, 5, step_x)
    y_1 = np.arange(-5, 5, step_y)
    x_1, y_1 = np.meshgrid(x_1, y_1)

    zeros = np.zeros((array.shape[0], array.shape[1]))

    rstride = 1
    cstride = 1
    if axis == "x":
        ax.plot_surface(
            zeros, x_1, y_1, rstride=rstride, cstride=cstride, facecolors=array
        )
    elif axis == "y":
        ax.plot_surface(
            x_1, zeros, y_1, rstride=rstride, cstride=cstride, facecolors=array
        )
    elif axis == "z":
        ax.plot_surface(
            x_1, y_1, zeros, rstride=rstride, cstride=cstride, facecolors=array
        )


if __name__ == "__main__":
    main()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM