1

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')

Current geometry

yvrob
  • 105
  • 10
  • Provide a reproducible code snippet, please. Thanks! – blunova Jul 08 '22 at 14:56
  • Hi, thank you for your answer. Please see my edited post. Is the problem clearer? – yvrob Jul 08 '22 at 18:15
  • Well, the second problem is not so easy to tackle, because it is intrinsically linked to how 3d graphics in matplotlib works. Give a read to this mpl [faq](https://matplotlib.org/stable/api/toolkits/mplot3d/faq.html#my-3d-plot-doesn-t-look-right-at-certain-viewing-angles) to understand better what I am talking about. Regarding the first question I think we are widening to much the question and losing focus. Write a new question about this issue. – blunova Jul 11 '22 at 21:25

1 Answers1

2

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()

enter image description here

blunova
  • 2,122
  • 3
  • 9
  • 21
  • Hello, thank you for your answer, it helps a lot! This got me started with the plot I show in my edit on the post. As you can see, some new problems arose. Would you have some solutions? – yvrob Jul 10 '22 at 05:58