Search code examples
pythonmatplotlibaxes

Add an image well outside the axes of my matplotlib plot


I have been making 3d plots for the first time using matplot lib.

I created this plot:

enter image description here

Using this code:

fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")

idx = 14

#origin

ax.scatter([0],[0],[0],s=200,marker='+',color='k')

#object1

ax.scatter(object1_z[idx],object1_ra[idx],object1_dec[idx], s=100, color='r',marker='o')

#cross1

ax.scatter(cross1_position[2],cross1_position[0],cross1_position[1], s=400, color='b',marker='X')

#b_hat

ax.quiver(cross1_position[2],cross1_position[0],cross1_position[1],b_hat_z[idx],b_hat_ra[idx],b_hat_dec[idx],arrow_length_ratio=0.1,lw=2,color='b')

#k_hat

ax.quiver(object1_z[idx],object1_ra[idx],object1_dec[idx],1,0,0,arrow_length_ratio=0.1,lw=2,color='b')

#axis

ax.quiver(cross1_position[2]+(0.05*(cross1_position[2]-axis[2])),cross1_position[0]+(0.05*(cross1_position[0]-axis[0])),cross1_position[1]+(0.05*(cross1_position[1]-axis[1])),axis[2],axis[0],axis[1],arrow_length_ratio=0.1,color='r',pivot='tip')
ax.quiver(cross1_position[2]-(0.05*(cross1_position[2]-axis[2])),cross1_position[0]-(0.05*(cross1_position[0]-axis[0])),cross1_position[1]-(0.05*(cross1_position[1]-axis[1])),-axis[2],-axis[0],-axis[1],arrow_length_ratio=0.1,color='r',pivot='tip')

#joining lines

ax.plot([cross1_position[2],object1_z[idx]],[cross1_position[0],object1_ra[idx]],[cross1_position[1],object1_dec[idx]],linestyle='--',color='k',lw=2)
ax.plot([cross1_position[2],53],[cross1_position[0],0],[cross1_position[1],0],linestyle='--',color='k',lw=2)
ax.plot([object1_z[idx],53],[object1_ra[idx],0],[object1_dec[idx],0],linestyle='--',color='k',lw=2)

# sphere

u = np.linspace(0, 2*np.pi, 100)
v = np.linspace(0, np.pi, 100)

x = np.outer(np.cos(u),np.sin(v))
y = np.outer(np.sin(u),np.sin(v))
z = np.outer(np.ones(np.size(u)),np.cos(v))
ax.plot_surface(x,y,z,rstride=4,cstride=4, color='r',alpha=0.1,facecolors=plt.cm.gray(z))



ax.set_xlabel('z')
ax.set_ylabel('x')
ax.set_zlabel('y')

ax.set_xlim(-1.3,1.3)
ax.set_ylim(-1.3,1.3)
ax.set_zlim(-1.3,1.3)

plt.show()

I would like to put another sphere in this following position, off of the first set of axes:

enter image description here

My question:

It is possible for me to do this using my existing axes? If I try to put my second sphere where I want, using co-ordinates (something like (x=0, y=0, z=5)), then that doesn't give me what I want because it squashes my existing image (along the z axis).

Do I need to add a second set of invisible axes or something like that?

In summary: what's a good way to place an image at the location of "HERE" in the above image.


Solution

  • I did a lot of research, but I couldn't find a way to add an image with only a 3D graph. So I used subplots, which is a 3D+2D graph, based on the official reference. Unfortunately, the right side of the graph is set to the center of the 3D graph and cannot be moved. This is not the answer you are looking for, but you may find it useful.

    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib.patches as patches
    import matplotlib.cbook as cbook
    
    fig = plt.figure(figsize=(18,9))
    
    
    test_img = '/Users/youraccount/Documents/Python/stackoverflow/logo-the-overflow.png'
    with cbook.get_sample_data(test_img) as image_file:
        image = plt.imread(image_file)
    
    # Make data
    u = np.linspace(0, 2 * np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    x = 10 * np.outer(np.cos(u), np.sin(v))
    y = 10 * np.outer(np.sin(u), np.sin(v))
    z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
    
    ax = fig.add_subplot(121, projection='3d')
    # Plot the surface
    ax.plot_surface(x, y, z)
    
    # Placement 0, 0 would be the bottom left, 1, 1 would be the top right.
    ax.text2D(1.5, 0.3, "2D Text", transform=ax.transAxes, fontsize=24)
    
    ax = fig.add_subplot(122)
    im = ax.imshow(image)
    patch = patches.Rectangle(xy=(1.0, -0.5), width=708, height=144, transform=ax.transData)
    im.set_clip_path(patch)
    ax.axis('off')
    
    plt.show()
    

    enter image description here