[pyshp] 01/09: Imported Upstream version 1.2.8+ds
Bas Couwenberg
sebastic at debian.org
Fri Aug 19 09:03:17 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository pyshp.
commit a74b8d174e90143889514314b199fbf75a0e9c1d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Fri Aug 19 09:44:48 2016 +0200
Imported Upstream version 1.2.8+ds
---
PKG-INFO | 1275 ++++++++++++++++++++++++++++------------------------------
README.txt | 661 ------------------------------
setup.py | 6 +-
shapefile.py | 58 +--
4 files changed, 649 insertions(+), 1351 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index ed0b3f7..ff18637 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,673 +1,622 @@
Metadata-Version: 1.1
Name: pyshp
-Version: 1.2.3
+Version: 1.2.8
Summary: Pure Python read/write support for ESRI Shapefile format
Home-page: https://github.com/GeospatialPython/pyshp
Author: Joel Lawhead
Author-email: jlawhead at geospatialpython.com
License: MIT
-Download-URL: https://github.com/GeospatialPython/pyshp/archive/1.2.3.tar.gz
-Description: PyShp
- ========================
-
- :Author: Joel Lawhead - jlawhead at geospatialpython.com
-
- :Version 1.2.2
-
- :Revised: January 9, 2015
-
- .. contents::
-
- Overview
- --------
-
- PyShp provides read and write support for the Esri
- Shapefile format. The Shapefile format is a popular Geographic Information
- System vector data format created by Esri. For more information about this format
- please read the well-written "ESRI Shapefile Technical Description - July 1998"
- located at http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf.
- The Esri document describes the shp and shx file formats. However a third file
- format called dbf is also required. This format is documented on the web as the
- "XBase File Format Description" and is a simple file-based database format created
- in the 1960's. For more on this specification see:
- http://www.clicketyclick.dk/databases/xbase/format/index.html
-
- Both the Esri and XBase file-formats are very simple in design and
- memory efficient which is part of the reason the shapefile format remains popular
- despite the numerous ways to store and exchange GIS data available today.
-
- Pyshp is compatible with Python 2.4-3.x.
-
- This document provides examples for using PyShp to read and write shapefiles.
-
- Currently the sample census blockgroup shapefile referenced in the examples is
- only available on the google code project site at http://code.google.com/p/pyshp.
- These examples are straight-forward and you can also easily run them against your
- own shapefiles manually with minimal modification. Other examples for specific
- topics are continually added to the pyshp wiki on google code and the blog
- http://GeospatialPython.com.
-
- Important: For information about map projections, shapefiles,
- and Python please visit: http://code.google.com/p/pyshp/wiki/MapProjections
-
- I sincerely hope this library eliminates the mundane distraction of simply
- reading and writing data, and allows you to focus on the challenging and FUN
- part of your geospatial project.
-
- Examples
- --------
-
- Before doing anything you must import the library.
-
- >>> import shapefile
-
- The examples below will use a shapefile created from the U.S. Census Bureau
- Blockgroups data set near San Francisco, CA and available in the subversion
- repository of the pyshp google code site.
-
- Reading Shapefiles
- ++++++++++++++++++
-
- To read a shapefile create a new "Reader" object and pass it the name of an
- existing shapefile. The shapefile format is acutally a collection of three
- files. You specify the base filename of the shapefile or the complete filename
- of any of the shapefile component files.
-
- >>> sf = shapefile.Reader("shapefiles/blockgroups")
-
-
- OR
-
- >>> sf = shapefile.Reader("shapefiles/blockgroups.shp")
-
-
- OR
-
- >>> sf = shapefile.Reader("shapefiles/blockgroups.dbf")
-
-
- OR any of the other 5+ formats which are potentially part of a shapefile.
- The library does not care about extensions.
-
- Reading Shapefiles from File-Like Objects
- .........................................
-
- You can also load shapefiles from any Python file-like object using keyword
- arguments to specify any of the three files. This feature is very powerful
- and allows you to load shapefiles from a url, from a zip file, serialized
- object, or in some cases a database.
-
- >>> myshp = open("shapefiles/blockgroups.shp", "rb")
- >>> mydbf = open("shapefiles/blockgroups.dbf", "rb")
- >>> r = shapefile.Reader(shp=myshp, dbf=mydbf)
-
- Notice in the examples above the shx file is never used. The shx file is a
- very simple fixed-record index for the variable length records in the shp file.
- This file is optional for reading. If it's available pyshp will use the shx file
- to access shape records a little faster but will do just fine without it.
-
- Reading Geometry
- ................
-
- A shapefile's geometry is the collection of points or shapes made from verticies
- and implied arcs representing physical locations. All types of shapefiles
- just store points. The metadata about the points determine how they are handled by
- software.
-
- You can get the a list of the shapefile's geometry by calling the shapes()
- method.
-
- >>> shapes = sf.shapes()
-
- The shapes method returns a list of Shape objects describing the
- geometry of each shape record.
-
- >>> len(shapes)
- 663
-
- You can iterate through the shapefile's geometry using the iterShapes() method.
-
- >>> len(list(sf.iterShapes()))
- 663
-
- Each shape record contains the following attributes:
-
- >>> for name in dir(shapes[3]):
- ... if not name.startswith('__'):
- ... name
- 'bbox'
- 'parts'
- 'points'
- 'shapeType'
-
- - shapeType: an integer representing the type of shape as defined by the
- shapefile specification.
-
- >>> shapes[3].shapeType
- 5
-
- - bbox: If the shape type contains multiple points this tuple describes the
- lower left (x,y) coordinate and upper right corner coordinate creating a
- complete box around the points. If the shapeType is a Null
- (shapeType == 0) then an AttributeError is raised.
-
- >>> # Get the bounding box of the 4th shape.
- >>> # Round coordinates to 3 decimal places
- >>> bbox = shapes[3].bbox
- >>> ['%.3f' % coord for coord in bbox]
- ['-122.486', '37.787', '-122.446', '37.811']
-
- - parts: Parts simply group collections of points into shapes. If the shape record
- has multiple parts this attribute contains the index of the first point of each part.
- If there is only one part then a list containing 0 is returned.
-
- >>> shapes[3].parts
- [0]
-
- - points: The points attribute contains a list of tuples containing an (x,y)
- coordinate for each point in the shape.
-
- >>> len(shapes[3].points)
- 173
- >>> # Get the 8th point of the fourth shape
- >>> # Truncate coordinates to 3 decimal places
- >>> shape = shapes[3].points[7]
- >>> ['%.3f' % coord for coord in shape]
- ['-122.471', '37.787']
-
- To read a single shape by calling its index use the shape() method. The index
- is the shape's count from 0. So to read the 8th shape record you would
- use its index which is 7.
-
- >>> s = sf.shape(7)
-
- >>> # Read the bbox of the 8th shape to verify
- >>> # Round coordinates to 3 decimal places
- >>> ['%.3f' % coord for coord in s.bbox]
- ['-122.450', '37.801', '-122.442', '37.808']
-
- Reading Records
- ................
-
- A record in a shapefile contains the attributes for each shape in the
- collection of geometry. Records are stored in the dbf file. The link
- between geometry and attributes is the foundation of Geographic Information
- Systems. This critical link is implied by the order of shapes and
- corresponding records in the shp geometry file and the dbf attribute file.
-
- The field names of a shapefile are available as soon as you read a shapefile.
- You can call the "fields" attribute of the shapefile as a Python list. Each
- field is a Python list with the following information:
-
- - Field name: the name describing the data at this column index.
-
- - Field type: the type of data at this column index. Types can be: Character, Numbers, Longs, Dates, or Memo.
- The "Memo" type has no meaning within a GIS and is part of the xbase spec instead.
-
- - Field length: the length of the data found at this column index. Older GIS software may truncate this
- length to 8 or 11 characters for "Character" fields.
-
- - Decimal length: the number of decimal places found in "Number" fields.
-
- To see the fields for the Reader object above (sf) call the "fields" attribute:
-
- >>> fields = sf.fields
-
- >>> assert fields == [("DeletionFlag", "C", 1, 0), ["AREA", "N", 18, 5],
- ... ["BKG_KEY", "C", 12, 0], ["POP1990", "N", 9, 0], ["POP90_SQMI", "N", 10, 1],
- ... ["HOUSEHOLDS", "N", 9, 0],
- ... ["MALES", "N", 9, 0], ["FEMALES", "N", 9, 0], ["WHITE", "N", 9, 0],
- ... ["BLACK", "N", 8, 0], ["AMERI_ES", "N", 7, 0], ["ASIAN_PI", "N", 8, 0],
- ... ["OTHER", "N", 8, 0], ["HISPANIC", "N", 8, 0], ["AGE_UNDER5", "N", 8, 0],
- ... ["AGE_5_17", "N", 8, 0], ["AGE_18_29", "N", 8, 0], ["AGE_30_49", "N", 8, 0],
- ... ["AGE_50_64", "N", 8, 0], ["AGE_65_UP", "N", 8, 0],
- ... ["NEVERMARRY", "N", 8, 0], ["MARRIED", "N", 9, 0], ["SEPARATED", "N", 7, 0],
- ... ["WIDOWED", "N", 8, 0], ["DIVORCED", "N", 8, 0], ["HSEHLD_1_M", "N", 8, 0],
- ... ["HSEHLD_1_F", "N", 8, 0], ["MARHH_CHD", "N", 8, 0],
- ... ["MARHH_NO_C", "N", 8, 0], ["MHH_CHILD", "N", 7, 0],
- ... ["FHH_CHILD", "N", 7, 0], ["HSE_UNITS", "N", 9, 0], ["VACANT", "N", 7, 0],
- ... ["OWNER_OCC", "N", 8, 0], ["RENTER_OCC", "N", 8, 0],
- ... ["MEDIAN_VAL", "N", 7, 0], ["MEDIANRENT", "N", 4, 0],
- ... ["UNITS_1DET", "N", 8, 0], ["UNITS_1ATT", "N", 7, 0], ["UNITS2", "N", 7, 0],
- ... ["UNITS3_9", "N", 8, 0], ["UNITS10_49", "N", 8, 0],
- ... ["UNITS50_UP", "N", 8, 0], ["MOBILEHOME", "N", 7, 0]]
-
- You can get a list of the shapefile's records by calling the records() method:
-
- >>> records = sf.records()
-
- >>> len(records)
- 663
-
- Similar to the geometry methods, you can iterate through dbf records using the
- recordsIter() method.
-
- >>> len(list(sf.iterRecords()))
- 663
-
- Each record is a list containing an attribute corresponding to each field in the
- field list.
-
- For example in the 4th record of the blockgroups shapefile the 2nd and 3rd
- fields are the blockgroup id and the 1990 population count of
- that San Francisco blockgroup:
-
- >>> records[3][1:3]
- ['060750601001', 4715]
-
- To read a single record call the record() method with the record's index:
-
- >>> rec = sf.record(3)
-
- >>> rec[1:3]
- ['060750601001', 4715]
-
- Reading Geometry and Records Simultaneously
- ...........................................
-
- You way want to examine both the geometry and the attributes for a record at the
- same time. The shapeRecord() and shapeRecords() method let you do just that.
-
- Calling the shapeRecords() method will return the geometry and attributes for
- all shapes as a list of ShapeRecord objects. Each ShapeRecord instance has a
- "shape" and "record" attribute. The shape attribute is a ShapeRecord object as
- dicussed in the first section "Reading Geometry". The record attribute is a
- list of field values as demonstrated in the "Reading Records" section.
-
- >>> shapeRecs = sf.shapeRecords()
-
- Let's read the blockgroup key and the population for the 4th blockgroup:
- >>> shapeRecs[3].record[1:3]
- ['060750601001', 4715]
-
- Now let's read the first two points for that same record:
-
- >>> points = shapeRecs[3].shape.points[0:2]
-
- >>> len(points)
- 2
-
- The shapeRec() method reads a single shape/record pair at the specified index.
- To get the 4th shape record from the blockgroups shapfile use the third index:
-
- >>> shapeRec = sf.shapeRecord(3)
-
- The blockgroup key and population count:
-
- >>> shapeRec.record[1:3]
- ['060750601001', 4715]
-
- >>> points = shapeRec.shape.points[0:2]
-
- >>> len(points)
- 2
-
- There is also an iterShapeRecords() method to iterate through large files:
-
- >>> shapeRecs = sf.iterShapeRecords()
- >>> for shape, rec in shapeRecs:
- ... # do something here
-
- Writing Shapefiles
- ++++++++++++++++++
-
- PyShp tries to be as flexible as possible when writing shapefiles while
- maintaining some degree of automatic validation to make sure you don't
- accidentally write an invalid file.
-
- PyShp can write just one of the component files such as the shp or dbf file
- without writing the others. So in addition to being a complete
- shapefile library, it can also be used as a basic dbf (xbase) library. Dbf files are
- a common database format which are often useful as a standalone simple
- database format. And even shp files occasionaly have uses as a standalone
- format. Some web-based GIS systems use an user-uploaded shp file to specify
- an area of interest. Many precision agriculture chemical field sprayers also
- use the shp format as a control file for the sprayer system (usually in
- combination with custom database file formats).
-
- To create a shapefile you add geometry and/or attributes using methods in the
- Writer class until you are ready to save the file.
-
- Create an instance of the Writer class to begin creating a shapefile:
-
- >>> w = shapefile.Writer()
-
-
- Setting the Shape Type
- ......................
-
- The shape type defines the type of geometry contained in the shapefile. All of
- the shapes must match the shape type setting.
-
- Shape types are represented by numbers between 0 and 31 as defined by the
- shapefile specification. It is important to note that numbering system has
- several reserved numbers which have not been used yet therefore the numbers of
- the existing shape types are not sequential.
-
- You can reference shape types by the numbers or by constants defined by PyShp:
- shapefile.NULL = 0
- shapefile.POINT = 1
- shapefile.POLYLINE = 3
- shapefile.POLYGON = 5
- shapefile.MULTIPOINT = 8
- shapefile.POINTZ = 11
- shapefile.POLYLINEZ = 13
- shapefile.POLYGONZ = 15
- shapefile.MULTIPOINTZ = 18
- shapefile.POINTM = 21
- shapefile.POLYLINEM = 23
- shapefile.POLYGONM = 25
- shapefile.MULTIPOINTM = 28
- shapefile.MULTIPATCH = 31
-
- There are three ways to set the shape type:
- - Set it when creating the class instance.
- - Set it by assigning a value to an existing class instance.
- - Set it automatically to the type of the first shape by saving the shapefile.
-
- To manually set the shape type for a Writer object when creating the Writer:
-
- >>> w = shapefile.Writer(shapeType=1)
-
- or we can use the constants as explained above:
-
- >>> w = shapefile.Writer(shapefile.POINT)
-
- As you can see, specifying the shapeType argument explicitly isn't necessary.
-
- >>> w.shapeType
- 1
-
- OR you can set it after the Writer is created by changing the property:
-
- >>> w.shapeType = 3
-
- >>> w.shapeType
- 3
-
- Geometry and Record Balancing
- .............................
-
- Because every shape must have a corresponding record it is critical that the
- number of records equals the number of shapes to create a valid shapefile. To
- help prevent accidental misalignment PyShp has an "auto balance" feature to
- make sure when you add either a shape or a record the two sides of the
- equation line up. This feature is NOT turned on by default. To activate it
- set the attribute autoBalance to 1 (True):
-
- >>> w.autoBalance = 1
-
- You also have the option of manually calling the balance() method each time you
- add a shape or a record to ensure the other side is up to date. When balancing
- is used null shapes are created on the geometry side or a record with a value of
- "NULL" for each field is created on the attribute side.
-
- The balancing option gives you flexibility in how you build the shapefile.
-
- Without auto balancing you can add geometry or records at anytime. You can
- create all of the shapes and then create all of the records or vice versa. You
- can use the balance method after creating a shape or record each time and make
- updates later. If you do not use the balance method and forget to manually
- balance the geometry and attributes the shapefile will be viewed as corrupt by
- most shapefile software.
-
- With auto balanacing you can add either shapes or geometry and update blank
- entries on either side as needed. Even if you forget to update an entry the
- shapefile will still be valid and handled correctly by most shapefile software.
-
- Adding Geometry
- ...............
-
- Geometry is added using one of three methods: "null", "point", or "poly". The "null"
- method is used for null shapes, "point" is used for point shapes, and "poly" is
- used for everything else.
-
- **Adding a Null shape**
-
- Because Null shape types (shape type 0) have no geometry the "null" method is
- called without any arguments.
-
- >>> w = shapefile.Writer()
-
- >>> w.null()
-
- The writer object's shapes list will now have one null shape:
-
- >>> assert w.shapes()[0].shapeType == shapefile.NULL
-
- **Adding a Point shape**
-
- Point shapes are added using the "point" method. A point is specified by an
- x, y, and optional z (elevation) and m (measure) value.
-
- >>> w = shapefile.Writer(shapefile.POINT)
-
- >>> w.point(122, 37) # No elevation or measure values
-
- >>> w.shapes()[0].points
- [[122, 37, 0, 0]]
-
- >>> w.point(118, 36, 4, 8)
-
- >>> w.shapes()[1].points
- [[118, 36, 4, 8]]
-
- **Adding a Poly Shape**
-
- "Poly" shapes can be either polygons or lines. Shapefile polygons must have at
- least 4 points and the last point must be the same as the first. PyShp automatically
- enforces closed polygons.
- A line must have at least two points.
- Because of the similarities between these two shape types they are created using
- a single method called "poly".
-
- >>> w = shapefile.Writer(shapefile.POLYGON)
-
- >>> w.poly(shapeType=3, parts=[[[122,37,4,9], [117,36,3,4]], [[115,32,8,8],
- ... [118,20,6,4], [113,24]]])
-
- **Adding a Polygon with Rings**
-
- Polygons consist of rings which mean they are closed. The first point and last point
- of a ring must be the same. PyShp enforces ring closure if the ring is incomplete when
- you add the shape. Polygons can have inner rings which create holes. Holes are defined
- by the order of the points. Normally points in a ring run clockwise. If the points
- run counter-clockwise then they form a hole. If you don't order the points correctly
- you'll just have overlapping polygons.
-
- >>> w = shapefile.Writer(shapefile.POLYGON)
- >>> outer_ring = [[10,10],[50,50],[100,10],[50,-50],[10,10]]
- >>> inner_ring = [[40,10],[50,30],[70,10],[50,-30],[40,10]]
- >>> inner_ring.reverse()
-
- You can use the "shapefile.signed_area()" method to determine if a ring is clockwise
- or counter-clockwise. A value >= 0 means the ring is counter-clockwise and < 0 means
- the ring is clockwise. The value returned is also the area of the polygon.
-
- >>> # Clockwise ring
- ... shapefile.signed_area(outer_ring)
- -4500.0
- >>> # Counter-clockwise ring
- ... shapefile.signed_area(inner_ring)
- 900.0
-
- **Creating 3D Polygons**
-
- Elevation values, known as "Z" values allow you to create 3-dimensional shapefiles. The
- z value is an extra value specified as part of a point.
-
- >>> w = shapefile.Writer(shapeType=shapefile.POLYGONZ)
- >>> w.poly([[[-89.0, 33, 12], [-90, 31, 11], [-91, 30, 12]]], shapeType=15)
- >>> w.field("NAME")
- >>> w.record("PolyZTest")
- >>> w.save("shapefiles/test/MyPolyZ")
-
- The z values are stored in a seperate shape attribute.
-
- >>> r = shapefile.Reader("shapefiles/test/MyPolyZ")
- >>> s = r.shape(0)
- >>> s.points
- [[-89.0, 33.0], [-90.0, 31.0], [-91.0, 30.0], [-89.0, 33.0]]
- >>> s.z
- [12.0, 11.0, 12.0, 12.0]
-
- Creating Attributes
- ...................
-
- Creating attributes involves two steps. Step 1 is to create fields to contain
- attribute values and step 2 is to populate the fields with values for each
- shape record.
-
- The following attempts to create a complete shapefile:
-
- >>> w = shapefile.Writer(shapefile.POINT)
- >>> w.point(1,1)
- >>> w.point(3,1)
- >>> w.point(4,3)
- >>> w.point(2,2)
- >>> w.field('FIRST_FLD')
- >>> w.field('SECOND_FLD','C','40')
- >>> w.record('First','Point')
- >>> w.record('Second','Point')
- >>> w.record('Third','Point')
- >>> w.record('Fourth','Point')
- >>> w.save('shapefiles/test/point')
-
- >>> w = shapefile.Writer(shapefile.POLYGON)
- >>> w.poly(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
- >>> w.field('FIRST_FLD','C','40')
- >>> w.field('SECOND_FLD','C','40')
- >>> w.record('First','Polygon')
- >>> w.save('shapefiles/test/polygon')
-
- >>> w = shapefile.Writer(shapefile.POLYLINE)
- >>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
- >>> w.poly(parts=[[[1,3],[5,3]]], shapeType=shapefile.POLYLINE)
- >>> w.field('FIRST_FLD','C','40')
- >>> w.field('SECOND_FLD','C','40')
- >>> w.record('First','Line')
- >>> w.record('Second','Line')
- >>> w.save('shapefiles/test/line')
-
- You can also add attributes using keyword arguments where the keys are field names.
-
- >>> w = shapefile.Writer(shapefile.POLYLINE)
- >>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
- >>> w.field('FIRST_FLD','C','40')
- >>> w.field('SECOND_FLD','C','40')
- >>> w.record(FIRST_FLD='First', SECOND_FLD='Line')
- >>> w.save('shapefiles/test/line')
-
- File Names
- ..........
-
- File extensions are optional when reading or writing shapfiles. If you specify them Pyshp
- ignores them anyway. When you save files you can specify a base file name that is used for
- all three file types. Or you can specify a nmae for one or more file types. In that case,
- any file types not assigned will not save and only file types with file names will be saved.
- If you do not specify any file names (i.e. save()), then a unique file name is generated with
- the prefix "shapefile\_" followed by random characters which is used for all three files. The
- unique file name is returned as a string.
-
- >>> targetName = w.save()
- >>> assert("shapefile_" in targetName)
-
- Saving to File-Like Objects
- ...........................
-
- Just as you can read shapefiles from python file-like objects you can also write them.
-
- >>> try:
- ... from StringIO import StringIO
- ... except ImportError:
- ... from io import BytesIO as StringIO
- >>> shp = StringIO()
- >>> shx = StringIO()
- >>> dbf = StringIO()
- >>> w.saveShp(shp)
- >>> w.saveShx(shx)
- >>> w.saveDbf(dbf)
- >>> # Normally you would call the "StringIO.getvalue()" method on these objects.
- >>> shp = shx = dbf = None
-
- Editing Shapefiles
- ++++++++++++++++++
-
- The Editor class attempts to make changing existing shapefiles easier by handling the reading and writing details behind the scenes.
-
- Let's add shapes to existing shapefiles:
-
- Add a point to a point shapefile
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
- >>> e.point(0,0,10,2)
- >>> e.record("Appended","Point")
- >>> # We added z and m values so
- >>> # change the shapetype
- >>> e.shapeType = shapefile.POINTZ
- >>> e.save('shapefiles/test/point')
-
- Edit the appended point to change the "y" and "z" value
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
- >>> # Find the point by the attribute
- >>> for s in enumerate(e.records):
- ... i, record = s
- ... if record[0] == "Appended":
- ... geom = e._shapes[i]
- ... # Change the y value to 5
- ... geom.points[0][1] = 5
- ... # Change the z value to 9
- ... if hasattr(geom, "z"):
- ... geom.z = (9,)
- ... else:
- ... geom.points[0][2] = 9
- >>> e.save('shapefiles/test/point')
-
- Add a new line to a line shapefile:
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/line.shp")
- >>> e.line(parts=[[[10,5],[15,5],[15,1],[13,3],[11,1]]])
- >>> e.record('Appended','Line')
- >>> e.save('shapefiles/test/line')
- >>> e = None
-
- Add a new polygon to a polygon shapefile:
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
- >>> e.poly(parts=[[[5.1,5],[9.9,5],[9.9,1],[7.5,3],[5.1,1]]])
- >>> e.record("Appended","Polygon")
- >>> e.save('shapefiles/test/polygon')
- >>> e = None
-
- Remove the first point in each shapefile - for a point shapefile that is
- the first shape and record"
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
- >>> e.delete(0)
- >>> e.save('shapefiles/test/point')
- >>> e = None
-
- Remove the last shape in the polygon shapefile.
-
- >>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
- >>> e.delete(-1)
- >>> e.save('shapefiles/test/polygon')
- >>> e = None
-
- Python __geo_interface__
- ++++++++++++++++++++++++
-
- The Python __geo_interface__ convention provides a data interchange interface
- among geospatial Python libraries. The interface returns data as GeoJSON.
- More information on the __geo_interface__ protocol can be found at:
- https://gist.github.com/sgillies/2217756.
- More information on GeoJSON is available at http://geojson.org.
-
- >>> s = sf.shape(0)
- >>> s.__geo_interface__["type"]
- 'MultiPolygon'
-
+Download-URL: https://github.com/GeospatialPython/pyshp/archive/1.2.8.tar.gz
+Description: ## Contents
+
+ [TOC]
+
+ # Overview
+
+ The Python Shapefile Library (pyshp) provides read and write support for the
+ Esri Shapefile format. The Shapefile format is a popular Geographic
+ Information System vector data format created by Esri. For more information
+ about this format please read the well-written "ESRI Shapefile Technical
+ Description - July 1998" located at [http://www.esri.com/library/whitepapers/p
+ dfs/shapefile.pdf](http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf)
+ . The Esri document describes the shp and shx file formats. However a third
+ file format called dbf is also required. This format is documented on the web
+ as the "XBase File Format Description" and is a simple file-based database
+ format created in the 1960's. For more on this specification see: [http://www.clicketyclick.dk/databases/xbase/format/index.html](http://www.clicketyclick.d
+ k/databases/xbase/format/index.html)
+
+ Both the Esri and XBase file-formats are very simple in design and memory
+ efficient which is part of the reason the shapefile format remains popular
+ despite the numerous ways to store and exchange GIS data available today.
+
+ Pyshp is compatible with Python 2.4-3.x.
+
+ This document provides examples for using pyshp to read and write shapefiles.
+
+ Currently the sample census blockgroup shapefile referenced in the examples is available on the GitHub project site at
+ [https://github.com/GeospatialPython/pyshp](https://github.com/GeospatialPython/pyshp). These
+ examples are straight-forward and you can also easily run them against your
+ own shapefiles manually with minimal modification. Other examples for specific
+ topics are continually added to the pyshp wiki on GitHub and the blog
+ [http://GeospatialPython.com](http://GeospatialPython.com).
+
+ Important: For information about map projections, shapefiles, and Python
+ please visit: [https://github.com/GeospatialPython/pyshp/wiki/Map-Projections](https://github.com/GeospatialPython/pyshp/wiki/Map-Projections)
+
+ I sincerely hope this library eliminates the mundane distraction of simply
+ reading and writing data, and allows you to focus on the challenging and FUN
+ part of your geospatial project.
+
+ # Examples
+
+ Before doing anything you must import the library.
+
+
+ >>> import shapefile
+
+ The examples below will use a shapefile created from the U.S. Census Bureau
+ Blockgroups data set near San Francisco, CA and available in the git
+ repository of the pyshp GitHub site.
+
+ ## Reading Shapefiles
+
+ To read a shapefile create a new "Reader" object and pass it the name of an
+ existing shapefile. The shapefile format is acutally a collection of three
+ files. You specify the base filename of the shapefile or the complete filename
+ of any of the shapefile component files.
+
+
+ >>> sf = shapefile.Reader("shapefiles/blockgroups")
+
+ OR
+
+
+ >>> sf = shapefile.Reader("shapefiles/blockgroups.shp")
+
+ OR
+
+
+ >>> sf = shapefile.Reader("shapefiles/blockgroups.dbf")
+
+ OR any of the other 5+ formats which are potentially part of a shapefile. The
+ library does not care about file extensions.
+
+ ### Reading Shapefiles from File-Like Objects
+
+ You can also load shapefiles from any Python file-like object using keyword
+ arguments to specify any of the three files. This feature is very powerful and
+ allows you to load shapefiles from a url, from a zip file, serialized object,
+ or in some cases a database.
+
+
+ >>> myshp = open("shapefiles/blockgroups.shp", "rb")
+ >>> mydbf = open("shapefiles/blockgroups.dbf", "rb")
+ >>> r = shapefile.Reader(shp=myshp, dbf=mydbf)
+
+ Notice in the examples above the shx file is never used. The shx file is a
+ very simple fixed-record index for the variable length records in the shp
+ file. This file is optional for reading. If it's available pyshp will use the
+ shx file to access shape records a little faster but will do just fine without
+ it.
+
+ ### Reading Geometry
+
+ A shapefile's geometry is the collection of points or shapes made from
+ verticies and implied arcs representing physical locations. All types of
+ shapefiles just store points. The metadata about the points determine how they
+ are handled by software.
+
+ You can get the a list of the shapefile's geometry by calling the shapes()
+ method.
+
+
+ >>> shapes = sf.shapes()
+
+ The shapes method returns a list of Shape objects describing the geometry of
+ each shape record.
+
+
+ >>> len(shapes)
+ 663
+
+ You can iterate through the shapefile's geometry using the iterShapes()
+ method.
+
+
+ >>> len(list(sf.iterShapes()))
+ 663
+
+ Each shape record contains the following attributes:
+
+
+ >>> for name in dir(shapes[3]):
+ ... if not name.startswith('__'):
+ ... name
+ 'bbox'
+ 'parts'
+ 'points'
+ 'shapeType'
+
+ * shapeType: an integer representing the type of shape as defined by the
+ shapefile specification.
+
+
+ >>> shapes[3].shapeType
+ 5
+
+ * bbox: If the shape type contains multiple points this tuple describes the
+ lower left (x,y) coordinate and upper right corner coordinate creating a
+ complete box around the points. If the shapeType is a
+ Null (shapeType == 0) then an AttributeError is raised.
+
+
+ >>> # Get the bounding box of the 4th shape.
+ >>> # Round coordinates to 3 decimal places
+ >>> bbox = shapes[3].bbox
+ >>> ['%.3f' % coord for coord in bbox]
+ ['-122.486', '37.787', '-122.446', '37.811']
+
+ * parts: Parts simply group collections of points into shapes. If the shape
+ record has multiple parts this attribute contains the index of the first
+ point of each part. If there is only one part then a list containing 0 is
+ returned.
+
+ >>> shapes[3].parts
+ [0]
+
+ * points: The points attribute contains a list of tuples containing an
+ (x,y) coordinate for each point in the shape.
+
+ >>> len(shapes[3].points)
+ 173
+ >>> # Get the 8th point of the fourth shape
+ >>> # Truncate coordinates to 3 decimal places
+ >>> shape = shapes[3].points[7]
+ >>> ['%.3f' % coord for coord in shape]
+ ['-122.471', '37.787']
+
+ To read a single shape by calling its index use the shape() method. The index
+ is the shape's count from 0. So to read the 8th shape record you would use its
+ index which is 7.
+
+
+ >>> s = sf.shape(7)
+
+ >>> # Read the bbox of the 8th shape to verify
+ >>> # Round coordinates to 3 decimal places
+ >>> ['%.3f' % coord for coord in s.bbox]
+ ['-122.450', '37.801', '-122.442', '37.808']
+
+ ### Reading Records
+
+ A record in a shapefile contains the attributes for each shape in the
+ collection of geometry. Records are stored in the dbf file. The link between
+ geometry and attributes is the foundation of all geographic information systems.
+ This critical link is implied by the order of shapes and corresponding records
+ in the shp geometry file and the dbf attribute file.
+
+ The field names of a shapefile are available as soon as you read a shapefile.
+ You can call the "fields" attribute of the shapefile as a Python list. Each
+ field is a Python list with the following information:
+
+ * Field name: the name describing the data at this column index.
+ * Field type: the type of data at this column index. Types can be: Character,
+ Numbers, Longs, Dates, or Memo. The "Memo" type has no meaning within a
+ GIS and is part of the xbase spec instead.
+ * Field length: the length of the data found at this column index. Older GIS
+ software may truncate this length to 8 or 11 characters for "Character"
+ fields.
+ * Decimal length: the number of decimal places found in "Number" fields.
+
+ To see the fields for the Reader object above (sf) call the "fields"
+ attribute:
+
+
+ >>> fields = sf.fields
+
+ >>> assert fields == [("DeletionFlag", "C", 1, 0), ["AREA", "N", 18, 5],
+ ... ["BKG_KEY", "C", 12, 0], ["POP1990", "N", 9, 0], ["POP90_SQMI", "N", 10, 1],
+ ... ["HOUSEHOLDS", "N", 9, 0],
+ ... ["MALES", "N", 9, 0], ["FEMALES", "N", 9, 0], ["WHITE", "N", 9, 0],
+ ... ["BLACK", "N", 8, 0], ["AMERI_ES", "N", 7, 0], ["ASIAN_PI", "N", 8, 0],
+ ... ["OTHER", "N", 8, 0], ["HISPANIC", "N", 8, 0], ["AGE_UNDER5", "N", 8, 0],
+ ... ["AGE_5_17", "N", 8, 0], ["AGE_18_29", "N", 8, 0], ["AGE_30_49", "N", 8, 0],
+ ... ["AGE_50_64", "N", 8, 0], ["AGE_65_UP", "N", 8, 0],
+ ... ["NEVERMARRY", "N", 8, 0], ["MARRIED", "N", 9, 0], ["SEPARATED", "N", 7, 0],
+ ... ["WIDOWED", "N", 8, 0], ["DIVORCED", "N", 8, 0], ["HSEHLD_1_M", "N", 8, 0],
+ ... ["HSEHLD_1_F", "N", 8, 0], ["MARHH_CHD", "N", 8, 0],
+ ... ["MARHH_NO_C", "N", 8, 0], ["MHH_CHILD", "N", 7, 0],
+ ... ["FHH_CHILD", "N", 7, 0], ["HSE_UNITS", "N", 9, 0], ["VACANT", "N", 7, 0],
+ ... ["OWNER_OCC", "N", 8, 0], ["RENTER_OCC", "N", 8, 0],
+ ... ["MEDIAN_VAL", "N", 7, 0], ["MEDIANRENT", "N", 4, 0],
+ ... ["UNITS_1DET", "N", 8, 0], ["UNITS_1ATT", "N", 7, 0], ["UNITS2", "N", 7, 0],
+ ... ["UNITS3_9", "N", 8, 0], ["UNITS10_49", "N", 8, 0],
+ ... ["UNITS50_UP", "N", 8, 0], ["MOBILEHOME", "N", 7, 0]]
+
+ You can get a list of the shapefile's records by calling the records() method:
+
+
+ >>> records = sf.records()
+
+ >>> len(records)
+ 663
+
+ Similar to the geometry methods, you can iterate through dbf records using the
+ iterRecords() method.
+
+
+ >>> len(list(sf.iterRecords()))
+ 663
+
+ Each record is a list containing an attribute corresponding to each field in
+ the field list.
+
+ For example in the 4th record of the blockgroups shapefile the 2nd and 3rd
+ fields are the blockgroup id and the 1990 population count of that San
+ Francisco blockgroup:
+
+
+ >>> records[3][1:3]
+ ['060750601001', 4715]
+
+ To read a single record call the record() method with the record's index:
+
+
+ >>> rec = sf.record(3)
+
+ >>> rec[1:3]
+ ['060750601001', 4715]
+
+ ### Reading Geometry and Records Simultaneously
+
+ You way want to examine both the geometry and the attributes for a record at
+ the same time. The shapeRecord() and shapeRecords() method let you do just
+ that.
+
+ Calling the shapeRecords() method will return the geometry and attributes for
+ all shapes as a list of ShapeRecord objects. Each ShapeRecord instance has a
+ "shape" and "record" attribute. The shape attribute is a ShapeRecord object as
+ dicussed in the first section "Reading Geometry". The record attribute is a
+ list of field values as demonstrated in the "Reading Records" section.
+
+
+ >>> shapeRecs = sf.shapeRecords()
+
+ Let's read the blockgroup key and the population for the 4th blockgroup:
+
+
+ >>> shapeRecs[3].record[1:3]
+ ['060750601001', 4715]
+
+ Now let's read the first two points for that same record:
+
+
+ >>> points = shapeRecs[3].shape.points[0:2]
+
+ >>> len(points)
+ 2
+
+ The shapeRecord() method reads a single shape/record pair at the specified index.
+ To get the 4th shape record from the blockgroups shapfile use the third index:
+
+
+ >>> shapeRec = sf.shapeRecord(3)
+
+ The blockgroup key and population count:
+
+
+ >>> shapeRec.record[1:3]
+ ['060750601001', 4715]
+
+ >>> points = shapeRec.shape.points[0:2]
+
+ >>> len(points)
+ 2
+
+ There is also an iterShapeRecords() method to iterate through large files:
+
+ >>> shapeRecs = sf.iterShapeRecords()
+ >>> for shapeRec in shapeRecs:
+ ... # do something here
+ ... pass
+
+
+ ## Writing Shapefiles
+
+ PyShp tries to be as flexible as possible when writing shapefiles while
+ maintaining some degree of automatic validation to make sure you don't
+ accidentally write an invalid file.
+
+ PyShp can write just one of the component files such as the shp or dbf file
+ without writing the others. So in addition to being a complete shapefile
+ library, it can also be used as a basic dbf (xbase) library. Dbf files are a
+ common database format which are often useful as a standalone simple database
+ format. And even shp files occasionaly have uses as a standalone format. Some
+ web-based GIS systems use an user-uploaded shp file to specify an area of
+ interest. Many precision agriculture chemical field sprayers also use the shp
+ format as a control file for the sprayer system (usually in combination with
+ custom database file formats).
+
+ To create a shapefile you add geometry and/or attributes using methods in the
+ Writer class until you are ready to save the file.
+
+ Create an instance of the Writer class to begin creating a shapefile:
+
+
+ >>> w = shapefile.Writer()
+
+ ### Setting the Shape Type
+
+ The shape type defines the type of geometry contained in the shapefile. All of
+ the shapes must match the shape type setting.
+
+ Shape types are represented by numbers between 0 and 31 as defined by the
+ shapefile specification. It is important to note that numbering system has
+ several reserved numbers which have not been used yet therefore the numbers of
+ the existing shape types are not sequential.
+
+ There are three ways to set the shape type:
+ * Set it when creating the class instance.
+ * Set it by assigning a value to an existing class instance.
+ * Set it automatically to the type of the first shape by saving the shapefile.
+
+ To manually set the shape type for a Writer object when creating the Writer:
+
+
+ >>> w = shapefile.Writer(shapeType=1)
+
+ >>> w.shapeType
+ 1
+
+ OR you can set it after the Writer is created:
+
+
+ >>> w.shapeType = 3
+
+ >>> w.shapeType
+ 3
+
+ ### Geometry and Record Balancing
+
+ Because every shape must have a corresponding record it is critical that the
+ number of records equals the number of shapes to create a valid shapefile. To
+ help prevent accidental misalignment the PSL has an "auto balance" feature to
+ make sure when you add either a shape or a record the two sides of the
+ equation line up. This feature is NOT turned on by default. To activate it set
+ the attribute autoBalance to 1 (True):
+
+
+ >>> w.autoBalance = 1
+
+ You also have the option of manually calling the balance() method each time
+ you add a shape or a record to ensure the other side is up to date. When
+ balancing is used null shapes are created on the geometry side or a record
+ with a value of "NULL" for each field is created on the attribute side.
+
+ The balancing option gives you flexibility in how you build the shapefile.
+
+ Without auto balancing you can add geometry or records at anytime. You can
+ create all of the shapes and then create all of the records or vice versa. You
+ can use the balance method after creating a shape or record each time and make
+ updates later. If you do not use the balance method and forget to manually
+ balance the geometry and attributes the shapefile will be viewed as corrupt by
+ most shapefile software.
+
+ With auto balanacing you can add either shapes or geometry and update blank
+ entries on either side as needed. Even if you forget to update an entry the
+ shapefile will still be valid and handled correctly by most shapefile
+ software.
+
+ ### Adding Geometry
+
+ Geometry is added using one of three methods: "null", "point", or "poly". The
+ "null" method is used for null shapes, "point" is used for point shapes, and
+ "poly" is used for everything else.
+
+ **Adding a Point shape**
+
+ Point shapes are added using the "point" method. A point is specified by an x,
+ y, and optional z (elevation) and m (measure) value.
+
+
+ >>> w = shapefile.Writer()
+
+ >>> w.point(122, 37) # No elevation or measure values
+
+ >>> w.shapes()[0].points
+ [[122, 37, 0, 0]]
+
+ >>> w.point(118, 36, 4, 8)
+
+ >>> w.shapes()[1].points
+ [[118, 36, 4, 8]]
+
+ **Adding a Poly shape**
+
+ "Poly" shapes can be either polygons or lines. Shapefile polygons must have at
+ least 4 points and the last point must be the same as the first. PyShp
+ automatically enforces closed polygons. A line must have at least two points.
+ Because of the similarities between these two shape types they are created
+ using a single method called "poly".
+
+
+ >>> w = shapefile.Writer()
+
+ >>> w.poly(shapeType=3, parts=[[[122,37,4,9], [117,36,3,4]], [[115,32,8,8],
+ ... [118,20,6,4], [113,24]]])
+
+ **Adding a Null shape**
+
+ Because Null shape types (shape type 0) have no geometry the "null" method is
+ called without any arguments. This type of shapefile is rarely used but it is valid.
+
+
+ >>> w = shapefile.Writer()
+
+ >>> w.null()
+
+ The writer object's shapes list will now have one null shape:
+
+
+ >>> assert w.shapes()[0].shapeType == shapefile.NULL
+
+ ### Creating Attributes
+
+ Creating attributes involves two steps. Step 1 is to create fields to contain
+ attribute values and step 2 is to populate the fields with values for each
+ shape record.
+
+ The following attempts to create a complete shapefile. The attribute and
+ field names are not very creative:
+
+
+ >>> w = shapefile.Writer(shapefile.POINT)
+ >>> w.point(1,1)
+ >>> w.point(3,1)
+ >>> w.point(4,3)
+ >>> w.point(2,2)
+ >>> w.field('FIRST_FLD')
+ >>> w.field('SECOND_FLD','C','40')
+ >>> w.record('First','Point')
+ >>> w.record('Second','Point')
+ >>> w.record('Third','Point')
+ >>> w.record('Fourth','Point')
+ >>> w.save('shapefiles/test/point')
+
+ >>> w = shapefile.Writer(shapefile.POLYGON)
+ >>> w.poly(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
+ >>> w.field('FIRST_FLD','C','40')
+ >>> w.field('SECOND_FLD','C','40')
+ >>> w.record('First','Polygon')
+ >>> w.save('shapefiles/test/polygon')
+
+ >>> w = shapefile.Writer(shapefile.POLYLINE)
+ >>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
+ >>> w.poly(parts=[[[1,3],[5,3]]], shapeType=shapefile.POLYLINE)
+ >>> w.field('FIRST_FLD','C','40')
+ >>> w.field('SECOND_FLD','C','40')
+ >>> w.record('First','Line')
+ >>> w.record('Second','Line')
+ >>> w.save('shapefiles/test/line')
+
+ You can also add attributes using keyword arguments where the keys are field
+ names.
+
+
+ >>> w = shapefile.Writer(shapefile.POLYLINE)
+ >>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
+ >>> w.field('FIRST_FLD','C','40')
+ >>> w.field('SECOND_FLD','C','40')
+ >>> w.record(FIRST_FLD='First', SECOND_FLD='Line')
+ >>> w.save('shapefiles/test/line')
+
+ ### File Names
+
+ File extensions are optional when reading or writing shapfiles. If you specify
+ them PyShp ignores them anyway. When you save files you can specify a base
+ file name that is used for all three file types. Or you can specify a nmae for
+ one or more file types. In that case, any file types not assigned will not
+ save and only file types with file names will be saved. If you do not specify
+ any file names (i.e. save()), then a unique file name is generated with the
+ prefix "shapefile_" followed by random characters which is used for all three
+ files. The unique file name is returned as a string.
+
+
+ >>> targetName = w.save()
+ >>> assert("shapefile_" in targetName)
+
+ ### Saving to File-Like Objects
+
+ Just as you can read shapefiles from python file-like objects you can also
+ write them.
+
+
+ >>> try:
+ ... from StringIO import StringIO
+ ... except ImportError:
+ ... from io import BytesIO as StringIO
+ >>> shp = StringIO()
+ >>> shx = StringIO()
+ >>> dbf = StringIO()
+ >>> w.saveShp(shp)
+ >>> w.saveShx(shx)
+ >>> w.saveDbf(dbf)
+ >>> # Normally you would call the "StringIO.getvalue()" method on these objects.
+ >>> shp = shx = dbf = None
+
+ ## Editing Shapefiles
+
+ The Editor class attempts to make changing existing shapefiles easier by
+ handling the reading and writing details behind the scenes. This class is
+ experimental and should be avoided for production use. You can do the same
+ thing by reading a shapefile into memory, making changes to the python objects,
+ and write out a new shapefile with the same or different name.
+
+ Let's add shapes to existing shapefiles:
+
+ Add a point to a point shapefile
+
+
+ >>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
+ >>> e.point(0,0,10,2)
+ >>> e.record("Appended","Point")
+ >>> e.save('shapefiles/test/point')
+
+ Add a new line to a line shapefile:
+
+
+ >>> e = shapefile.Editor(shapefile="shapefiles/test/line.shp")
+ >>> e.line(parts=[[[10,5],[15,5],[15,1],[13,3],[11,1]]])
+ >>> e.record('Appended','Line')
+ >>> e.save('shapefiles/test/line')
+
+ Add a new polygon to a polygon shapefile:
+
+
+ >>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
+ >>> e.poly(parts=[[[5.1,5],[9.9,5],[9.9,1],[7.5,3],[5.1,1]]])
+ >>> e.record("Appended","Polygon")
+ >>> e.save('shapefiles/test/polygon')
+
+ Remove the first point in each shapefile - for a point shapefile that is the
+ first shape and record"
+
+
+ >>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
+ >>> e.delete(0)
+ >>> e.save('shapefiles/test/point')
+
+ Remove the last shape in the polygon shapefile.
+
+
+ >>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
+ >>> e.delete(-1)
+ >>> e.save('shapefiles/test/polygon')
+
+ ## Python \_\_geo_interface\_\_
+
+ The Python \_\_geo_interface\_\_ convention provides a data interchange interface
+ among geospatial Python libraries. The interface returns data as GeoJSON. More
+ information on the \_\_geo_interface\_\_ protocol can be found at: [https://gist.g
+ ithub.com/sgillies/2217756](https://gist.github.com/sgillies/2217756). More
+ information on GeoJSON is available at
+ [http://geojson.org](http://geojson.org).
+
+
+ >>> s = sf.shape(0)
+ >>> s.__geo_interface__["type"]
+ 'MultiPolygon'
+
+ # Testing
+
+ The testing framework is doctest, which are located in this file README.md.
+ In the same folder as README.md and shapefile.py, from the command line run
+ ```
+ $ python shapefile.py
+ ```
+
+ Linux/Mac and similar platforms will need to run `$ dos2unix README.md` in order
+ correct line endings in README.md.
Keywords: gis geospatial geographic shapefile shapefiles
Platform: UNKNOWN
diff --git a/README.txt b/README.txt
deleted file mode 100644
index df8014f..0000000
--- a/README.txt
+++ /dev/null
@@ -1,661 +0,0 @@
-PyShp
-========================
-
-:Author: Joel Lawhead - jlawhead at geospatialpython.com
-
-:Version 1.2.2
-
-:Revised: January 9, 2015
-
-.. contents::
-
-Overview
---------
-
-PyShp provides read and write support for the Esri
-Shapefile format. The Shapefile format is a popular Geographic Information
-System vector data format created by Esri. For more information about this format
-please read the well-written "ESRI Shapefile Technical Description - July 1998"
-located at http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf.
-The Esri document describes the shp and shx file formats. However a third file
-format called dbf is also required. This format is documented on the web as the
-"XBase File Format Description" and is a simple file-based database format created
-in the 1960's. For more on this specification see:
-http://www.clicketyclick.dk/databases/xbase/format/index.html
-
-Both the Esri and XBase file-formats are very simple in design and
-memory efficient which is part of the reason the shapefile format remains popular
-despite the numerous ways to store and exchange GIS data available today.
-
-Pyshp is compatible with Python 2.4-3.x.
-
-This document provides examples for using PyShp to read and write shapefiles.
-
-Currently the sample census blockgroup shapefile referenced in the examples is
-only available on the google code project site at http://code.google.com/p/pyshp.
-These examples are straight-forward and you can also easily run them against your
-own shapefiles manually with minimal modification. Other examples for specific
-topics are continually added to the pyshp wiki on google code and the blog
-http://GeospatialPython.com.
-
-Important: For information about map projections, shapefiles,
-and Python please visit: http://code.google.com/p/pyshp/wiki/MapProjections
-
-I sincerely hope this library eliminates the mundane distraction of simply
-reading and writing data, and allows you to focus on the challenging and FUN
-part of your geospatial project.
-
-Examples
---------
-
-Before doing anything you must import the library.
-
->>> import shapefile
-
-The examples below will use a shapefile created from the U.S. Census Bureau
-Blockgroups data set near San Francisco, CA and available in the subversion
-repository of the pyshp google code site.
-
-Reading Shapefiles
-++++++++++++++++++
-
-To read a shapefile create a new "Reader" object and pass it the name of an
-existing shapefile. The shapefile format is acutally a collection of three
-files. You specify the base filename of the shapefile or the complete filename
-of any of the shapefile component files.
-
->>> sf = shapefile.Reader("shapefiles/blockgroups")
-
-
-OR
-
->>> sf = shapefile.Reader("shapefiles/blockgroups.shp")
-
-
-OR
-
->>> sf = shapefile.Reader("shapefiles/blockgroups.dbf")
-
-
-OR any of the other 5+ formats which are potentially part of a shapefile.
-The library does not care about extensions.
-
-Reading Shapefiles from File-Like Objects
-.........................................
-
-You can also load shapefiles from any Python file-like object using keyword
-arguments to specify any of the three files. This feature is very powerful
-and allows you to load shapefiles from a url, from a zip file, serialized
-object, or in some cases a database.
-
->>> myshp = open("shapefiles/blockgroups.shp", "rb")
->>> mydbf = open("shapefiles/blockgroups.dbf", "rb")
->>> r = shapefile.Reader(shp=myshp, dbf=mydbf)
-
-Notice in the examples above the shx file is never used. The shx file is a
-very simple fixed-record index for the variable length records in the shp file.
-This file is optional for reading. If it's available pyshp will use the shx file
-to access shape records a little faster but will do just fine without it.
-
-Reading Geometry
-................
-
-A shapefile's geometry is the collection of points or shapes made from verticies
-and implied arcs representing physical locations. All types of shapefiles
-just store points. The metadata about the points determine how they are handled by
-software.
-
-You can get the a list of the shapefile's geometry by calling the shapes()
-method.
-
->>> shapes = sf.shapes()
-
-The shapes method returns a list of Shape objects describing the
-geometry of each shape record.
-
->>> len(shapes)
-663
-
-You can iterate through the shapefile's geometry using the iterShapes() method.
-
->>> len(list(sf.iterShapes()))
-663
-
-Each shape record contains the following attributes:
-
->>> for name in dir(shapes[3]):
-... if not name.startswith('__'):
-... name
-'bbox'
-'parts'
-'points'
-'shapeType'
-
- - shapeType: an integer representing the type of shape as defined by the
- shapefile specification.
-
->>> shapes[3].shapeType
-5
-
- - bbox: If the shape type contains multiple points this tuple describes the
- lower left (x,y) coordinate and upper right corner coordinate creating a
- complete box around the points. If the shapeType is a Null
- (shapeType == 0) then an AttributeError is raised.
-
->>> # Get the bounding box of the 4th shape.
->>> # Round coordinates to 3 decimal places
->>> bbox = shapes[3].bbox
->>> ['%.3f' % coord for coord in bbox]
-['-122.486', '37.787', '-122.446', '37.811']
-
- - parts: Parts simply group collections of points into shapes. If the shape record
- has multiple parts this attribute contains the index of the first point of each part.
- If there is only one part then a list containing 0 is returned.
-
->>> shapes[3].parts
-[0]
-
- - points: The points attribute contains a list of tuples containing an (x,y)
- coordinate for each point in the shape.
-
->>> len(shapes[3].points)
-173
->>> # Get the 8th point of the fourth shape
->>> # Truncate coordinates to 3 decimal places
->>> shape = shapes[3].points[7]
->>> ['%.3f' % coord for coord in shape]
-['-122.471', '37.787']
-
-To read a single shape by calling its index use the shape() method. The index
-is the shape's count from 0. So to read the 8th shape record you would
-use its index which is 7.
-
->>> s = sf.shape(7)
-
->>> # Read the bbox of the 8th shape to verify
->>> # Round coordinates to 3 decimal places
->>> ['%.3f' % coord for coord in s.bbox]
-['-122.450', '37.801', '-122.442', '37.808']
-
-Reading Records
-................
-
-A record in a shapefile contains the attributes for each shape in the
-collection of geometry. Records are stored in the dbf file. The link
-between geometry and attributes is the foundation of Geographic Information
-Systems. This critical link is implied by the order of shapes and
-corresponding records in the shp geometry file and the dbf attribute file.
-
-The field names of a shapefile are available as soon as you read a shapefile.
-You can call the "fields" attribute of the shapefile as a Python list. Each
-field is a Python list with the following information:
-
-- Field name: the name describing the data at this column index.
-
-- Field type: the type of data at this column index. Types can be: Character, Numbers, Longs, Dates, or Memo.
- The "Memo" type has no meaning within a GIS and is part of the xbase spec instead.
-
-- Field length: the length of the data found at this column index. Older GIS software may truncate this
- length to 8 or 11 characters for "Character" fields.
-
-- Decimal length: the number of decimal places found in "Number" fields.
-
-To see the fields for the Reader object above (sf) call the "fields" attribute:
-
->>> fields = sf.fields
-
->>> assert fields == [("DeletionFlag", "C", 1, 0), ["AREA", "N", 18, 5],
-... ["BKG_KEY", "C", 12, 0], ["POP1990", "N", 9, 0], ["POP90_SQMI", "N", 10, 1],
-... ["HOUSEHOLDS", "N", 9, 0],
-... ["MALES", "N", 9, 0], ["FEMALES", "N", 9, 0], ["WHITE", "N", 9, 0],
-... ["BLACK", "N", 8, 0], ["AMERI_ES", "N", 7, 0], ["ASIAN_PI", "N", 8, 0],
-... ["OTHER", "N", 8, 0], ["HISPANIC", "N", 8, 0], ["AGE_UNDER5", "N", 8, 0],
-... ["AGE_5_17", "N", 8, 0], ["AGE_18_29", "N", 8, 0], ["AGE_30_49", "N", 8, 0],
-... ["AGE_50_64", "N", 8, 0], ["AGE_65_UP", "N", 8, 0],
-... ["NEVERMARRY", "N", 8, 0], ["MARRIED", "N", 9, 0], ["SEPARATED", "N", 7, 0],
-... ["WIDOWED", "N", 8, 0], ["DIVORCED", "N", 8, 0], ["HSEHLD_1_M", "N", 8, 0],
-... ["HSEHLD_1_F", "N", 8, 0], ["MARHH_CHD", "N", 8, 0],
-... ["MARHH_NO_C", "N", 8, 0], ["MHH_CHILD", "N", 7, 0],
-... ["FHH_CHILD", "N", 7, 0], ["HSE_UNITS", "N", 9, 0], ["VACANT", "N", 7, 0],
-... ["OWNER_OCC", "N", 8, 0], ["RENTER_OCC", "N", 8, 0],
-... ["MEDIAN_VAL", "N", 7, 0], ["MEDIANRENT", "N", 4, 0],
-... ["UNITS_1DET", "N", 8, 0], ["UNITS_1ATT", "N", 7, 0], ["UNITS2", "N", 7, 0],
-... ["UNITS3_9", "N", 8, 0], ["UNITS10_49", "N", 8, 0],
-... ["UNITS50_UP", "N", 8, 0], ["MOBILEHOME", "N", 7, 0]]
-
-You can get a list of the shapefile's records by calling the records() method:
-
->>> records = sf.records()
-
->>> len(records)
-663
-
-Similar to the geometry methods, you can iterate through dbf records using the
-recordsIter() method.
-
->>> len(list(sf.iterRecords()))
-663
-
-Each record is a list containing an attribute corresponding to each field in the
-field list.
-
-For example in the 4th record of the blockgroups shapefile the 2nd and 3rd
-fields are the blockgroup id and the 1990 population count of
-that San Francisco blockgroup:
-
->>> records[3][1:3]
-['060750601001', 4715]
-
-To read a single record call the record() method with the record's index:
-
->>> rec = sf.record(3)
-
->>> rec[1:3]
-['060750601001', 4715]
-
-Reading Geometry and Records Simultaneously
-...........................................
-
-You way want to examine both the geometry and the attributes for a record at the
-same time. The shapeRecord() and shapeRecords() method let you do just that.
-
-Calling the shapeRecords() method will return the geometry and attributes for
-all shapes as a list of ShapeRecord objects. Each ShapeRecord instance has a
-"shape" and "record" attribute. The shape attribute is a ShapeRecord object as
-dicussed in the first section "Reading Geometry". The record attribute is a
-list of field values as demonstrated in the "Reading Records" section.
-
->>> shapeRecs = sf.shapeRecords()
-
-Let's read the blockgroup key and the population for the 4th blockgroup:
->>> shapeRecs[3].record[1:3]
-['060750601001', 4715]
-
-Now let's read the first two points for that same record:
-
->>> points = shapeRecs[3].shape.points[0:2]
-
->>> len(points)
-2
-
-The shapeRec() method reads a single shape/record pair at the specified index.
-To get the 4th shape record from the blockgroups shapfile use the third index:
-
->>> shapeRec = sf.shapeRecord(3)
-
-The blockgroup key and population count:
-
->>> shapeRec.record[1:3]
-['060750601001', 4715]
-
->>> points = shapeRec.shape.points[0:2]
-
->>> len(points)
-2
-
-There is also an iterShapeRecords() method to iterate through large files:
-
->>> shapeRecs = sf.iterShapeRecords()
->>> for shape, rec in shapeRecs:
-... # do something here
-
-Writing Shapefiles
-++++++++++++++++++
-
-PyShp tries to be as flexible as possible when writing shapefiles while
-maintaining some degree of automatic validation to make sure you don't
-accidentally write an invalid file.
-
-PyShp can write just one of the component files such as the shp or dbf file
-without writing the others. So in addition to being a complete
-shapefile library, it can also be used as a basic dbf (xbase) library. Dbf files are
-a common database format which are often useful as a standalone simple
-database format. And even shp files occasionaly have uses as a standalone
-format. Some web-based GIS systems use an user-uploaded shp file to specify
-an area of interest. Many precision agriculture chemical field sprayers also
-use the shp format as a control file for the sprayer system (usually in
-combination with custom database file formats).
-
-To create a shapefile you add geometry and/or attributes using methods in the
-Writer class until you are ready to save the file.
-
-Create an instance of the Writer class to begin creating a shapefile:
-
->>> w = shapefile.Writer()
-
-
-Setting the Shape Type
-......................
-
-The shape type defines the type of geometry contained in the shapefile. All of
-the shapes must match the shape type setting.
-
-Shape types are represented by numbers between 0 and 31 as defined by the
-shapefile specification. It is important to note that numbering system has
-several reserved numbers which have not been used yet therefore the numbers of
-the existing shape types are not sequential.
-
-You can reference shape types by the numbers or by constants defined by PyShp:
-shapefile.NULL = 0
-shapefile.POINT = 1
-shapefile.POLYLINE = 3
-shapefile.POLYGON = 5
-shapefile.MULTIPOINT = 8
-shapefile.POINTZ = 11
-shapefile.POLYLINEZ = 13
-shapefile.POLYGONZ = 15
-shapefile.MULTIPOINTZ = 18
-shapefile.POINTM = 21
-shapefile.POLYLINEM = 23
-shapefile.POLYGONM = 25
-shapefile.MULTIPOINTM = 28
-shapefile.MULTIPATCH = 31
-
-There are three ways to set the shape type:
-- Set it when creating the class instance.
-- Set it by assigning a value to an existing class instance.
-- Set it automatically to the type of the first shape by saving the shapefile.
-
-To manually set the shape type for a Writer object when creating the Writer:
-
->>> w = shapefile.Writer(shapeType=1)
-
-or we can use the constants as explained above:
-
->>> w = shapefile.Writer(shapefile.POINT)
-
-As you can see, specifying the shapeType argument explicitly isn't necessary.
-
->>> w.shapeType
-1
-
-OR you can set it after the Writer is created by changing the property:
-
->>> w.shapeType = 3
-
->>> w.shapeType
-3
-
-Geometry and Record Balancing
-.............................
-
-Because every shape must have a corresponding record it is critical that the
-number of records equals the number of shapes to create a valid shapefile. To
-help prevent accidental misalignment PyShp has an "auto balance" feature to
-make sure when you add either a shape or a record the two sides of the
-equation line up. This feature is NOT turned on by default. To activate it
-set the attribute autoBalance to 1 (True):
-
->>> w.autoBalance = 1
-
-You also have the option of manually calling the balance() method each time you
-add a shape or a record to ensure the other side is up to date. When balancing
-is used null shapes are created on the geometry side or a record with a value of
-"NULL" for each field is created on the attribute side.
-
-The balancing option gives you flexibility in how you build the shapefile.
-
-Without auto balancing you can add geometry or records at anytime. You can
-create all of the shapes and then create all of the records or vice versa. You
-can use the balance method after creating a shape or record each time and make
-updates later. If you do not use the balance method and forget to manually
-balance the geometry and attributes the shapefile will be viewed as corrupt by
-most shapefile software.
-
-With auto balanacing you can add either shapes or geometry and update blank
-entries on either side as needed. Even if you forget to update an entry the
-shapefile will still be valid and handled correctly by most shapefile software.
-
-Adding Geometry
-...............
-
-Geometry is added using one of three methods: "null", "point", or "poly". The "null"
-method is used for null shapes, "point" is used for point shapes, and "poly" is
-used for everything else.
-
-**Adding a Null shape**
-
-Because Null shape types (shape type 0) have no geometry the "null" method is
-called without any arguments.
-
->>> w = shapefile.Writer()
-
->>> w.null()
-
-The writer object's shapes list will now have one null shape:
-
->>> assert w.shapes()[0].shapeType == shapefile.NULL
-
-**Adding a Point shape**
-
-Point shapes are added using the "point" method. A point is specified by an
-x, y, and optional z (elevation) and m (measure) value.
-
->>> w = shapefile.Writer(shapefile.POINT)
-
->>> w.point(122, 37) # No elevation or measure values
-
->>> w.shapes()[0].points
-[[122, 37, 0, 0]]
-
->>> w.point(118, 36, 4, 8)
-
->>> w.shapes()[1].points
-[[118, 36, 4, 8]]
-
-**Adding a Poly Shape**
-
-"Poly" shapes can be either polygons or lines. Shapefile polygons must have at
-least 4 points and the last point must be the same as the first. PyShp automatically
-enforces closed polygons.
-A line must have at least two points.
-Because of the similarities between these two shape types they are created using
-a single method called "poly".
-
->>> w = shapefile.Writer(shapefile.POLYGON)
-
->>> w.poly(shapeType=3, parts=[[[122,37,4,9], [117,36,3,4]], [[115,32,8,8],
-... [118,20,6,4], [113,24]]])
-
-**Adding a Polygon with Rings**
-
-Polygons consist of rings which mean they are closed. The first point and last point
-of a ring must be the same. PyShp enforces ring closure if the ring is incomplete when
-you add the shape. Polygons can have inner rings which create holes. Holes are defined
-by the order of the points. Normally points in a ring run clockwise. If the points
-run counter-clockwise then they form a hole. If you don't order the points correctly
-you'll just have overlapping polygons.
-
->>> w = shapefile.Writer(shapefile.POLYGON)
->>> outer_ring = [[10,10],[50,50],[100,10],[50,-50],[10,10]]
->>> inner_ring = [[40,10],[50,30],[70,10],[50,-30],[40,10]]
->>> inner_ring.reverse()
-
-You can use the "shapefile.signed_area()" method to determine if a ring is clockwise
-or counter-clockwise. A value >= 0 means the ring is counter-clockwise and < 0 means
-the ring is clockwise. The value returned is also the area of the polygon.
-
->>> # Clockwise ring
-... shapefile.signed_area(outer_ring)
--4500.0
->>> # Counter-clockwise ring
-... shapefile.signed_area(inner_ring)
-900.0
-
-**Creating 3D Polygons**
-
-Elevation values, known as "Z" values allow you to create 3-dimensional shapefiles. The
-z value is an extra value specified as part of a point.
-
->>> w = shapefile.Writer(shapeType=shapefile.POLYGONZ)
->>> w.poly([[[-89.0, 33, 12], [-90, 31, 11], [-91, 30, 12]]], shapeType=15)
->>> w.field("NAME")
->>> w.record("PolyZTest")
->>> w.save("shapefiles/test/MyPolyZ")
-
-The z values are stored in a seperate shape attribute.
-
->>> r = shapefile.Reader("shapefiles/test/MyPolyZ")
->>> s = r.shape(0)
->>> s.points
-[[-89.0, 33.0], [-90.0, 31.0], [-91.0, 30.0], [-89.0, 33.0]]
->>> s.z
-[12.0, 11.0, 12.0, 12.0]
-
-Creating Attributes
-...................
-
-Creating attributes involves two steps. Step 1 is to create fields to contain
-attribute values and step 2 is to populate the fields with values for each
-shape record.
-
-The following attempts to create a complete shapefile:
-
->>> w = shapefile.Writer(shapefile.POINT)
->>> w.point(1,1)
->>> w.point(3,1)
->>> w.point(4,3)
->>> w.point(2,2)
->>> w.field('FIRST_FLD')
->>> w.field('SECOND_FLD','C','40')
->>> w.record('First','Point')
->>> w.record('Second','Point')
->>> w.record('Third','Point')
->>> w.record('Fourth','Point')
->>> w.save('shapefiles/test/point')
-
->>> w = shapefile.Writer(shapefile.POLYGON)
->>> w.poly(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
->>> w.field('FIRST_FLD','C','40')
->>> w.field('SECOND_FLD','C','40')
->>> w.record('First','Polygon')
->>> w.save('shapefiles/test/polygon')
-
->>> w = shapefile.Writer(shapefile.POLYLINE)
->>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
->>> w.poly(parts=[[[1,3],[5,3]]], shapeType=shapefile.POLYLINE)
->>> w.field('FIRST_FLD','C','40')
->>> w.field('SECOND_FLD','C','40')
->>> w.record('First','Line')
->>> w.record('Second','Line')
->>> w.save('shapefiles/test/line')
-
-You can also add attributes using keyword arguments where the keys are field names.
-
->>> w = shapefile.Writer(shapefile.POLYLINE)
->>> w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])
->>> w.field('FIRST_FLD','C','40')
->>> w.field('SECOND_FLD','C','40')
->>> w.record(FIRST_FLD='First', SECOND_FLD='Line')
->>> w.save('shapefiles/test/line')
-
-File Names
-..........
-
-File extensions are optional when reading or writing shapfiles. If you specify them Pyshp
-ignores them anyway. When you save files you can specify a base file name that is used for
-all three file types. Or you can specify a nmae for one or more file types. In that case,
-any file types not assigned will not save and only file types with file names will be saved.
-If you do not specify any file names (i.e. save()), then a unique file name is generated with
-the prefix "shapefile\_" followed by random characters which is used for all three files. The
-unique file name is returned as a string.
-
->>> targetName = w.save()
->>> assert("shapefile_" in targetName)
-
-Saving to File-Like Objects
-...........................
-
-Just as you can read shapefiles from python file-like objects you can also write them.
-
->>> try:
-... from StringIO import StringIO
-... except ImportError:
-... from io import BytesIO as StringIO
->>> shp = StringIO()
->>> shx = StringIO()
->>> dbf = StringIO()
->>> w.saveShp(shp)
->>> w.saveShx(shx)
->>> w.saveDbf(dbf)
->>> # Normally you would call the "StringIO.getvalue()" method on these objects.
->>> shp = shx = dbf = None
-
-Editing Shapefiles
-++++++++++++++++++
-
-The Editor class attempts to make changing existing shapefiles easier by handling the reading and writing details behind the scenes.
-
-Let's add shapes to existing shapefiles:
-
-Add a point to a point shapefile
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
->>> e.point(0,0,10,2)
->>> e.record("Appended","Point")
->>> # We added z and m values so
->>> # change the shapetype
->>> e.shapeType = shapefile.POINTZ
->>> e.save('shapefiles/test/point')
-
-Edit the appended point to change the "y" and "z" value
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
->>> # Find the point by the attribute
->>> for s in enumerate(e.records):
-... i, record = s
-... if record[0] == "Appended":
-... geom = e._shapes[i]
-... # Change the y value to 5
-... geom.points[0][1] = 5
-... # Change the z value to 9
-... if hasattr(geom, "z"):
-... geom.z = (9,)
-... else:
-... geom.points[0][2] = 9
->>> e.save('shapefiles/test/point')
-
-Add a new line to a line shapefile:
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/line.shp")
->>> e.line(parts=[[[10,5],[15,5],[15,1],[13,3],[11,1]]])
->>> e.record('Appended','Line')
->>> e.save('shapefiles/test/line')
->>> e = None
-
-Add a new polygon to a polygon shapefile:
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
->>> e.poly(parts=[[[5.1,5],[9.9,5],[9.9,1],[7.5,3],[5.1,1]]])
->>> e.record("Appended","Polygon")
->>> e.save('shapefiles/test/polygon')
->>> e = None
-
-Remove the first point in each shapefile - for a point shapefile that is
-the first shape and record"
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/point.shp")
->>> e.delete(0)
->>> e.save('shapefiles/test/point')
->>> e = None
-
-Remove the last shape in the polygon shapefile.
-
->>> e = shapefile.Editor(shapefile="shapefiles/test/polygon.shp")
->>> e.delete(-1)
->>> e.save('shapefiles/test/polygon')
->>> e = None
-
-Python __geo_interface__
-++++++++++++++++++++++++
-
-The Python __geo_interface__ convention provides a data interchange interface
-among geospatial Python libraries. The interface returns data as GeoJSON.
-More information on the __geo_interface__ protocol can be found at:
-https://gist.github.com/sgillies/2217756.
-More information on GeoJSON is available at http://geojson.org.
-
->>> s = sf.shape(0)
->>> s.__geo_interface__["type"]
-'MultiPolygon'
-
diff --git a/setup.py b/setup.py
index a5a0b8c..890f12e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,13 +1,13 @@
from setuptools import setup
setup(name='pyshp',
- version='1.2.3',
+ version='1.2.8',
description='Pure Python read/write support for ESRI Shapefile format',
- long_description=open('README.txt').read(),
+ long_description=open('README.md').read(),
author='Joel Lawhead',
author_email='jlawhead at geospatialpython.com',
url='https://github.com/GeospatialPython/pyshp',
- download_url='https://github.com/GeospatialPython/pyshp/archive/1.2.3.tar.gz',
+ download_url='https://github.com/GeospatialPython/pyshp/archive/1.2.8.tar.gz',
py_modules=['shapefile'],
license='MIT',
zip_safe=False,
diff --git a/shapefile.py b/shapefile.py
index c125a90..e665c4f 100644
--- a/shapefile.py
+++ b/shapefile.py
@@ -3,14 +3,15 @@ shapefile.py
Provides read and write support for ESRI Shapefiles.
author: jlawhead<at>geospatialpython.com
date: 2015/06/22
-version: 1.2.3
+version: 1.2.8
Compatible with Python versions 2.4-3.x
-version changelog: Reader.iterShapeRecords() bugfix for Python 3
+version changelog:
+- Pushing 1.2.5 changes to PyPi using Travis-CI.
"""
-__version__ = "1.2.3"
+__version__ = "1.2.8"
-from struct import pack, unpack, calcsize, error
+from struct import pack, unpack, calcsize, error, Struct
import os
import sys
import time
@@ -96,8 +97,7 @@ class _Array(array.array):
def signed_area(coords):
"""Return the signed area enclosed by a ring using the linear time
- algorithm at http://www.cgafaq.info/wiki/Polygon_Area. A value >= 0
- indicates a counter-clockwise oriented ring.
+ algorithm. A value >= 0 indicates a counter-clockwise oriented ring.
"""
xs, ys = map(list, zip(*coords))
xs.append(xs[1])
@@ -337,7 +337,7 @@ class Reader:
if shapeType in (3,5,13,15,23,25,31):
nParts = unpack("<i", f.read(4))[0]
# Shape types with points
- if shapeType in (3,5,8,13,15,23,25,31):
+ if shapeType in (3,5,8,13,15,18,23,25,28,31):
nPoints = unpack("<i", f.read(4))[0]
# Read parts
if nParts:
@@ -347,7 +347,8 @@ class Reader:
record.partTypes = _Array('i', unpack("<%si" % nParts, f.read(nParts * 4)))
# Read points - produces a list of [x,y] values
if nPoints:
- record.points = [_Array('d', unpack("<2d", f.read(16))) for p in range(nPoints)]
+ flat = unpack("<%sd" % (2 * nPoints), f.read(16*nPoints))
+ record.points = list(izip(*(iter(flat),) * 2))
# Read z extremes and values
if shapeType in (13,15,18,31):
(zmin, zmax) = unpack("<2d", f.read(16))
@@ -390,10 +391,12 @@ class Reader:
numRecords = shxRecordLength // 8
# Jump to the first record.
shx.seek(100)
- for r in range(numRecords):
- # Offsets are 16-bit words just like the file length
- self._offsets.append(unpack(">i", shx.read(4))[0] * 2)
- shx.seek(shx.tell() + 4)
+ shxRecords = _Array('i')
+ # Each offset consists of two nrs, only the first one matters
+ shxRecords.fromfile(shx, 2 * numRecords)
+ if sys.byteorder != 'big':
+ shxRecords.byteswap()
+ self._offsets = [2 * el for el in shxRecords[::2]]
if not i == None:
return self._offsets[i]
@@ -470,6 +473,8 @@ class Reader:
if terminator != b("\r"):
raise ShapefileException("Shapefile dbf header lacks expected terminator. (likely corrupt?)")
self.fields.insert(0, ('DeletionFlag', 'C', 1, 0))
+ fmt,fmtSize = self.__recordFmt()
+ self.__recStruct = Struct(fmt)
def __recordFmt(self):
"""Calculates the size of a .shp geometry record."""
@@ -482,8 +487,7 @@ class Reader:
def __record(self):
"""Reads and returns a dbf record row as a list of values."""
f = self.__getFileObj(self.dbf)
- recFmt = self.__recordFmt()
- recordContents = unpack(recFmt[0], f.read(recFmt[1]))
+ recordContents = self.__recStruct.unpack(f.read(self.__recStruct.size))
if recordContents[0] != b(' '):
# deleted record
return None
@@ -501,9 +505,17 @@ class Reader:
if value == b(''):
value = None
elif deci:
- value = float(value)
+ try:
+ value = float(value)
+ except ValueError:
+ #not parseable as float, set to None
+ value = None
else:
- value = int(value)
+ try:
+ value = int(value)
+ except ValueError:
+ #not parseable as int, set to None
+ value = None
elif typ == b('D'):
if value.count(b('0')) == len(value): # QGIS NULL is all '0' chars
value = None
@@ -528,7 +540,7 @@ class Reader:
if not self.numRecords:
self.__dbfHeader()
i = self.__restrictIndex(i)
- recSize = self.__recordFmt()[1]
+ recSize = self.__recStruct.size
f.seek(0)
f.seek(self.__dbfHeaderLength() + (i * recSize))
return self.__record()
@@ -537,13 +549,11 @@ class Reader:
"""Returns all records in a dbf file."""
if not self.numRecords:
self.__dbfHeader()
- records = []
f = self.__getFileObj(self.dbf)
f.seek(self.__dbfHeaderLength())
- for i in range(self.numRecords):
- r = self.__record()
- if r:
- records.append(r)
+ flat = unpack(self.__recStruct.format * self.numRecords, f.read(self.__recStruct.size * self.numRecords))
+ rowlen = len(self.fields) - 1
+ records = list(izip(*(iter(flat),) * rowlen))
return records
def iterRecords(self):
@@ -1183,11 +1193,11 @@ class Editor(Writer):
def test():
import doctest
doctest.NORMALIZE_WHITESPACE = 1
- doctest.testfile("README.txt", verbose=1)
+ doctest.testfile("README.md", verbose=1)
if __name__ == "__main__":
"""
- Doctests are contained in the file 'README.txt'. This library was originally developed
+ Doctests are contained in the file 'README.md'. This library was originally developed
using Python 2.3. Python 2.4 and above have some excellent improvements in the built-in
testing libraries but for now unit testing is done using what's available in
2.3.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pyshp.git
More information about the Pkg-grass-devel
mailing list