Loading and drawing maps with Ruby

Loading geographic map data and drawing maps is pretty easy to do with two Ruby tools – ruby-shapelib (to load the map data) and RImageMagick (to create the drawings).

I didn’t see any tutorials or sample code, so I’m posting this sample as is – it will draw every shape part of every shape in a given shape file. Note this code does not perform any geographic projections.

require 'rubygems'
require 'RMagick'
require 'rvg/rvg'
require 'shapelib'
include ShapeLib
include Magick

USSTATES_SHAPEFILE="/Users/jkk/projects/shapelib/statesp020/statesp020.shp"
OUTFILE="/Users/jkk/projects/shapelib/test.png"

def drawshape shape, canvas
#each shape can have multiple shape parts...
#iterate over each shape part in this shape -
0.upto(shape.part_start.length-1) do |index|
part_begin = shape.part_start[index]
unless shape.part_start[index+1].nil? then
part_end = shape.part_start[index+1]-1
else
part_end=-1
end
#NOTE we're assuming all the parts are polygons for now...
#draw a polygon with the current subset of the xvals and yvals point arrays
canvas.polygon(shape.xvals.slice(part_begin..part_end),shape.yvals.slice(part_begin..part_end)).styles(:fill =>"green",:stroke=>"black",:stroke_width=>0.01)
end
end

#create a viewbox with lat/long coordinate space in the correct range
def create_canvas rvg, shapefile
width = shapefile.maxbound[0] -shapefile.minbound[0]
height = shapefile.maxbound[1] -shapefile.minbound[1]
#puts "viewport #{shapefile.minbound[0]},#{shapefile.minbound[1]} - width= #{width} height= #{height}"
#invert the y axis so "up" is bigger and map the coordinate space to the shape's bounding box
canvas = rvg.translate(0,rvg.height).scale(1,-1).viewbox(shapefile.minbound[0],shapefile.minbound[1],width,height).preserve_aspect_ratio('xMinYMin', 'meet')
end


shapefile = ShapeFile.open(USSTATES_SHAPEFILE,"rb")
#create a new RVG object
rvg = RVG.new(1000,100)
rvg.background_fill='white'
canvas = create_canvas rvg, shapefile
shapefile.each { |shape| drawshape(shape,canvas) }
shapefile.close

rvg.draw.write(OUTFILE)




I’m using the US State boundary file from the national atlas website.

One thought on “Loading and drawing maps with Ruby”

Leave a Reply

Your email address will not be published.