Search code examples
pythonmatplotlibplotmatplotlib-3d

Plotting cylindrical map data over a 3D sphere


Suppose I have an image with a cylindrical map of a planet, say one of these:

http://www.johnstonsarchive.net/spaceart/cylmaps.html

And I want to plot it over a 3D sphere to recover the original figure of the planet.

Is there a way to do it using a Python package like matplotlib, mayavi, basemap or similar?


Solution

  • Update: This is the new version using Cartopy, as basemap is EOL. Below is the original answer.

    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    
    img = plt.imread("/tmp/venuscyl4.tif")
    
    plt.figure(figsize=(3, 3))
    
    ax = plt.axes(projection=ccrs.Orthographic(-10, 45))
    ax.gridlines(color='black', linestyle='dotted')
    ax.imshow(img, origin="upper", extent=(-180, 180, -90, 90),
              transform=ccrs.PlateCarree())  # Important
    
    plt.show()
    

    Venus map using Cartopy


    Thanks to Raphael Roth answer I finally found what I was looking for: the basemap method warpimage.

    Here is a very minimal example. Using this cylindrical map of Venus, and based on the simple example of the cookbook:

    from mpl_toolkits.basemap import Basemap
    import matplotlib.pyplot as plt
    import numpy as np
    # set up orthographic map projection with
    # perspective of satellite looking down at 50N, 100W.
    # use low resolution coastlines.
    # don't plot features that are smaller than 1000 square km.
    bmap = Basemap(projection='ortho', lat_0 = 50, lon_0 = -100,
                  resolution = 'l', area_thresh = 1000.)
    # plot surface
    bmap.warpimage(image='venuscyl4.jpg')
    # draw the edge of the map projection region (the projection limb)
    bmap.drawmapboundary()
    # draw lat/lon grid lines every 30 degrees.
    bmap.drawmeridians(np.arange(0, 360, 30))
    bmap.drawparallels(np.arange(-90, 90, 30))
    plt.show()
    

    produces the following output:

    Venus sphere map