From: <js...@us...> - 2008-01-10 13:59:50
|
Revision: 4847 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4847&view=rev Author: jswhit Date: 2008-01-10 05:59:29 -0800 (Thu, 10 Jan 2008) Log Message: ----------- move matplotlit/toolkits to mpl_toolkits Modified Paths: -------------- trunk/toolkits/basemap/API_CHANGES trunk/toolkits/basemap/Changelog trunk/toolkits/basemap/setup.py trunk/toolkits/basemap/setupegg.py Added Paths: ----------- trunk/toolkits/basemap/lib/mpl_toolkits/ trunk/toolkits/basemap/lib/mpl_toolkits/__init__.py trunk/toolkits/basemap/lib/mpl_toolkits/basemap/ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_geod.so trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_proj.so trunk/toolkits/basemap/lib/mpl_toolkits/basemap/basemap.py trunk/toolkits/basemap/lib/mpl_toolkits/basemap/cm.py trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/5minmask.bin trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/GL27 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/README trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/__init__.py trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countries_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countries_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countries_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countries_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countries_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countriesmeta_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countriesmeta_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countriesmeta_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countriesmeta_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/countriesmeta_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/epsg trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/esri trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/esri.extra trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhs_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhs_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhs_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhs_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhs_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhsmeta_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhsmeta_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhsmeta_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhsmeta_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/gshhsmeta_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/nad.lst trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/nad27 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/nad83 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/ntv2_out.dist trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/other.extra trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/pj_out27.dist trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/pj_out83.dist trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/proj_def.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/rivers_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/rivers_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/rivers_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/rivers_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/rivers_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/riversmeta_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/riversmeta_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/riversmeta_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/riversmeta_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/riversmeta_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/states_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/states_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/states_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/states_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/states_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/statesmeta_c.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/statesmeta_f.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/statesmeta_h.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/statesmeta_i.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/statesmeta_l.dat trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/td_out.dist trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/test27 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/test83 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/testntv2 trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/testvarious trunk/toolkits/basemap/lib/mpl_toolkits/basemap/data/world Removed Paths: ------------- trunk/toolkits/basemap/lib/matplotlib/ Modified: trunk/toolkits/basemap/API_CHANGES =================================================================== --- trunk/toolkits/basemap/API_CHANGES 2008-01-10 13:38:37 UTC (rev 4846) +++ trunk/toolkits/basemap/API_CHANGES 2008-01-10 13:59:29 UTC (rev 4847) @@ -1,3 +1,5 @@ +version 0.99: now must be imported as mpl_toolkits.basemap instead + of matplotlib.toolkits.basemap. version 0.9.8: remove linestyle kwarg from drawparallels and drawmeridians. add fill_color kwarg to drawmapboundary. version 0.9.7: added lake_color kwarg to fillcontinents. Modified: trunk/toolkits/basemap/Changelog =================================================================== --- trunk/toolkits/basemap/Changelog 2008-01-10 13:38:37 UTC (rev 4846) +++ trunk/toolkits/basemap/Changelog 2008-01-10 13:59:29 UTC (rev 4847) @@ -1,3 +1,10 @@ +version 0.9.9.2 + * Now lives in mpl_toolkits.basemap. Instead + of 'from matplotlib.toolkits.basemap import Basemap', + use 'from mpl_toolkits.basemap import Basemap'. + All examples changed. Uses matplotlib mpl_toolkits + namespace package, so basemap can now be installed + if matplotlib is installed as an egg. version 0.9.9.1 (svn revision 4808) * require python 2.4 (really only needed for building). Once namespace packages are re-enabled in matplotlib, Added: trunk/toolkits/basemap/lib/mpl_toolkits/__init__.py =================================================================== --- trunk/toolkits/basemap/lib/mpl_toolkits/__init__.py (rev 0) +++ trunk/toolkits/basemap/lib/mpl_toolkits/__init__.py 2008-01-10 13:59:29 UTC (rev 4847) @@ -0,0 +1,4 @@ +try: + __import__('pkg_resources').declare_namespace(__name__) +except ImportError: + pass # must not have setuptools Added: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py =================================================================== --- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py (rev 0) +++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/__init__.py 2008-01-10 13:59:29 UTC (rev 4847) @@ -0,0 +1,2 @@ +from basemap import __doc__, __version__ +from basemap import * Added: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_geod.so =================================================================== (Binary files differ) Property changes on: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_geod.so ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_proj.so =================================================================== (Binary files differ) Property changes on: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/_proj.so ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/toolkits/basemap/lib/mpl_toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap/lib/mpl_toolkits/basemap/basemap.py (rev 0) +++ trunk/toolkits/basemap/lib/mpl_toolkits/basemap/basemap.py 2008-01-10 13:59:29 UTC (rev 4847) @@ -0,0 +1,2981 @@ +""" +Module for plotting data on maps with matplotlib. + +Contains the Basemap class (which does most of the +heavy lifting), and the following functions: + +NetCDFFile: Read local and remote NetCDF datasets. + +interp: bilinear interpolation between rectilinear grids. + +shiftgrid: shifts global lat/lon grids east or west. + +addcyclic: Add cyclic (wraparound) point in longitude. + +num2date: convert from a numeric time value to a datetime object. + +date2num: convert from a datetime object to a numeric time value. +""" +from matplotlib import __version__ as _matplotlib_version +from matplotlib.cbook import is_scalar, dedent +# check to make sure matplotlib is not too old. +_mpl_required_version = '0.98' +if _matplotlib_version < _mpl_required_version: + msg = dedent(""" + your matplotlib is too old - basemap requires version %s or + higher, you have version %s""" % + (_mpl_required_version,_matplotlib_version)) + raise ImportError(msg) +from matplotlib import rcParams, is_interactive, _pylab_helpers +from matplotlib.collections import LineCollection +from matplotlib.patches import Ellipse, Circle, Polygon +from matplotlib.lines import Line2D +import pyproj, sys, os, math, dbflib +from proj import Proj +import numpy as npy +from numpy import linspace, squeeze, ma +from shapelib import ShapeFile +import _geos, pupynere, netcdftime + +# basemap data files now installed in lib/matplotlib/toolkits/basemap/data +basemap_datadir = os.sep.join([os.path.dirname(__file__), 'data']) + +__version__ = '0.99' + +# supported map projections. +_projnames = {'cyl' : 'Cylindrical Equidistant', + 'merc' : 'Mercator', + 'tmerc' : 'Transverse Mercator', + 'omerc' : 'Oblique Mercator', + 'mill' : 'Miller Cylindrical', + 'lcc' : 'Lambert Conformal', + 'laea' : 'Lambert Azimuthal Equal Area', + 'nplaea' : 'North-Polar Lambert Azimuthal', + 'splaea' : 'South-Polar Lambert Azimuthal', + 'eqdc' : 'Equidistant Conic', + 'aeqd' : 'Azimuthal Equidistant', + 'npaeqd' : 'North-Polar Azimuthal Equidistant', + 'spaeqd' : 'South-Polar Azimuthal Equidistant', + 'aea' : 'Albers Equal Area', + 'stere' : 'Stereographic', + 'npstere' : 'North-Polar Stereographic', + 'spstere' : 'South-Polar Stereographic', + 'cass' : 'Cassini-Soldner', + 'poly' : 'Polyconic', + 'ortho' : 'Orthographic', + 'geos' : 'Geostationary', + 'sinu' : 'Sinusoidal', + 'moll' : 'Mollweide', + 'robin' : 'Robinson', + 'gnom' : 'Gnomonic', + } +supported_projections = [] +for _items in _projnames.iteritems(): + supported_projections.append("'%s' = %s\n" % (_items)) +supported_projections = ''.join(supported_projections) + +# projection specific parameters. +projection_params = {'cyl' : 'corners only (no width/height)', + 'merc' : 'corners plus lat_ts (no width/height)', + 'tmerc' : 'lon_0,lat_0', + 'omerc' : 'lon_0,lat_0,lat_1,lat_2,lon_1,lon_2,no width/height', + 'mill' : 'corners only (no width/height)', + 'lcc' : 'lon_0,lat_0,lat_1,lat_2', + 'laea' : 'lon_0,lat_0', + 'nplaea' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'splaea' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'eqdc' : 'lon_0,lat_0,lat_1,lat_2', + 'aeqd' : 'lon_0,lat_0', + 'npaeqd' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'spaeqd' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'aea' : 'lon_0,lat_0,lat_1', + 'stere' : 'lon_0,lat_0,lat_ts', + 'npstere' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'spstere' : 'bounding_lat,lon_0,lat_0,no corners or width/height', + 'cass' : 'lon_0,lat_0', + 'poly' : 'lon_0,lat_0', + 'ortho' : 'lon_0,lat_0', + 'geos' : 'lon_0,lat_0,satellite_height', + 'sinu' : 'lon_0,lat_0,no corners or width/height', + 'moll' : 'lon_0,lat_0,no corners or width/height', + 'robin' : 'lon_0,lat_0,no corners or width/height', + 'gnom' : 'lon_0,lat_0', + } + +# The __init__ docstring is pulled out here because it is so long; +# Having it in the usual place makes it hard to get from the +# __init__ argument list to the code that uses the arguments. +_Basemap_init_doc = """ + create a Basemap instance. + + This sets up a basemap with specified map projection. + and creates the coastline data structures in native map projection + coordinates. + + arguments: + + projection - map projection. Supported projections are: +%(supported_projections)s + Default is 'cyl'. + + For most map projections, the map projection region can either be + specified by setting these keywords: + + llcrnrlon - longitude of lower left hand corner of the desired map domain (degrees). + llcrnrlat - latitude of lower left hand corner of the desired map domain (degrees). + urcrnrlon - longitude of upper right hand corner of the desired map domain (degrees). + urcrnrlat - latitude of upper right hand corner of the desired map domain (degrees). + + or these keywords: + + width - width of desired map domain in projection coordinates (meters). + height - height of desired map domain in projection coordinates (meters). + lon_0 - center of desired map domain (in degrees). + lat_0 - center of desired map domain (in degrees). + + For 'sinu', 'moll', 'npstere', 'spstere', 'nplaea', 'splaea', 'nplaea', + 'splaea', 'npaeqd', 'spaeqd' or 'robin', the values of + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat,width and height are ignored + (because either they are computed internally, or entire globe is + always plotted). For the cylindrical projections + ('cyl','merc' and 'mill'), the default is to use + llcrnrlon=-180,llcrnrlat=-90, urcrnrlon=180 and urcrnrlat=90). For all other + projections except 'ortho' and 'geos', either the lat/lon values of the + corners or width and height must be specified by the user. + For 'ortho' and 'geos', the lat/lon values of the corners may be specified, + but if they are not, the entire globe is plotted. + + resolution - resolution of boundary database to use. Can be 'c' (crude), + 'l' (low), 'i' (intermediate), 'h' (high), 'f' (full) or None. + If None, no boundary data will be read in (and class methods + such as drawcoastlines will raise an exception if invoked). + Resolution drops off by roughly 80%% + between datasets. Higher res datasets are much slower to draw. + Default 'c'. Coastline data is from the GSHHS + (http://www.soest.hawaii.edu/wessel/gshhs/gshhs.html). + State, country and river datasets from the Generic Mapping + Tools (http://gmt.soest.hawaii.edu). + + area_thresh - coastline or lake with an area smaller than area_thresh + in km^2 will not be plotted. Default 10000,1000,100,10,1 for resolution + 'c','l','i','h','f'. + + rsphere - radius of the sphere used to define map projection (default + 6370997 meters, close to the arithmetic mean radius of the earth). If + given as a sequence, the first two elements are interpreted as + the the radii of the major and minor axes of an ellipsoid. Note: sometimes + an ellipsoid is specified by the major axis and an 'inverse flattening + parameter' (if). The minor axis (b) can be computed from the major axis (a) + and the inverse flattening parameter using the formula if = a/(a-b). + + suppress_ticks - suppress automatic drawing of axis ticks and labels + in map projection coordinates. Default False, so parallels and meridians + can be labelled instead. If parallel or meridian labelling is requested + (using drawparallels and drawmeridians methods), automatic tick labelling + will be supressed even is suppress_ticks=False. suppress_ticks=False + is useful if you want to use your own custom tick formatter, or + if you want to let matplotlib label the axes in meters + using native map projection coordinates + + anchor - determines how map is placed in axes rectangle (passed to + axes.set_aspect). Default is 'C', which means map is centered. + Allowed values are ['C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W']. + + ax - set default axes instance (default None - pylab.gca() may be used + to get the current axes instance). If you don't want pylab to be imported, + you can either set this to a pre-defined axes instance, or use the 'ax' + keyword in each Basemap method call that does drawing. In the first case, + all Basemap method calls will draw to the same axes instance. In the + second case, you can draw to different axes with the same Basemap instance. + You can also use the 'ax' keyword in individual method calls to + selectively override the default axes instance. + + The following parameters are map projection parameters which all default to + None. Not all parameters are used by all projections, some are ignored. + The module variable 'projection_params' is a dictionary which + lists which parameters apply to which projections. + + lat_ts - latitude of true scale for mercator projection, optional + for stereographic projection. + lat_1 - first standard parallel for lambert conformal, albers + equal area projection and equidistant conic projections. Latitude of one + of the two points on the projection centerline for oblique mercator. + If lat_1 is not given, but lat_0 is, lat_1 is set to lat_0 for + lambert conformal, albers equal area and equidistant conic. + lat_2 - second standard parallel for lambert conformal, albers + equal area projection and equidistant conic projections. Latitude of one + of the two points on the projection centerline for oblique mercator. + If lat_2 is not given, it is set to lat_1 for + lambert conformal, albers equal area and equidistant conic. + lon_1 - longitude of one of the two points on the projection centerline + for oblique mercator. + lon_2 - longitude of one of the two points on the projection centerline + for oblique mercator. + lat_0 - central latitude (y-axis origin) - used by all projections, + Must be equator for mercator projection. + lon_0 - central meridian (x-axis origin) - used by all projections, + boundinglat - bounding latitude for pole-centered projections (npstere,spstere, + nplaea,splaea,npaeqd,spaeqd). These projections are square regions centered + on the north or south pole. The longitude lon_0 is at 6-o'clock, and the + latitude circle boundinglat is tangent to the edge of the map at lon_0. + satellite_height - height of satellite (in m) above equator - + only relevant for geostationary projections ('geos'). Default 35,786 km. + + Here are the most commonly used class methods (see the docstring + for each for more details): + + To draw a graticule grid (labelled latitude and longitude lines) + use the drawparallels and drawmeridians methods. + + To draw coastline, rivers and political boundaries, use the + the drawcontinents, drawrivers, drawcountries and drawstates methods. + + To fill the continents and inland lakes, use the fillcontinents method. + + To draw the boundary of the map projection region, and fill the + interior a certain color, use the drawmapboundary method. + + The contour, contourf, pcolor, pcolormesh, plot, scatter + quiver and imshow methods use the corresponding matplotlib axes + methods to draw on the map. + + The transform_scalar method can be used to interpolate regular + lat/lon grids of scalar data to native map projection grids. + + The transform_vector method can be used to interpolate and rotate + regular lat/lon grids of vector data to native map projection grids. + + The rotate_vector method rotates a vector field from lat/lon + coordinates into map projections coordinates, without doing any + interpolation. + + The readshapefile method can be used to read in data from ESRI + shapefiles. + + The drawgreatcircle method draws great circles on the map. +""" % locals() + +# unsupported projection error message. +_unsupported_projection = ["'%s' is an unsupported projection.\n"] +_unsupported_projection.append("The supported projections are:\n") +_unsupported_projection.append(supported_projections) +_unsupported_projection = ''.join(_unsupported_projection) + +def _validated_ll(param, name, minval, maxval): + param = float(param) + if param > maxval or param < minval: + raise ValueError('%s must be between %f and %f degrees' % + (name, minval, maxval)) + return param + +def _insert_validated(d, param, name, minval, maxval): + if param is not None: + d[name] = _validated_ll(param, name, minval, maxval) + +class Basemap(object): + """ + Class for plotting data on map projections with matplotlib. + See __init__ docstring for details on how to create a class + instance for a given map projection. + + Useful instance variables: + + projection - map projection. Print the module variable + "supported_projections" to see a list. + aspect - map aspect ratio (size of y dimension / size of x dimension). + llcrnrlon - longitude of lower left hand corner of the desired map domain. + llcrnrlon - latitude of lower left hand corner of the desired map domain. + urcrnrlon - longitude of upper right hand corner of the desired map domain. + urcrnrlon - latitude of upper right hand corner of the desired map domain. + llcrnrx,llcrnry,urcrnrx,urcrnry - corners of map domain in projection coordinates. + rmajor,rminor - equatorial and polar radii of ellipsoid used (in meters). + resolution - resolution of boundary dataset being used ('c' for crude, + 'l' for low, etc.). If None, no boundary dataset is associated with the + Basemap instance. + srs - a string representing the 'spatial reference system' for the map + projection as defined by PROJ.4. + + Example Usage: + + >>> from mpl_toolkits.basemap import Basemap + >>> from pylab import load, meshgrid, title, arange, show + >>> # read in topo data (on a regular lat/lon grid) + >>> etopo = load('etopo20data.gz') + >>> lons = load('etopo20lons.gz') + >>> lats = load('etopo20lats.gz') + >>> # create Basemap instance for Robinson projection. + >>> m = Basemap(projection='robin',lon_0=0.5*(lons[0]+lons[-1])) + >>> # compute native map projection coordinates for lat/lon grid. + >>> x, y = m(*meshgrid(lons,lats)) + >>> # make filled contour plot. + >>> cs = m.contourf(x,y,etopo,30,cmap=cm.jet) + >>> m.drawcoastlines() # draw coastlines + >>> m.drawmapboundary() # draw a line around the map region + >>> m.drawparallels(arange(-90.,120.,30.),labels=[1,0,0,0]) # draw parallels + >>> m.drawmeridians(arange(0.,420.,60.),labels=[0,0,0,1]) # draw meridians + >>> title('Robinson Projection') # add a title + >>> show() + + [this example (simpletest.py) plus many others can be found in the + examples directory of source distribution. The "OO" version of this + example (which does not use pylab) is called "simpletest_oo.py".] + """ + + def __init__(self, llcrnrlon=None, llcrnrlat=None, + urcrnrlon=None, urcrnrlat=None, + width=None, height=None, + projection='cyl', resolution='c', + area_thresh=None, rsphere=6370997.0, + lat_ts=None, + lat_1=None, lat_2=None, + lat_0=None, lon_0=None, + lon_1=None, lon_2=None, + suppress_ticks=True, + satellite_height=35786000, + boundinglat=None, + anchor='C', + ax=None): + # docstring is added after __init__ method definition + + # where to put plot in figure (default is 'C' or center) + self.anchor = anchor + # map projection. + self.projection = projection + + # set up projection parameter dict. + projparams = {} + projparams['proj'] = projection + try: + if rsphere[0] > rsphere[1]: + projparams['a'] = rsphere[0] + projparams['b'] = rsphere[1] + else: + projparams['a'] = rsphere[1] + projparams['b'] = rsphere[0] + except: + if projection == 'tmerc': + # use bR_a instead of R because of obscure bug + # in proj4 for tmerc projection. + projparams['bR_a'] = rsphere + else: + projparams['R'] = rsphere + # set units to meters. + projparams['units']='m' + # check for sane values of lon_0, lat_0, lat_ts, lat_1, lat_2 + _insert_validated(projparams, lat_0, 'lat_0', -90, 90) + _insert_validated(projparams, lat_1, 'lat_1', -90, 90) + _insert_validated(projparams, lat_2, 'lat_2', -90, 90) + _insert_validated(projparams, lat_ts, 'lat_ts', -90, 90) + _insert_validated(projparams, lon_0, 'lon_0', -360, 720) + _insert_validated(projparams, lon_1, 'lon_1', -360, 720) + _insert_validated(projparams, lon_2, 'lon_2', -360, 720) + if projection == 'geos': + projparams['h'] = satellite_height + # check for sane values of projection corners. + using_corners = (None not in [llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat]) + if using_corners: + self.llcrnrlon = _validated_ll(llcrnrlon, 'llcrnrlon', -360, 720) + self.urcrnrlon = _validated_ll(urcrnrlon, 'urcrnrlon', -360, 720) + self.llcrnrlat = _validated_ll(llcrnrlat, 'llcrnrlat', -90, 90) + self.urcrnrlat = _validated_ll(urcrnrlat, 'urcrnrlat', -90, 90) + + # for each of the supported projections, + # compute lat/lon of domain corners + # and set values in projparams dict as needed. + + if projection in ['lcc', 'eqdc', 'aea']: + # if lat_0 is given, but not lat_1, + # set lat_1=lat_0 + if lat_1 is None and lat_0 is not None: + lat_1 = lat_0 + projparams['lat_1'] = lat_1 + if lat_1 is None or lon_0 is None: + raise ValueError('must specify lat_1 or lat_0 and lon_0 for %s basemap (lat_2 is optional)' % _projnames[projection]) + if lat_2 is None: + projparams['lat_2'] = lat_1 + if not using_corners: + if width is None or height is None: + raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters' + if lon_0 is None or lat_0 is None: + raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region' + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams) + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection == 'stere': + if lat_0 is None or lon_0 is None: + raise ValueError, 'must specify lat_0 and lon_0 for Stereographic basemap (lat_ts is optional)' + if not using_corners: + if width is None or height is None: + raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters' + if lon_0 is None or lat_0 is None: + raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region' + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams) + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection in ['spstere', 'npstere', + 'splaea', 'nplaea', + 'spaeqd', 'npaeqd']: + if boundinglat is None or lon_0 is None: + raise ValueError('must specify boundinglat and lon_0 for %s basemap' % _projnames[projection]) + if projection[0] == 's': + sgn = -1 + else: + sgn = 1 + rootproj = projection[2:] + projparams['proj'] = rootproj + if rootproj == 'stere': + projparams['lat_ts'] = sgn * 90. + projparams['lat_0'] = sgn * 90. + self.llcrnrlon = lon_0 - sgn*45. + self.urcrnrlon = lon_0 + sgn*135. + proj = pyproj.Proj(projparams) + x,y = proj(lon_0,boundinglat) + lon,self.llcrnrlat = proj(math.sqrt(2.)*y,0.,inverse=True) + self.urcrnrlat = self.llcrnrlat + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % _projnames[projection] + elif projection == 'laea': + if lat_0 is None or lon_0 is None: + raise ValueError, 'must specify lat_0 and lon_0 for Lambert Azimuthal basemap' + if not using_corners: + if width is None or height is None: + raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters' + if lon_0 is None or lat_0 is None: + raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region' + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams) + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection == 'merc': + if lat_ts is None: + raise ValueError, 'must specify lat_ts for Mercator basemap' + # clip plot region to be within -89.99S to 89.99N + # (mercator is singular at poles) + if not using_corners: + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + if llcrnrlat < -89.99: llcrnrlat = -89.99 + if llcrnrlat > 89.99: llcrnrlat = 89.99 + if urcrnrlat < -89.99: urcrnrlat = -89.99 + if urcrnrlat > 89.99: urcrnrlat = 89.99 + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + elif projection in ['tmerc','gnom','cass','poly'] : + if lat_0 is None or lon_0 is None: + raise ValueError, 'must specify lat_0 and lon_0 for Transverse Mercator, Gnomonic, Cassini-Soldnerr Polyconic basemap' + if not using_corners: + if width is None or height is None: + raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters' + if lon_0 is None or lat_0 is None: + raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region' + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams) + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection == 'ortho': + if not projparams.has_key('R'): + raise ValueError, 'orthographic projection only works for perfect spheres - not ellipsoids' + if lat_0 is None or lon_0 is None: + raise ValueError, 'must specify lat_0 and lon_0 for Orthographic basemap' + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + if not using_corners: + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + self._fulldisk = True + else: + self._fulldisk = False + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + # FIXME: won't work for points exactly on equator?? + if npy.abs(lat_0) < 1.e-2: lat_0 = 1.e-2 + projparams['lat_0'] = lat_0 + elif projection == 'geos': + if lon_0 is None: + raise ValueError, 'must specify lon_0 for Geostationary basemap' + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + if not using_corners: + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + self._fulldisk = True + else: + self._fulldisk = False + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection in ['moll','robin','sinu']: + if lon_0 is None: + raise ValueError, 'must specify lon_0 for Robinson, Mollweide, or Sinusoidal basemap' + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection == 'omerc': + if lat_1 is None or lon_1 is None or lat_2 is None or lon_2 is None: + raise ValueError, 'must specify lat_1,lon_1 and lat_2,lon_2 for Oblique Mercator basemap' + projparams['lat_1'] = lat_1 + projparams['lon_1'] = lon_1 + projparams['lat_2'] = lat_2 + projparams['lon_2'] = lon_2 + if not using_corners: + raise ValueError, 'cannot specify map region with width and height keywords for this projection, please specify lat/lon values of corners' + elif projection == 'aeqd': + if lat_0 is None or lon_0 is None: + raise ValueError, 'must specify lat_0 and lon_0 for Azimuthal Equidistant basemap' + if not using_corners: + if width is None or height is None: + raise ValueError, 'must either specify lat/lon values of corners (llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters' + if lon_0 is None or lat_0 is None: + raise ValueError, 'must specify lon_0 and lat_0 when using width, height to specify projection region' + llcrnrlon,llcrnrlat,urcrnrlon,urcrnrlat = _choosecorners(width,height,**projparams) + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + elif projection == 'mill': + if not using_corners: + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + elif projection == 'cyl': + if not using_corners: + llcrnrlon = -180. + llcrnrlat = -90. + urcrnrlon = 180 + urcrnrlat = 90. + self.llcrnrlon = llcrnrlon; self.llcrnrlat = llcrnrlat + self.urcrnrlon = urcrnrlon; self.urcrnrlat = urcrnrlat + if width is not None or height is not None: + print 'warning: width and height keywords ignored for %s projection' % self.projection + else: + raise ValueError(_unsupported_projection % projection) + + # initialize proj4 + proj = Proj(projparams,self.llcrnrlon,self.llcrnrlat,self.urcrnrlon,self.urcrnrlat) + + # make sure axis ticks are suppressed. + self.noticks = suppress_ticks + + # make Proj instance a Basemap instance variable. + self.projtran = proj + # copy some Proj attributes. + atts = ['rmajor','rminor','esq','flattening','ellipsoid','projparams'] + for att in atts: + self.__dict__[att] = proj.__dict__[att] + # these only exist for geostationary projection. + if hasattr(proj,'_width'): + self.__dict__['_width'] = proj.__dict__['_width'] + if hasattr(proj,'_height'): + self.__dict__['_height'] = proj.__dict__['_height'] + # spatial reference string (useful for georeferencing output + # images with gdal_translate). + if hasattr(self,'_proj4'): + self.srs = proj._proj4.srs + else: + pjargs = [] + for key,value in self.projparams.iteritems(): + # 'cyl' projection translates to 'eqc' in PROJ.4 + if projection == 'cyl' and key == 'proj': + value = 'eqc' + # ignore x_0 and y_0 settings for 'cyl' projection + # (they are not consistent with what PROJ.4 uses) + elif projection == 'cyl' and key in ['x_0','y_0']: + continue + pjargs.append('+'+key+"="+str(value)+' ') + self.srs = ''.join(pjargs) + # set instance variables defining map region. + self.xmin = proj.xmin + self.xmax = proj.xmax + self.ymin = proj.ymin + self.ymax = proj.ymax + if projection == 'cyl': + self.aspect = (self.urcrnrlat-self.llcrnrlat)/(self.urcrnrlon-self.llcrnrlon) + else: + self.aspect = (proj.ymax-proj.ymin)/(proj.xmax-proj.xmin) + self.llcrnrx = proj.llcrnrx + self.llcrnry = proj.llcrnry + self.urcrnrx = proj.urcrnrx + self.urcrnry = proj.urcrnry + + # set min/max lats for projection domain. + if projection in ['mill','cyl','merc']: + self.latmin = self.llcrnrlat + self.latmax = self.urcrnrlat + elif projection in ['ortho','geos','moll','robin','sinu']: + self.latmin = -90. + self.latmax = 90. + else: + lons, lats = self.makegrid(101,101) + self.latmin = lats.min() + self.latmax = lats.max() + + # if ax == None, pylab.gca may be used. + self.ax = ax + self.lsmask = None + + # set defaults for area_thresh. + self.resolution = resolution + if area_thresh is None and resolution is not None: + if resolution == 'c': + area_thresh = 10000. + elif resolution == 'l': + area_thresh = 1000. + elif resolution == 'i': + area_thresh = 100. + elif resolution == 'h': + area_thresh = 10. + elif resolution == 'f': + area_thresh = 1. + else: + raise ValueError, "boundary resolution must be one of 'c','l','i','h' or 'f'" + self.area_thresh = area_thresh + # define map boundary polygon (in lat/lon coordinates) + self._boundarypolyll, self._boundarypolyxy = self._getmapboundary() + # read in coastline polygons, only keeping those that + # intersect map boundary polygon. + if self.resolution is not None: + self.coastsegs, self.coastpolygontypes = self._readboundarydata('gshhs') + # reformat for use in matplotlib.patches.Polygon. + self.coastpolygons = [] + # also, split coastline segments that jump across entire plot. + coastsegs = [] + for seg in self.coastsegs: + x, y = zip(*seg) + self.coastpolygons.append((x,y)) + x = npy.array(x,npy.float64); y = npy.array(y,npy.float64) + xd = (x[1:]-x[0:-1])**2 + yd = (y[1:]-y[0:-1])**2 + dist = npy.sqrt(xd+yd) + split = dist > 5000000. + if npy.sum(split) and self.projection not in ['merc','cyl','mill']: + ind = (npy.compress(split,squeeze(split*npy.indices(xd.shape)))+1).tolist() + iprev = 0 + ind.append(len(xd)) + for i in ind: + # don't add empty lists. + if len(range(iprev,i)): + coastsegs.append(zip(x[iprev:i],y[iprev:i])) + iprev = i + else: + coastsegs.append(seg) + self.coastsegs = coastsegs + # set __init__'s docstring + __init__.__doc__ = _Basemap_init_doc + + def __call__(self,x,y,inverse=False): + """ + Calling a Basemap class instance with the arguments lon, lat will + convert lon/lat (in degrees) to x/y native map projection + coordinates (in meters). If optional keyword 'inverse' is + True (default is False), the inverse transformation from x/y + to lon/lat is performed. + + For cylindrical equidistant projection ('cyl'), this + does nothing (i.e. x,y == lon,lat). + + For non-cylindrical projections, the inverse transformation + always returns longitudes between -180 and 180 degrees. For + cylindrical projections (self.projection == 'cyl','mill' or 'merc') + the inverse transformation will return longitudes between + self.llcrnrlon and self.llcrnrlat. + + input arguments lon, lat can be either scalar floats or N arrays. + """ + return self.projtran(x,y,inverse=inverse) + + def makegrid(self,nx,ny,returnxy=False): + """ + return arrays of shape (ny,nx) containing lon,lat coordinates of + an equally spaced native projection grid. + if returnxy = True, the x,y values of the grid are returned also. + """ + return self.projtran.makegrid(nx,ny,returnxy=returnxy) + + def _readboundarydata(self,name): + """ + read boundary data, clip to map projection region. + """ + msg = dedent(""" + Unable to open boundary dataset file. Only the 'crude', 'low', + 'intermediate' and 'high' resolution datasets are installed by default. + If you are requesting a 'full' resolution dataset, you may need to + download and install those files separately + (see the basemap README for details).""") + try: + bdatfile = open(os.path.join(basemap_datadir,name+'_'+self.resolution+'.dat'),'rb') + bdatmetafile = open(os.path.join(basemap_datadir,name+'meta_'+self.resolution+'.dat'),'r') + except: + raise IOError, msg + polygons = [] + polygon_types = [] + # coastlines are polygons, other boundaries are line segments. + if name == 'gshhs': + Shape = _geos.Polygon + else: + Shape = _geos.LineString + # see if map projection region polygon contains a pole. + NPole = _geos.Point(self(0.,90.)) + SPole = _geos.Point(self(0.,-90.)) + boundarypolyxy = self._boundarypolyxy + boundarypolyll = self._boundarypolyll + hasNP = NPole.within(boundarypolyxy) + hasSP = SPole.within(boundarypolyxy) + containsPole = hasNP or hasSP + # these projections cannot cross pole. + if containsPole and\ + self.projection in ['tmerc','cass','omerc','merc','mill','cyl','robin','moll','sinu','geos']: + raise ValueError('%s projection cannot cross pole'%(self.projection)) + # make sure orthographic projection has containsPole=True + # we will compute the intersections in stereographic + # coordinates, then transform to orthographic. + if self.projection == 'ortho' and name == 'gshhs': + containsPole = True + lon_0=self.projparams['lon_0'] + lat_0=self.projparams['lat_0'] + re = self.projparams['R'] + # center of stereographic projection restricted to be + # nearest one of 6 points on the sphere (every 90 deg lat/lon). + lon0 = 90.*(npy.around(lon_0/90.)) + lat0 = 90.*(npy.around(lat_0/90.)) + if npy.abs(int(lat0)) == 90: lon0=0. + maptran = pyproj.Proj(proj='stere',lon_0=lon0,lat_0=lat0,R=re) + # boundary polygon for orthographic projection + # in stereographic coorindates. + b = self._boundarypolyll.boundary + blons = b[:,0]; blats = b[:,1] + b[:,0], b[:,1] = maptran(blons, blats) + boundarypolyxy = _geos.Polygon(b) + for line in bdatmetafile: + linesplit = line.split() + area = float(linesplit[1]) + south = float(linesplit[3]) + north = float(linesplit[4]) + if area < 0.: area = 1.e30 + useit = self.latmax>=south and self.latmin<=north and area>self.area_thresh + if useit: + type = int(linesplit[0]) + npts = int(linesplit[2]) + offsetbytes = int(linesplit[5]) + bytecount = int(linesplit[6]) + bdatfile.seek(offsetbytes,0) + # read in binary string convert into an npts by 2 + # numpy array (first column is lons, second is lats). + polystring = bdatfile.read(bytecount) + # binary data is little endian. + b = npy.array(npy.fromstring(polystring,dtype='<f4'),'f8') + b.shape = (npts,2) + b2 = b.copy() + # if map boundary polygon is a valid one in lat/lon + # coordinates (i.e. it does not contain either pole), + # the intersections of the boundary geometries + # and the map projection region can be computed before + # transforming the boundary geometry to map projection + # coordinates (this saves time, especially for small map + # regions and high-resolution boundary geometries). + if not containsPole: + # close Antarctica. + if name == 'gshhs' and south < -68 and area > 10000: + lons = b[:,0] + lats = b[:,1] + lons2 = lons[:-2][::-1] + lats2 = lats[:-2][::-1] + lons1 = lons2 - 360. + lons3 = lons2 + 360. + lons = lons1.tolist()+lons2.tolist()+lons3.tolist() + lats = lats2.tolist()+lats2.tolist()+lats2.tolist() + lonstart,latstart = lons[0], lats[0] + lonend,latend = lons[-1], lats[-1] + lons.insert(0,lonstart) + lats.insert(0,-90.) + lons.append(lonend) + lats.append(-90.) + b = npy.empty((len(lons),2),npy.float64) + b[:,0] = lons; b[:,1] = lats + poly = _geos.Polygon(b) + antart = True + else: + poly = Shape(b) + antart = False + # create duplicate polygons shifted by -360 and +360 + # (so as to properly treat polygons that cross + # Greenwich meridian). + if not antart: + b2[:,0] = b[:,0]-360 + poly1 = Shape(b2) + b2[:,0] = b[:,0]+360 + poly2 = Shape(b2) + polys = [poly1,poly,poly2] + else: # Antartica already extends from -360 to +720. + polys = [poly] + for poly in polys: + # if polygon instersects map projection + # region, process it. + if poly.intersects(boundarypolyll): + # if geometry intersection calculation fails, + # just move on. + try: + geoms = poly.intersection(boundarypolyll) + except: + continue + # iterate over geometries in intersection. + for psub in geoms: + # only coastlines are polygons, + # which have a 'boundary' attribute. + # otherwise, use 'coords' attribute + # to extract coordinates. + b = psub.boundary + blons = b[:,0]; blats = b[:,1] + # transformation from lat/lon to + # map projection coordinates. + bx, by = self(blons, blats) + polygons.append(zip(bx,by)) + polygon_types.append(type) + # if map boundary polygon is not valid in lat/lon + # coordinates, compute intersection between map + # projection region and boundary geometries in map + # projection coordinates. + else: + # transform coordinates from lat/lon + # to map projection coordinates. + # special case for ortho, compute coastline polygon + # vertices in stereographic coords. + if name == 'gshhs' and self.projection == 'ortho': + b[:,0], b[:,1] = maptran(b[:,0], b[:,1]) + else: + b[:,0], b[:,1] = self(b[:,0], b[:,1]) + goodmask = npy.logical_and(b[:,0]<1.e20,b[:,1]<1.e20) + # if less than two points are valid in + # map proj coords, skip this geometry. + if npy.sum(goodmask) <= 1: continue + if name != 'gshhs': + # if not a polygon, + # just remove parts of geometry that are undefined + # in this map projection. + bx = npy.compress(goodmask, b[:,0]) + by = npy.compress(goodmask, b[:,1]) + # for orthographic projection, all points + # outside map projection region are eliminated + # with the above step, so we're done. + if self.projection == 'ortho': + polygons.append(zip(bx,by)) + polygon_types.append(type) + continue + # create a GEOS geometry object. + poly = Shape(b) + # if geometry instersects map projection + # region, and doesn't have any invalid points, process it. + if goodmask.all() and poly.intersects(boundarypolyxy): + # if geometry intersection calculation fails, + # just move on. + try: + geoms = poly.intersection(boundarypolyxy) + except: + continue + # iterate over geometries in intersection. + for psub in geoms: + b = psub.boundary + # if projection == 'ortho', + # transform polygon from stereographic + # to orthographic coordinates. + if self.projection == 'ortho': + # if coastline polygon covers more than 99% + # of map region for fulldisk projection, + # it's probably bogus, so skip it. + areafrac = psub.area()/boundarypolyxy.area() + if name == 'gshhs' and\ + self._fulldisk and\ + areafrac > 0.99: continue + # inverse transform from stereographic + # to lat/lon. + b[:,0], b[:,1] = maptran(b[:,0], b[:,1], inverse=True) + # orthographic. + b[:,0], b[:,1]= self(b[:,0], b[:,1]) + polygons.append(zip(b[:,0],b[:,1])) + polygon_types.append(type) + return polygons, polygon_types + + def _getmapboundary(self): + """ + create map boundary polygon (in lat/lon and x/y coordinates) + """ + nx = 100 + ny = 100 + maptran = self + if self.projection in ['ortho','geos']: + # circular region. + thetas = linspace(0.,2.*npy.pi,2*nx*ny)[:-1] + if self.projection == 'ortho': + rminor = self.rmajor + rmajor = self.rmajor + else: + rminor = self._height + rmajor = self._width + x = rmajor*npy.cos(thetas) + rmajor + y = rminor*npy.sin(thetas) + rminor + b = npy.empty((len(x),2),npy.float64) + b[:,0]=x; b[:,1]=y + boundaryxy = _geos.Polygon(b) + # compute proj instance for full disk, if necessary. + if not self._fulldisk: + projparms = self.projparams + del projparms['x_0'] + del projparms['y_0'] + if self.projection == 'ortho': + llcrnrx = -self.rmajor + llcrnry = -self.rmajor + urcrnrx = -llcrnrx + urcrnry = -llcrnry + else: + llcrnrx = -self._width + llcrnry = -self._height + urcrnrx = -llcrnrx + urcrnry = -llcrnry + projparms['x_0']=-llcrnrx + projparms['y_0']=-llcrnry + maptran = pyproj.Proj(projparms) + elif self.projection in ['moll','robin','sinu']: + # quasi-elliptical region. + lon_0 = self.projparams['lon_0'] + # left side + lats1 = linspace(-89.9,89.9,ny).tolist() + lons1 = len(lats1)*[lon_0-179.9] + # top. + lons2 = linspace(lon_0-179.9,lon_0+179.9,nx).tolist() + lats2 = len(lons2)*[89.9] + # right side + lats3 = linspace(89.9,-89.9,ny).tolist() + lons3 = len(lats3)*[lon_0+179.9] + # bottom. + lons4 = linspace(lon_0+179.9,lon_0-179.9,nx).tolist() + lats4 = len(lons4)*[-89.9] + lons = npy.array(lons1+lons2+lons3+lons4,npy.float64) + lats = npy.array(lats1+lats2+lats3+lats4,npy.float64) + x, y = maptran(lons,lats) + b = npy.empty((len(x),2),npy.float64) + b[:,0]=x; b[:,1]=y + boundaryxy = _geos.Polygon(b) + else: # all other projections are rectangular. + # left side (x = xmin, ymin <= y <= ymax) + yy = linspace(self.ymin, self.ymax, ny)[:-1] + x = len(yy)*[self.xmin]; y = yy.tolist() + # top (y = ymax, xmin <= x <= xmax) + xx = npy.linspace(self.xmin, self.xmax, nx)[:-1] + x = x + xx.tolist() + y = y + len(xx)*[self.ymax] + # right side (x = xmax, ymin <= y <= ymax) + yy = linspace(self.ymax, self.ymin, ny)[:-1] + x = x + len(yy)*[self.xmax]; y = y + yy.tolist() + # bottom (y = ymin, xmin <= x <= xmax) + xx = linspace(self.xmax, self.xmin, nx)[:-1] + x = x + xx.tolist() + y = y + len(xx)*[self.ymin] + x = npy.array(x,npy.float64) + y = npy.array(y,npy.float64) + b = npy.empty((4,2),npy.float64) + b[:,0]=[self.xmin,self.xmin,self.xmax,self.xmax] + b[:,1]=[self.ymin,self.ymax,self.ymax,self.ymin] + boundaryxy = _geos.Polygon(b) + if self.projection in ['mill','merc','cyl']: + # make sure map boundary doesn't quite include pole. + if self.urcrnrlat > 89.9999: + urcrnrlat = 89.9999 + else: + urcrnrlat = self.urcrnrlat + if self.llcrnrlat < -89.9999: + llcrnrlat = -89.9999 + else: + llcrnrlat = self.llcrnrlat + lons = [self.llcrnrlon, self.llcrnrlon, self.urcrnrlon, self.urcrnrlon] + lats = [llcrnrlat, urcrnrlat, urcrnrlat, llcrnrlat] + x, y = self(lons, lats) + b = npy.empty((len(x),2),npy.float64) + b[:,0]=x; b[:,1]=y + boundaryxy = _geos.Polygon(b) + else: + if self.projection not in ['moll','robin','sinu']: + lons, lats = maptran(x,y,inverse=True) + # fix lons so there are no jumps. + n = 1 + lonprev = lons[0] + for lon,lat in zip(lons[1:],lats[1:]): + if npy.abs(lon-lonprev) > 90.: + if lonprev < 0: + lon = lon - 360. + else: + lon = lon + 360 + lons[n] = lon + lonprev = lon + n = n + 1 + b = npy.empty((len(lons),2),npy.float64) + b[:,0]=lons; b[:,1]=lats + boundaryll = _geos.Polygon(b) + return boundaryll, boundaryxy + + + def drawmapboundary(self,color='k',linewidth=1.0,fill_color=None,\ + zorder=None,ax=None): + """ + draw boundary around map projection region, optionally + filling interior of region. + + linewidth - line width for boundary (default 1.) + color - color of boundary line (default black) + fill_color - fill the map region background with this + color (default is no fill or fill with axis background color). + zorder - sets the zorder for filling map background + (default 0). + ax - axes instance to use (default None, use default axes + instance). + """ + # get current axes instance (if none specified). + if ax is None and... [truncated message content] |