pythonmatplotlibmatplotlib-3d

Image overlay in 3d plot


I have a 3d plot of lines generated by matplotlib. I want to overlay an image at a specific xy (or yz, xz) slice. How do I do that using python? Thanks.

I have a simple 3d plot code as:

fig = plt.figure(1),<br>
ax = Axes3D(fig)<br>
ax.plot(f[:,0], f[:,1], f[:,2], color='r')

I also have an image "Im" (a 2d array), so I need something like:

ax.overlay(Im, slice='xy', sliceNo=10)

Solution

  • I did a 3d surface plot overlay on top of a background image once:

    3d surface plot on top of background image

    If this is similar to what you want, I could try to make a working example out of it.

    Alternatively, if you just want to display an image in 3d space, you can use a surface plot:

    from pylab import *
    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib.cbook import get_sample_data
    from matplotlib._png import read_png
    fn = get_sample_data("lena.png", asfileobj=False)
    img = read_png(fn)
    x, y = ogrid[0:img.shape[0], 0:img.shape[1]]
    ax = gca(projection='3d')
    ax.plot_surface(x, y, 10, rstride=5, cstride=5, facecolors=img)
    show()
    

    Of course, the stride values can be decreased to 1 for better image quality, but then drawing will take loooong =)

    Resulting image from above code:

    enter image description here

    Edit Nov 2020:

    Since it seems to be of interest, here's the code I used to generate the first image (which is the minority charge carrier decay in a multicrystalline silicon wafer after photo-excitation):

    bg_img = Image.open(datadir + "DSC_1495_dark.jpg")
    bg_img = bg_img.crop((0, 0, 4000, 2848))
    dpi = pl.rcParams['figure.dpi']
    figsize = float(bg_img.size[0]) / dpi, float(bg_img.size[1]) / dpi
    
    fig = pl.figure(figsize=figsize)
    ax = pl.axes([0, 0, 1, 1], frameon=False)
    ax.set_axis_off()
    im = pl.imshow(bg_img)
    
    ax = pl.axes([0.01, -0.005, 1.01, 1], projection='3d')
    data = (loadtxt(datadir + "pl-image.txt")[14:950, 14:950] - 30) / 270
    height, width = data.shape
    bin = 1
    print data.min(), data.max()
    X = arange(data.shape[1])
    Y = arange(data.shape[0])
    tau = data[:, data.shape[1] // 2][:, None]
    T = 5.0
    t = linspace(0, T, data.shape[1])[None, :]
    f = 1 / (1 + exp(-T / (2 * tau)))
    Z = where(t < T / 2, 1 - f * exp(-t / tau), f * exp(-(t - T / 2) / tau))
    X, Y = meshgrid(X, Y)
    colors = rbow(data)
    colors[:, :, -1] = 0.6
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,
            linewidth=0, antialiased=True, shade=True)
    ax.set_xlim3d(0, data.shape[0] + 36.0 / bin)
    ax.set_ylim3d(18.0 / bin, data.shape[0] + 30.0 / bin)
    ax.set_zlim3d(-0.8, 1.1)
    ax.grid(False)
    ax.view_init(38, -55.5)
    ax.dist = 9.4
    for a in (ax.w_xaxis, ax.w_yaxis, ax.w_zaxis):
        for t in a.get_ticklines() + a.get_ticklabels():
            t.set_visible(False)
        a.line.set_visible(False)
        a.pane.set_visible(False)
    pl.savefig(picdir + "3d-plot.png", transparent=True)