| 
 
	积分17103贡献 精华在线时间 小时注册时间2012-8-25最后登录1970-1-1 
 | 
 
| 
本帖最后由 非对称 于 2018-2-13 18:14 编辑
x
登录后查看更多精彩内容~您需要 登录 才可以下载或查看,没有帐号?立即注册 
  
 复制代码# -*- coding: utf-8 -*-
"""
特此申明,以下源代码改写自basemap的readshapefile
适合在无投影下的经纬度坐标中绘制。
需要在投影坐标系绘制,请自行用basemap的readshapefile绘制
-------------------------------------------------
   File Name:     readshp
   Description :
   Author :        Xy Liu
   date:          2018/2/13
-------------------------------------------------
   Change Activity:
                   2018/2/13
-------------------------------------------------
"""
import os
from matplotlib import dedent
from matplotlib.collections import LineCollection
__author__ = 'Xy Liu'
def readshapefile(shapefile, name, drawbounds=True, zorder=None,
                  linewidth=0.5, color='k', antialiased=1, ax=None,
                  default_encoding='utf-8'):
    """
    Read in shape file, optionally draw boundaries on map.
    .. note::
      - Assumes shapes are 2D
      - only works for Point, MultiPoint, Polyline and Polygon shapes.
      - vertices/points must be in geographic (lat/lon) coordinates.
    Mandatory Arguments:
    .. tabularcolumns:: |l|L|
    ==============   ====================================================
    Argument         Description
    ==============   ====================================================
    shapefile        path to shapefile components.  Example:
                     shapefile='/home/jeff/esri/world_borders' assumes
                     that world_borders.shp, world_borders.shx and
                     world_borders.dbf live in /home/jeff/esri.
    name             name for Basemap attribute to hold the shapefile
                     vertices or points in map projection
                     coordinates. Class attribute name+'_info' is a list
                     of dictionaries, one for each shape, containing
                     attributes of each shape from dbf file, For
                     example, if name='counties', self.counties
                     will be a list of x,y vertices for each shape in
                     map projection  coordinates and self.counties_info
                     will be a list of dictionaries with shape
                     attributes.  Rings in individual Polygon
                     shapes are split out into separate polygons, and
                     additional keys 'RINGNUM' and 'SHAPENUM' are added
                     to the shape attribute dictionary.
    ==============   ====================================================
    The following optional keyword arguments are only relevant for Polyline
    and Polygon shape types, for Point and MultiPoint shapes they are
    ignored.
    .. tabularcolumns:: |l|L|
    ==============   ====================================================
    Keyword          Description
    ==============   ====================================================
    drawbounds       draw boundaries of shapes (default True).
    zorder           shape boundary zorder (if not specified,
                     default for mathplotlib.lines.LineCollection
                     is used).
    linewidth        shape boundary line width (default 0.5)
    color            shape boundary line color (default black)
    antialiased      antialiasing switch for shape boundaries
                     (default True).
    ax               axes instance (overrides default axes instance)
    ==============   ====================================================
    A tuple (num_shapes, type, min, max) containing shape file info
    is returned.
    num_shapes is the number of shapes, type is the type code (one of
    the SHPT* constants defined in the shapelib module, see
    http://shapelib.maptools.org/shp_api.html) and min and
    max are 4-element lists with the minimum and maximum values of the
    vertices. If ``drawbounds=True`` a
    matplotlib.patches.LineCollection object is appended to the tuple.
    """
    import shapefile as shp
    from shapefile import Reader
    shp.default_encoding = default_encoding
    if not os.path.exists('%s.shp' % shapefile):
        raise IOError('cannot locate %s.shp' % shapefile)
    if not os.path.exists('%s.shx' % shapefile):
        raise IOError('cannot locate %s.shx' % shapefile)
    if not os.path.exists('%s.dbf' % shapefile):
        raise IOError('cannot locate %s.dbf' % shapefile)
    # open shapefile, read vertices for each object, convert
    # to map projection coordinates (only works for 2D shape types).
    try:
        shf = Reader(shapefile)
    except:
        raise IOError('error reading shapefile %s.shp' % shapefile)
    fields = shf.fields
    coords = []
    attributes = []
    msg = dedent("""
        shapefile must have lat/lon vertices  - it looks like this one has vertices
        in map projection coordinates. You can convert the shapefile to geographic
        coordinates using the shpproj utility from the shapelib tools
        (http://shapelib.maptools.org/shapelib-tools.html)""")
    shptype = shf.shapes()[0].shapeType
    bbox = shf.bbox.tolist()
    info = dict()
    info['info'] = (shf.numRecords, shptype, bbox[0:2] + [0., 0.], bbox[2:] + [0., 0.])
    npoly = 0
    for shprec in shf.shapeRecords():
        shp = shprec.shape
        rec = shprec.record
        npoly = npoly + 1
        if shptype != shp.shapeType:
            raise ValueError('readshapefile can only handle a single shape type per file')
        if shptype not in [1, 3, 5, 8]:
            raise ValueError('readshapefile can only handle 2D shape types')
        verts = shp.points
        if shptype in [1, 8]:  # a Point or MultiPoint shape.
            lons, lats = list(zip(*verts))
            if max(lons) > 721. or min(lons) < -721. or max(lats) > 90.01 or min(lats) < -90.01:
                raise ValueError(msg)
            # if latitude is slightly greater than 90, truncate to 90
            lats = [max(min(lat, 90.0), -90.0) for lat in lats]
            if len(verts) > 1:  # MultiPoint
                x, y = lons, lats
                coords.append(list(zip(x, y)))
            else:  # single Point
                x, y = lons[0], lats[0]
                coords.append((x, y))
            attdict = {}
            for r, key in zip(rec, fields[1:]):
                attdict[key[0]] = r
            attributes.append(attdict)
        else:  # a Polyline or Polygon shape.
            parts = shp.parts.tolist()
            ringnum = 0
            for indx1, indx2 in zip(parts, parts[1:] + [len(verts)]):
                ringnum = ringnum + 1
                lons, lats = list(zip(*verts[indx1:indx2]))
                if max(lons) > 721. or min(lons) < -721. or max(lats) > 90.01 or min(lats) < -90.01:
                    raise ValueError(msg)
                # if latitude is slightly greater than 90, truncate to 90
                lats = [max(min(lat, 90.0), -90.0) for lat in lats]
                x, y = lons, lats
                coords.append(list(zip(x, y)))
                attdict = {}
                for r, key in zip(rec, fields[1:]):
                    attdict[key[0]] = r
                # add information about ring number to dictionary.
                attdict['RINGNUM'] = ringnum
                attdict['SHAPENUM'] = npoly
                attributes.append(attdict)
    # draw shape boundaries for polylines, polygons  using LineCollection.
    if shptype not in [1, 8] and drawbounds:
        # get current axes instance (if none specified).
        import matplotlib.pyplot as plt
        ax = ax or plt.gca()
        # make LineCollections for each polygon.
        lines = LineCollection(coords, antialiaseds=(antialiased,))
        lines.set_color(color)
        lines.set_linewidth(linewidth)
        lines.set_label('_nolabel_')
        if zorder is not None:
            lines.set_zorder(zorder)
        ax.add_collection(lines)
    # set axes limits to fit map region.
    # self.set_axes_limits(ax=ax)
    # # clip boundaries to map limbs
    # lines,c = self._cliplimb(ax,lines)
    # info = info + (lines,)
    info[name] = coords
    info[name + '_info'] = attributes
    return info
if __name__ == '__main__':
    file = 'test.shp'
    readshapefile(file.replace('.shp', ''), os.path.basename(file), color='k', linewidth=1)
   | 
 评分
查看全部评分
 |