Matplotlib/basemap: Plot a globe in the center of a plot

2k views Asked by At

I am trying to in python figure out how to use basemap to make plots like this:

enter image description here

Focusing on the upper left plot, this is a 2d histogram of density in each bin with a graphic Earth overlaid in the center.

The big issue I have is that basemap doesn't seem to play nicely as an overplot. I can pass axes in but it seems to take over these axes and not behave well. I would be really awesome to be able to use the basemap bluemarble interface to get a really cool looking Earth with the right shading and all for the current date and time and viewpoint.

In my case I am making 2d contour plots in polar (or using bar to get little curved boxes that look great) and want to place an earth spanning out to radius 1.

Here is an even simpler example of what doesn't work.

import matplotlib.pyplot as plt
import basemap
from mpl_toolkits.basemap import Basemap
plt.plot(range(-10,10))
ax = plt.gca()
map = Basemap(projection='ortho',lat_0=45,lon_0=-100,resolution='l', ax=ax)
map.fillcontinents(color='coral',lake_color='aqua')

As you can see basemap totally took over the axis and the plot made first is no where to be seen.

enter image description here

2

There are 2 answers

0
rapadulles On BEST ANSWER

You can try the following:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap

fig=plt.figure()
ax=fig.add_axes([.1,.1,.8,.8],polar=True) # This is the background axis

# variables for the background plot. I use some random numbers just for
# illustration purposes
N = 150
r = (1 - 0.8) * np.random.random_sample(N) +0.8
theta = 2*np.pi*np.random.random(N)
area = 200*r**2*np.random.random(N)

ax.scatter(theta, r, c=theta, s=area, cmap='hsv')

This plot has to be then formatted accordingly, in this case, with transparency and without axis information:

plt.setp(ax.get_xticklabels(),visible=False)
plt.setp(ax.get_yticklabels(),visible=False)
ax.patch.set_visible(False)
ax.grid(False)
ax.axis('off')

And finally, the earth globe using basemap:

ax2=fig.add_axes([.3,.3,.4,.4])
m = Basemap(projection='ortho',lon_0=-105,lat_0=-25,resolution='l',ax=ax2)
m.bluemarble(scale=.1) # scale=.1 for low resolution

The trick is to place the secondary axis (ax2) in the center using the add_axes method. You can play with the axes limits to obtain the numbers you need. Hope it helps. Example image of the code

2
Tim Seed On

Or switch to Carto

%matplotlib inline

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.PlateCarree())
ax.stock_img()

ny_lon, ny_lat = -75, 43
delhi_lon, delhi_lat = 77.23, 28.61


plt.text(ny_lon - 3, ny_lat - 12, 'New York',
         horizontalalignment='right',
         transform=ccrs.Geodetic())

plt.text(delhi_lon + 3, delhi_lat - 12, 'Delhi',
         horizontalalignment='left',
         transform=ccrs.Geodetic())

plt.show()