I have a need for a utility to translate shapefiles to SVG images, and I’m thinking of writing my own.  I’m aware of the one at carto.net.  I don’t like that it requires shp2pgsql, though; there are native Perl modules for parsing shapefiles so there should be no need for external executables with their own prerequisites.  Also, if I write my own I can put into it whatever features that I want… if they are within my capabilities.

If anyone stumbles across this post and has something that they’d like to see in such a utility, please leave a comment.

Update: Success!

Initial success came more easily than I anticipated, in only 90 lines of code using the Geo::Shapefile and SVG modules from CPAN.  Here is a map showing the Ozark Trail in Missouri that was generated from three separate shapefiles with a single run of the new program.  (The colors were modified after the fact with Inkscape.)  This exercised the handling of the three basic data types in shapefiles: points, polylines, and polygons.

Ozark Trail in Missouri; initial results from a new SVG generator

Ozark Trail in Missouri; initial results from a new SVG generator

To do list:

  • Accept source SRS specs on the command line, allowing multiple input files to have disparate coordinate systems.  DONE
  • Generate the results to an arbitrary SRS using Geo::Proj4.  That will be necessary to support the first item.  The initial test worked only because all 3 datasets use the same UTM zone as their coordinate system, and that same coordinate system was used as the basis for the rendering.  DONE
  • Support some specification of color and other rendering options, per source, on the command line.  (I anticipate that in most cases some post-processing with Inkscape will still be necessary, though.)  DONE
  • Optionally select subset of shapes by regex on arbitrary data fields.  DONEish
  • Support coloring of shapes by value of arbitrary data field.  DONE
  • Allow specification of a shapefile to use in scaling but not in rendering.  That would support independent production of layers to be later combined in Inkscape; they could all be scaled and translated according to the geometry of the base/largest layer to aid layering after the fact.  DONE
  • Include value from some data field in the SVG objects, either in the object ID or in another suitable field.
  • Specify a background color.
  • Take a name from a field to print in the output.  Getting labels to print in a legible manner that doesn’t interfere with the other items on a map is very problematical.  But if they’re already in the image as an output option, it’s easier to move them around in Inkscape than if you had to type them in by hand to boot.

Update 2:

The utility is coming along better that I anticipated, as testified to by the “DONE” tags in the to-do list.  After I tie up a few loose ends I’ll start another post to document what I have and how to use it.  I’ll post the code after I have a chance to tidy it up.

Final update:

As mentioned in the comments, I’ve posted this utility on GitHub.  All further development and documentation will be done there, but feel free to use this page for comments and suggestions.

One thing that I will note here is that the dependencies may not be quite as simple as I thought.  I import four Perl modules to use in the utlity, but they have some subdependencies that I wasn’t aware of.  I already had those on my system, so they weren’t flagged when I installed these other packages specifically for this project.  I’m installing a fresh testbed on a clean VM, and I’m starting to run into dependency hell.  I hate that.  I will try to carefully document at GitHub all the dependencies, once I have the testbed fully operational.

7 Responses to “Shapefile to SVG translator project”

  1. acocancer says:

    I’ve been looking for this tool. It seems promising. Thank you for sharing your work, mate.

  2. egb13 says:

    @Christian,

    I do extensive work on the output of this tool with Inkscape, the free SVG editor. That’s where I will create layers and add text, scale bars, legends, etc. As far as my limited understanding goes, layers are a construct of Inkscape built on the SVG standard, but they’re not part of the base SVG spec. I could be wrong there, but when you create a “plain SVG” file from Inkscape, it loses all the layer information.

    Objects from the same file will be grouped. There may be more grouping, too, though I can’t recall the details and could be mistaken.

    There is much that could be added or improved with this tool. One thing I have done that can be very useful is to support cropping the output of all output objects to a rectangle specified on the command line in the target coordinate system. Prior to that I’d have to either crop individual objects by hand in Inkscape, or define the extent of the view and put up with the overhead of having all these points and lines defined outside the view just wasting resources. I have not uploaded that version, though. Perhaps this conversation will spur me into doing that.

    Another outstanding issue is that the tool does not properly handle islands in polygons. That’s probably a problem with the Ogallala Aquifer map if rendered at high resolutions, though the way the data is “layered” in the file takes care of some of that — drawing a shallower region over a deeper region effectively creates that island.

    I think you’re misusing “group”. Maybe if I saw your use example. You could post it here or, if you prefer, email it to me at “egb13″ at this domain.

  3. Christian says:

    I came across your shptosvg tool. Very nice work! However I have the question how you managed to get the different shapefiles on different layers in the resulting svg. I have the tool running but it writes no layers in the svg file. Also in your example svg ogallala the svg objects that represent the different states contain the corresponding names. This also does not work for me. When I use the group flag for an attribute named NAME_1 I get the error: Couldn’t get file handle for group=NAME_1.shx. Any help would be appreciated.

  4. hgavin says:

    I’ve just used your script from github to generate SVGs from Tele Atlas shapefiles – it works great! Thanks very much for all your efforts.

  5. egb13 says:

    Okay, now I recall that git is what Linus wrote to replace that bitthingy.

    I’ve created a github account called “kbh3rd” with a repository called “shptosvg”. The perl script and an example shellscript that invokes it are the two files currently in the repository. Running “shptosvg.pl -h” gives a fairly lenghty usage summary.

    The perl script requires two modules from CPAN to run: Geo::Shapefile and SVG. No other external dependencies exist.

  6. egb13 says:

    It’s very close to ready for prime time. I just posted a map on Wikipedia that I made with it. I had to do very little tweaking after the fact. It will require some documentation about how to specify all those options on the command line; there’s quite a lot there, and I’ve found it easier to put it into a shell script where I can easily edit and tweak the parameters for successive runs until I’m happy with the result.

    I was considering creating a project on SourceForge. It would be my first, so I’m not bound to that site. I’m not familiar with GitHub. Why would I want to use that instead?

    BTW, the new map is at http://commons.wikimedia.org/wiki/File:Ogallala_saturated_thickness_1997-sattk97-v2.svg and is used in the Ogallala Aquifer article. (There, I’ve gone and blown my cover and linked this site to another of my online identities. Out of one closet and into another. ;)

  7. This would be extremely handy, would you mind throwing it up on GitHub, even un-tidied? I’m about ready to write my own Ruby version, but I’d rather hack yours.

Leave a Reply

Your comment will be silently rejected if it contains a link. It's fine if you can mention a relevant site in a way that a human will be able to recognize it, but not as a full-blown link. Do not enter anything containing "http:". Sorry, this is necessary to fight link spam.