Chris
Chris

Reputation: 291

Plotting a wrapped path in Basemap

I am trying to plot a satellite ground track. I have a list of latitudes and longitudes in degrees. The longitude values are all from -180 to +180 deg. My first issue is with using the latlon keyword (by the way, I'm using this in Julia via the PyCall.jl package, so forgive the weird-looking syntax):

map = Basemap.Basemap(projection="mill",lon_0=0)
map[:drawcoastlines]()
map[:drawparallels](-90:30:90,labels=[1,0,0,0])
map[:drawmeridians](map[:lonmin]:60:map[:lonmax]+30,labels=[0,0,0,1])
map[:plot](lon,lat,color="red",latlon=true)

Weird plot

This is... not what that should look like. I'm not really sure what the problem is. However, if I convert to map coordinates first:

xx,yy = map(lon,lat) 
map[:plot](xx,yy,color="red")

Better plot

This is much better, except for the line at the point that the longitude wraps from +180 to -180. Any suggestions for making this look nicer?

The latitude, longitude pairs (in degrees) used for generating these plots can be found here.

Upvotes: 3

Views: 3339

Answers (1)

lmillefiori
lmillefiori

Reputation: 486

At the beginning I thought this could be related to an old issue of Basemap. However, I think your problem is not due to Basemap, which is actually handling correctly the longitude wrapping, as you could see if you used only markers to plot the satellite ground track.

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

f = plt.figure(figsize(10,7.5))
m = Basemap(projection="mill", lon_0=0)

m.drawcoastlines()
m.drawparallels(np.arange(-90,91,30),labels=[1,0,0,0])
m.drawmeridians(np.arange(-180,181,60), labels=[0,0,0,1])

x,y = m(lon, lat)
m.plot(x, y, color="red", latlon=False, marker='.', linestyle='None')

enter image description here

The definitive solutions would be to split your ground track in multiple tracks and plot them using LineCollection, as also explained here. A simpler approach (if you expect one discontinuity in the longitude):

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

latlon_ar = np.array(latlon)

threshold = 90
idx_wrap = np.nonzero(np.abs(np.diff(latlon_ar[:,1])) > threshold)[0]+1

lon_1 = lon[:idx_wrap]
lat_1 = lat[:idx_wrap]

lon_2 = lon[idx_wrap:]
lat_2 = lat[idx_wrap:]

f = plt.figure(figsize(10,7.5))
m = Basemap(projection="mill", lon_0=0)

m.drawcoastlines()
m.drawparallels(np.arange(-90,91,30),labels=[1,0,0,0])
m.drawmeridians(np.arange(-180,181,60), labels=[0,0,0,1])

x1, y1 = m(lon_1, lat_1)
x2, y2 = m(lon_2, lat_2)

m.plot(x1, y1, color="red", latlon=False)
m.plot(x2, y2, color="blue", latlon=False)

enter image description here

Edit This confirmed bug in Basemap is responsible for the behaviour in the first example of the question, where Basemap.plot is called directly with latitude and longitude values, having set the latlon flag to True. There is a solution, that is to manually shift the input coordinates before plotting, as in the following code.

lons, lats = m.shiftdata(lon, lat)
m.plot(lons, lats, color="blue", latlon=True, marker='.', linestyle='None')

enter image description here

Upvotes: 8

Related Questions