zxdawn
zxdawn

Reputation: 1005

How to set offset of Basemap in Python?

Here's one example of Basemap:

fig = plt.figure(figsize=(10,6))

ax = fig.add_subplot(121)
ax.set_title('Default')

# miller projection
map = Basemap(projection='mill',lon_0=180)
# plot coastlines, draw label meridians and parallels.
map.drawcoastlines()
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])

ax = fig.add_subplot(122)
ax.set_title('Add offset')

# miller projection
map = Basemap(projection='mill',lon_0=180)
# plot coastlines, draw label meridians and parallels.
map.drawcoastlines()
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0],xoffset=100,yoffset=100)
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],xoffset=100,yoffset=100)

I want to add more space between the xlabel/ylabel and axis. But, the space is smaller when xoffset and yoffset are added.

example

Upvotes: 1

Views: 808

Answers (2)

Jason
Jason

Reputation: 3266

I think you are not using the correct unit. @Thomas Kühn quoted the basemap doc:

xoffset: label offset from edge of map in x-direction (default is 0.01 times width of map in map projection coordinates).

yoffset: label offset from edge of map in y-direction (default is 0.01 times height of map in map projection coordinates).

Note that it is defaulted to 1% of the domain span measured in map projection coordinates.

If you check the span in y-axis of the mill projection you used, the length has 8 digits, so no wonder yoffset=100 gives no visual offset.

So an easier way is to modify the offset using the actual domain span, like:

map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],
        yoffset=0.01*abs(map.ymax-map.ymin))

This gives the same offset as default, i.e. 1% of the domain span (See figure (b) below). Changing 0.01 to 0.03 will be 3x of that (figure (c)).

If you instead use cyl projection which uses degree of latitude/longitude as units, the offsets are also measured in degrees, then yoffset=100 will be an insane offset. Figure (f) uses a yoffset=30, note that is the same distance as the distance from 60S to 90S.

enter image description here

The script to generate the figure:

import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
fig = plt.figure(figsize=(12,6))

def drawMap(proj):
    map = Basemap(projection=proj,lon_0=180)
    map.drawcoastlines()
    return map

# miller projection
ax = fig.add_subplot(231)
ax.set_title('(a) Mill, Default')
map=drawMap('mill')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])

ax = fig.add_subplot(232)
ax.set_title('(b) Mill, add same offset as default')
map=drawMap('mill')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0],
        xoffset=0.01*abs(map.xmax-map.xmin))
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],
        yoffset=0.01*abs(map.ymax-map.ymin))

ax = fig.add_subplot(233)
ax.set_title('(c) Mill, add 3x offset as default')
map=drawMap('mill')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0],
        xoffset=0.03*abs(map.xmax-map.xmin))
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],
        yoffset=0.03*abs(map.ymax-map.ymin))

ax = fig.add_subplot(234)
ax.set_title('(d) Cyl, Default')
map=drawMap('cyl')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])

ax = fig.add_subplot(235)
ax.set_title('(e) Cyl, add same offset as default')
map=drawMap('cyl')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0],
        xoffset=0.01*abs(map.xmax-map.xmin))
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],
        yoffset=0.01*abs(map.ymax-map.ymin))

ax = fig.add_subplot(236)
ax.set_title('(f) Cyl, add 30 degree offset')
map=drawMap('cyl')
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0],
        xoffset=0.03*abs(map.xmax-map.xmin))
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1],
        yoffset=30)

fig.subplots_adjust(hspace=0.01)
fig.show()

Upvotes: 0

Thomas Kühn
Thomas Kühn

Reputation: 9810

basemap is not being actively developed anymore, but maintenance still continues for some time. This means that things that break because of changes in other packages will still be fixed, but no new features will be added. Anyway, the fixing part may take some time and I'm guessing that the xoffset feature for the parallels and meridians is suffering from that. However, looking at the basemap documentation, the functionality of xoffset and yoffset are described as

xoffset: label offset from edge of map in x-direction (default is 0.01 times width of map in map projection coordinates).

yoffset: label offset from edge of map in y-direction (default is 0.01 times height of map in map projection coordinates).

This is easy enough to emulate by manipulating the Text objects that drawparallels() and drawmeridians() produce. The results of these functions are stored in a dict that contains a tuple of lists for each plotted parallel/meridian, the second of which contains the text labels. A Text object has a get_position() and a set_position() method, which, in combination with the axes limits and the definition above, can be used to compute the offset:

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

fig = plt.figure(figsize=(10,6))

ax = fig.add_subplot(121)
ax.set_title('Default')

# miller projection
map = Basemap(projection='mill',lon_0=180)
# plot coastlines, draw label meridians and parallels.
map.drawcoastlines()
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])

ax = fig.add_subplot(122)
ax.set_title('Add offset')

# miller projection
map = Basemap(projection='mill',lon_0=180)
# plot coastlines, draw label meridians and parallels.
map.drawcoastlines()

##getting axes dimensions
x0,x1 = ax.get_xlim()
w = x1-x0
y0,y1 = ax.get_ylim()
h = y1-y0

xoffset = 0.05
yoffset = 0.05

result = map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
##
for key, (lines,texts) in result.items():
    for text in texts:
        x,y = text.get_position()
        text.set_position((x0-xoffset*w,y))


result = map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])
for key, (lines,texts) in result.items():
    for text in texts:
        x,y = text.get_position()
        text.set_position((x,y0-yoffset*h))



plt.show()

The resulting plot looks like this:

Result of the above code

Upvotes: 1

Related Questions