2011-11-17 45 views
13

我想在底图投影上绘制椭圆。要绘制一个像多边形的圆,可以使用tissot函数绘制Tissot's indicatrix',如下例所示。在matplotlib底图投影上绘制椭圆

from mpl_toolkits.basemap import Basemap 

x0, y0 = 35, -50 
R = 5 

m = Basemap(width=8000000,height=7000000, resolution='l',projection='aea', 
    lat_1=-40.,lat_2=-60,lon_0=35,lat_0=-50) 
m.drawcoastlines() 
m.tissot(x0, y0, R, 100, facecolor='g', alpha=0.5) 

但是,我有兴趣绘制省略号的形式(x-x0)**2/a**2 + (y-y0)**2/2 = 1

import pylab 
from matplotlib.patches import Ellipse 

fig = pylab.figure() 
ax = pylab.subplot(1, 1, 1, aspect='equal') 

x0, y0 = 35, -50 
w, h = 10, 5 
e = Ellipse(xy=(x0, y0), width=w, height=h, linewidth=2.0, color='g') 
ax.add_artist(e) 
e.set_clip_box(ax.bbox) 
e.set_alpha(0.7) 
pylab.xlim([20, 50]) 
pylab.ylim([-65, -35]) 

有没有一种方法来绘制与类似tissot的效果底图投影省略号:在另一方面,要定期笛卡尔网格我可以使用下面的示例代码绘制一个省略号?

回答

21

经过几小时分析底图tissot函数的源代码,学习ellipses的一些属性和很多的调试,我带着解决我的问题。我已经扩展了一个名为ellipse如下新功能底图类,

from __future__ import division 
import pylab 
import numpy 

from matplotlib.patches import Polygon 
from mpl_toolkits.basemap import pyproj 
from mpl_toolkits.basemap import Basemap 

class Basemap(Basemap): 
    def ellipse(self, x0, y0, a, b, n, ax=None, **kwargs): 
     """ 
     Draws a polygon centered at ``x0, y0``. The polygon approximates an 
     ellipse on the surface of the Earth with semi-major-axis ``a`` and 
     semi-minor axis ``b`` degrees longitude and latitude, made up of 
     ``n`` vertices. 

     For a description of the properties of ellipsis, please refer to [1]. 

     The polygon is based upon code written do plot Tissot's indicatrix 
     found on the matplotlib mailing list at [2]. 

     Extra keyword ``ax`` can be used to override the default axis instance. 

     Other \**kwargs passed on to matplotlib.patches.Polygon 

     RETURNS 
      poly : a maptplotlib.patches.Polygon object. 

     REFERENCES 
      [1] : http://en.wikipedia.org/wiki/Ellipse 


     """ 
     ax = kwargs.pop('ax', None) or self._check_ax() 
     g = pyproj.Geod(a=self.rmajor, b=self.rminor) 
     # Gets forward and back azimuths, plus distances between initial 
     # points (x0, y0) 
     azf, azb, dist = g.inv([x0, x0], [y0, y0], [x0+a, x0], [y0, y0+b]) 
     tsid = dist[0] * dist[1] # a * b 

     # Initializes list of segments, calculates \del azimuth, and goes on 
     # for every vertex 
     seg = [self(x0+a, y0)] 
     AZ = numpy.linspace(azf[0], 360. + azf[0], n) 
     for i, az in enumerate(AZ): 
      # Skips segments along equator (Geod can't handle equatorial arcs). 
      if numpy.allclose(0., y0) and (numpy.allclose(90., az) or 
       numpy.allclose(270., az)): 
       continue 

      # In polar coordinates, with the origin at the center of the 
      # ellipse and with the angular coordinate ``az`` measured from the 
      # major axis, the ellipse's equation is [1]: 
      # 
      #       a * b 
      # r(az) = ------------------------------------------ 
      #   ((b * cos(az))**2 + (a * sin(az))**2)**0.5 
      # 
      # Azymuth angle in radial coordinates and corrected for reference 
      # angle. 
      azr = 2. * numpy.pi/360. * (az + 90.) 
      A = dist[0] * numpy.sin(azr) 
      B = dist[1] * numpy.cos(azr) 
      r = tsid/(B**2. + A**2.)**0.5 
      lon, lat, azb = g.fwd(x0, y0, az, r) 
      x, y = self(lon, lat) 

      # Add segment if it is in the map projection region. 
      if x < 1e20 and y < 1e20: 
       seg.append((x, y)) 

     poly = Polygon(seg, **kwargs) 
     ax.add_patch(poly) 

     # Set axes limits to fit map region. 
     self.set_axes_limits(ax=ax) 

     return poly 

这项新功能可以在这个例子中立即使用,如:

pylab.close('all') 
pylab.ion() 

m = Basemap(width=12000000, height=8000000, resolution='l', projection='stere', 
      lat_ts=50, lat_0=50, lon_0=-107.) 
m.drawcoastlines() 
m.fillcontinents(color='coral',lake_color='aqua') 
# draw parallels and meridians. 
m.drawparallels(numpy.arange(-80.,81.,20.)) 
m.drawmeridians(numpy.arange(-180.,181.,20.)) 
m.drawmapboundary(fill_color='aqua') 
# draw ellipses 
ax = pylab.gca() 
for y in numpy.linspace(m.ymax/20, 19*m.ymax/20, 9): 
    for x in numpy.linspace(m.xmax/20, 19*m.xmax/20, 12): 
     lon, lat = m(x, y, inverse=True) 
     poly = m.ellipse(lon, lat, 3, 1.5, 100, facecolor='green', zorder=10, 
      alpha=0.5) 
pylab.title("Ellipses on stereographic projection") 

它具有以下结果: Sample figure

+4

我知道这可能看起来像回答我自己的问题作弊,但它花了我一段时间,一些启发来到这个解决方案。尽管如此,我认为我可以分享它。 – regeirk

+5

这不是作弊,这是正确的做法:http://meta.stackexchange.com/questions/12513/should-i-not-answer-my-own-questions – Yann