I recently had a request for a shapefile containing geographic informaton for some of the stations listed on Variable Pitch. I’d been meaning to create a simple export facility for a while, but had never really looked at shapefiles in any detail before. As it took me a few attempts to get them working correctly, the following may help others!
I’m using the pyshp python module.
Essentially I’m creating a shapefile with a list of points. Each point will have a series of data fields associated with it. At the present time I’ve not specified types or other details for the fields, but that may be something I do in the future.
writer = shapefile.Writer(shapefile.POINT)<br></br> writer.autoBalance = 1<br></br> writer.field('Station Name')<br></br> writer.field('Technology')<br></br> writer.field('Variable Pitch ID')``` Now the writer object is prepared, I loop through the stations I need to add and write the data. This is done in two steps, the first adding the point and the second the data associated with it. As the station names are stored in Unicode and the shapefile expects ascii, I have forced a simple conversion to ascii (ignoring any characters that cannot be converted).
for s in stations:
writer.record(s.name.encode('ascii', 'ignore'), s.category.desc, "%d" % s.id, 'Point')
At this point I have all the data in the writer object, but now need to create the 3 or 4 files that comprise a shapefile. To keep things simple I elected to create a single zipefile containing all the generated files which can then be downloaded. All generation is done in memory.
s = cStringIO.StringIO()<br></br> zf = zipfile.ZipFile(s, "w")``` fobj = cStringIO.StringIO() writer.saveShp(fobj) zf.writestr('%s/shapefile.shp' % filename, fobj.getvalue()) fobj.close() fobj = cStringIO.StringIO() writer.saveShx(fobj) zf.writestr('%s/shapefile.shx' % filename, fobj.getvalue()) fobj.close() fobj = cStringIO.StringIO() writer.saveDbf(fobj) zf.writestr('%s/shapefile.dbf' % filename, fobj.getvalue()) fobj.close() # Must close zip for all contents to be written zf.close() **Update** My initial code simply used the lat/lon co-ordinates I already had stored for the stations, but when the file was downloaded by the person requesting it they complained they had expected the points to be in UK Grid Easting/Northing format. This pointed me to look at the .prj files that are often included in a shapefile and give details of the co-ordinate system used. As the format is simple formatted text ([WKT](http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html)) I found the appropriate text for the formats I support and insert the appropriate text in shapefile.prj and include that with the download. The [.prj file](http://spatialreference.org/ref/epsg/27700/prj/) for UK Grid Easting/Northing. You can find the current version of this code being used on the [Variable Pitch site](http://www.variablepitch.co.uk/stations/selector/).