Search code examples
pythonmatplotlibplotmatplotlib-3d

How to plot a rotating 3D earth


I know we can create simple 3-Dimensional spheres using matplotlib, an example of such a sphere is included in the documentation.

Now, we also have a warp method as part of the matplotlib module, an example of it's usage is here .

To warp a cylindrical image to the sphere. Is it possible to combine these methods to create a 3D rotatable earth? Unless my way of thinking about this problem is way off it seems that to be able to do this you would have to take the pixel data of the image and then plot every pixel using the sin and cosine expressions along the surface of the 3D sphere being created in the first example. Some examples of these cylindrical maps can be found here

I know alternative ways to do this are through maya and blender, but I am attempting to stay within matplotlib to do this, as I want to create this plot and then be able to plot geospatial data to the surface using an array of data.


Solution

  • Interesting question. I tried to basically follow the thinking outlined by @Skeletor, and map the image so that it can be shown with plot_surface:

    import PIL
    import matplotlib.pyplot as plt
    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    
    # load bluemarble with PIL
    bm = PIL.Image.open('bluemarble.jpg')
    # it's big, so I'll rescale it, convert to array, and divide by 256 to get RGB values that matplotlib accept 
    bm = np.array(bm.resize([d/5 for d in bm.size]))/256.
    
    # coordinates of the image - don't know if this is entirely accurate, but probably close
    lons = np.linspace(-180, 180, bm.shape[1]) * np.pi/180 
    lats = np.linspace(-90, 90, bm.shape[0])[::-1] * np.pi/180 
    
    # repeat code from one of the examples linked to in the question, except for specifying facecolors:
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    
    x = np.outer(np.cos(lons), np.cos(lats)).T
    y = np.outer(np.sin(lons), np.cos(lats)).T
    z = np.outer(np.ones(np.size(lons)), np.sin(lats)).T
    ax.plot_surface(x, y, z, rstride=4, cstride=4, facecolors = bm)
    
    plt.show()
    

    Result: bluemarble.jpg shown in 3D with plot_surface