zhikrullah / pyshp

Automatically exported from code.google.com/p/pyshp
MIT License
0 stars 0 forks source link

I made some pyshp edits to allow a list for point coordinates and a list or dict for records #46

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
This isn't a bug report.  The pyshp library is awesome!  I actually just have a 
few suggestions for the pyshp code.  

The first is to allow a list of coordinates when writing points:

Currently you must do this:

    w = shapefile.Writer(shapefile.POINTZ)
    coordList = [-80, 40, 300]
    x = coordList[0]
    y = coordList[1]
    z = coordList[2]
    w.point(x,y,z)

I made changes to the code so I can do this:

    w = shapefile.Writer(shapefile.POINTZ)
    coordList = [-80, 40, 300]
    w.point(coordList)

Here are the edits to the pyshp code for allowing lists of coordinates:

    def getValue(self, argList, argNum):
        try:
            return argList[argNum]
        except IndexError:
            return 0

    def point(self, x, y=None, z=0, m=0):
        """Creates a point shape."""
        if type(x) is list:
            truex = self.getValue(x, 0)
            y = self.getValue(x, 1)
            z = self.getValue(x, 2)
            m = self.getValue(x, 3)
            x = truex
        elif type(x) is not list and y == None:
            raise ShapefileException('A y-value was not supplied for the point')
        pointShape = _Shape(self.shapeType)
        pointShape.points.append([x, y, z, m])
        self._shapes.append(pointShape)

My second suggestion is to allow a list or dict to be used for writing records:

Currently you must do this:

    w = shapefile.Writer(shapefile.POINTZ)
    fieldNames = ['longitude','latitude','elevation']
    makeFields = [ w.field(field) for field in fieldNames ]
    w.point(-80,40,300)
    fieldValues = ['-80','40','300']
    longitude = fieldValues[0]
    latitude = fieldValues[1]
    elevation = fieldValues[1]
    w.record(longitude,latitude,elevation)

I made changes to the code so I use a list instead of multiple arguments:

    w = shapefile.Writer(shapefile.POINTZ)
    fieldNames = ['longitude','latitude','elevation']
    makeFields = [ w.field(field) for field in fieldNames ]
    w.point(-80,40,300)
    fieldValues = ['-80','40','300']
    w.record(fieldValues)

or use a dict:

    w = shapefile.Writer(shapefile.POINTZ)
    fieldNames = ['longitude','latitude','elevation']
    makeFields = [ w.field(field) for field in fieldNames ]
    w.point(-80,40,300)
    fieldValues = {'longitude': '-80', 'latitude': '45', 'elevation': '300'}
    w.record(fieldValues)

Here are the changes I made to allow for lists or dicts but still allow 
individual args:

    def record(self, *recordList, **recordDict):
        """Creates a dbf attribute record. You can submit either a sequence of
        field values or keyword arguments of field names and values. Before
        adding records you must add fields for the record values using the
        fields() method. If the record values exceed the number of fields the
        extra ones won't be added. In the case of using keyword arguments to specify
        field/value pairs only fields matching the already registered fields
        will be added."""
        record = []
        fieldCount = len(self.fields)
        # Compensate for deletion flag
        if self.fields[0][0].startswith("Deletion"): fieldCount -= 1
        if recordList and type(recordList[0]) is list:
            [record.append(recordList[0][i]) for i in range(fieldCount)]
        elif recordList and type(recordList[0]) is not list and type(recordList[0]) is not dict:
            [record.append(recordList[i]) for i in range(fieldCount)]
        elif recordList and type(recordList[0]) is dict or recordDict:
            recordDict = recordList[0] if recordList and type(recordList[0]) is dict else recordDict
            for field in self.fields:
                if field[0] in recordDict:
                    val = recordDict[field[0]]
                    if val:
                        record.append(val)
                    else:
                        record.append("")
        if record:
            self.records.append(record)

I tested these changes to make sure they don't break the functionality of 
passing in individual arguments, but I was using single file to test and could 
have easily overlooked something.

I used these pyshp changes in a GPX waypoints to SHP script I wrote.  It allows 
me to pass lists to the point and record methods while looping through the 
waypoints.

I think these changes would be beneficial for others and they don't add too 
much to the existing code.

Thanks for the great work.

Original issue reported on code.google.com by Ryan.J.S...@gmail.com on 16 Feb 2013 at 9:16