Community Sourced Advice

We created this choropleth of home insurance values across various counties in the US. We parsed the Topojson file of US counties available on the internet and plotted shapes of counties using ruby gem for Gnuplot. The broad steps we followed to create the choropleth are:

Parsing topojson

The US counties and states topojson can be downloaded from the internet.

TopoJSON is a JSON format for encoding geographic data structures into a shared topology. The file format supports representing multiple geometry types.

An example of geometry for Valley county, MT which is a part of the US topojson file is given below.The ‘id’ in the dictionary is county FIPS code. (Here is a list of FIPS codes for US counties)

{"type":"Polygon","id":30105,"arcs":[[3,4,5,6,7,8]]}

A TopoJSON topology represents one or more geometries that share sequences of “arcs”. The value of an arc is an array of positions. Arcs can be referenced by a zero-based index. For example, index 0 refers to the first arc, index 1 refers to the second arc, and so on.

The positions in arc are delta-encoded. The first position of the arc is a normal position [x₁, y₁]. The second position [x₂, y₂] is encoded as [Δx₂, Δy₂], where x₂ = x₁ + Δx₂ and y₂= y₁ + Δy₂. The third position [x₃, y₃] is encoded as [Δx₃, Δy₃], where x₃ = x₂ + Δx₃ = x₁ + Δx₂ + Δx₃ and y₃ = y₂ + Δy₃ = y₁ + Δy₂+ Δy₃ and so on.

Additionally, there are some transforms which have to be applied to the positions in the arcs to get the absolute position which can be plotted and there will be negative arcs  also. The detailed topojson specification can be found here.

An example of an arc is given below

[[162416,583189],[236,-863],[95,-3199],[219,-1079],[-271,-1241]]

The ruby code to parse each arc and construct a hash of arc mapped to its absolute positions is given below

geohash = JSON.parse(File.read('us.json'))

txform = geohash['transform']

arcs = geohash['arcs']

absarcs=[]

arcs.each do |arc|

xli=[]

yli=[]

prex=0

prey=0

arc.each do |pt|

x=pt[0]+prex

y=pt[1]+prey

prex=x

prey=y

xli << (x*txform['scale'][0])+txform['translate'][0]

yli << (y*txform['scale'][1])+txform['translate'][1]

end

absarcs << [xli,yli]

end

Plotting the map using Gnuplot

Once the hash is built we can iterate the Topojson file, parse the geometry of each county and construct the array of positions which constitute the shape of each county. The array of strings can be plotted using Gnuplot.

The method we used to plot is given below

def plottoimage(data)

Gnuplot.open do |gp|

Gnuplot::Plot.new( gp ) do |plot|

plot.xrange "[-135:-50]"

plot.yrange "[20:52]"

plot.size "1,1"

plot.terminal "png"

plot.output File.expand_path(“choropleth.png”, __FILE__)

plot.data = data

end

end

end

When we parse counties and plot them without filling them, the output looks like this

Deciding color of the choropleth

The color with which each county should be represented can be calculated with this code

countydata = JSON.parse(File.read('county_data.json'))

insvals = []

countydata.each do |cid,cnty|

insvals << countydata[cid]["insval"].to_i

end

\$minins,\$maxins = insvals.min,insvals.max

\$colorlevels = 5

def calculate_color(countyval)

level = ((countyval-\$minins)*\$colorlevels/(\$maxins-\$minins)).ceil

color = 255-(level*255/\$colorlevels).ceil

hexcolor = color.to_s(16)

if hexcolor.length==1

hexcolor = '0'+hexcolor

end

'#0000'+hexcolor

end

The code basically takes the value of home insurance for each county and quantizes it to a value of blue color. The code can be made to return any color be tweaking it a little.

Once this is done one can generate the choropleth by iterating through the geometries and constructing a Gnuplot data objects and plotting them. The code below does this. ( The white areas in the choropleth are present because we chose to ignore a few counties with MultiPolygon Geometry. )

data = []

bdata = []

geohash['objects']['counties']['geometries'].each do |allarcs|

if allarcs['type']=='Polygon'

id = allarcs['id']

stx,sty=[],[]

allarcs['arcs'][0].each do |arc|

if arc>=0

pt = absarcs[arc]

stx=stx+pt[0]

sty=sty+pt[1]

else

pt = absarcs[arc.abs-1]

rx=pt[0].reverse

ry=pt[1].reverse

stx=stx+rx

sty=sty+ry

end

end

begin

data << Gnuplot::DataSet.new([stx,sty]) do |ds|

ds.with = "filledcurve fs solid 1.0 lc rgb '"+calculate_color(countydata[id.to_s]['insval'].to_i)+"'"

ds.notitle

end

data << Gnuplot::DataSet.new([stx,sty]) do |ds|

ds.with = "lines lc rgb '#000000'"

ds.notitle

end

rescue Exception => e

puts e,"some exceptio"

end

end

end

plottoimage(data)