Matthew Henderson

college station, tx

Mapping shapefile polygons

May 10, 2014

Static image of map showing warning polygons

Above is a static image captured of a map produced using code in the exercise below, which displays warning polygons. The image above also showed locations of tweets within that same thirty minute timeframe, which mentioned certain weather terms. The map produced in this exercise will only deal with displaying the warnings, and will be interactive.


The Goal

The goal of this exercise is to produce an embedded, interactive map on a web page, which will display the latest warnings issued by the National Weather Service. These warnings are updated by the NWS every minute, 24 hours a day, 365 days a year. You can read more about these files here.

There are two parts needed to produce the map. First, the web page itself. Second, we need a script which will download the latest files (issued in ESRI shapefile format), extract any existing polygons describing the areas currently under an issued warning, and produce a small javascript file which will then display them on a map.

For this example, we will be using Ruby, HTML and Javascript.

How it Works

Running the ruby script will:

  1. Download the latest warnings issued by the National Weather Service.
  2. Extract any warning polygons of the type you specify. There are four available: SVR (Severe Thunderstorm), TOR (Tornado), FFW (Flash Flood), and SMW (Special Marine Warnings).
  3. Create a file called polygons.js, which will be used to display them on a map embedded in a web page.

The web page will display a map – in this example centered on the continental US – and show any warnings that might exist at the time the ruby script was run to generate them.

In the end, an automated process could be set up so that the ruby script was executed every n minutes (ie. with launchd on a Mac), and the map would be periodically updated with the latest weather information.

Prerequisites

There are a few things you will need to have installed on your system before we can begin. The instructions for this are assuming a user on OS X.

First, you should install GEOS(Geometry Engine, Open Source). If you have brew installed on your system, this is a simple process:

brew install GEOS 

Next, you will want to install a few necessary gems if they are not already part your system. You should begin with rubyzip, which will allow us to work with our downloaded zip file.

gem install rubyzip

Next, you will want to install the two gems which will allow us to extract the polygon information we need for displaying on the web. You will want to specify where GEOS was installed. The following examples are for our installation with brew.

gem install rgeo -- --with-geos-dir=/usr/local/lib
gem install rgeo-shapefile -- --with-geos-dir=/usr/local/lib

Note: if your geos is installed in another location, you can check where by using:

sudo find / -name 'libgeos*'

Note: depending on your setup, you might be required to sudo when installing the gems.

The Code to Process Current Warnings

Now, below is the Ruby code for the script which will be used to build the polygon.js file to display any current warnings on our map.

require 'rubygems'
require 'open-uri'
require 'zip'
require 'rgeo'
require 'rgeo-shapefile'

def getcurrentwarnings(warningtype)
  tempfile = Tempfile.new(['tempfile','.zip'])
  tempfile.binmode
  tempfile.write(open("http://www.nws.noaa.gov/regsci/gis/shapefiles/current_warnings.zip").read)  
  tempfile.close
 
  Zip::File.open(tempfile.path) do |zip_file|
    zip_file.each do |entry|
      fname = entry.name
      if fname.include?(warningtype)
        ## passing true overwrites existing files
        ## if same named file already exists
        entry.extract("#{@targetshapefiles}#{fname}"){ true }
      end    
    end
  end
end

def readwarningpolygons(warningtype)
  RGeo::Shapefile::Reader.open("#{@targetshapefiles}#{warningtype}.shp") do |file|    
    if file.num_records.to_i > 0 
      puts "File contains #{file.num_records} records."
      file.each do |record|
        record.geometry.each do |polygon|          
          File.open(@targetploygonfile, 'a') {|f| f.write("polygon = L.polygon([\n") }      
          puts polygon.as_text
          polygon.exterior_ring.points.each do |point|
            line = "[#{point.y}, #{point.x}],\n"
            File.open(@targetploygonfile, 'a') {|f| f.write(line) }            
          end
          line = "],{ color: 'red', fillColor: '#05f', fillOpacity: 0.9 }).addTo(map);\n\n"
          File.open(@targetploygonfile, 'a') {|f| f.write(line) }                                 
        end
      end
      file.rewind
    end
  end
end

def initpolyfile()
  File.open(@targetploygonfile, 'w') {|f| f.write("function drawPolygons() { \n\t var polygon \n") }  
end

def finalizepolyfile()
  File.open(@targetploygonfile, 'a') {|f| f.write("\n\n}") }
end

## ***************************************
## EXECUTE *******************************
## ***************************************

## ********* SET THREE THINGS BELOW ***************
## Set the target locations for saving the files
@targetshapefiles = "/path/to/your/dir/"
@targetploygonfile = "/path/to/your/dir/polygons.js"

## Set the type of warnings you want to display:
## SVR (Severe Thunderstorm); TOR (Tornado); 
## FFW (Flash Flood); SMW (Special Marine Warnings)
warningtype = "SVR"
## ********* SET THREE THINGS ABOVE ***************

getcurrentwarnings(warningtype)
initpolyfile()
readwarningpolygons(warningtype)
finalizepolyfile()

Near the bottom of the code, you will find a section noted where there are three items you must set before you run it:

  1. @targetshapefiles - the location where you want to unzip the warning files
  2. @targetploygonfile - the location of your web page where the javascript file should be saved
  3. warningtype – choose the type of warnings you are interested in displaying

The Code to Display the Map

To display the map, we will be using tiles from Open Street Maps, and a Javascript library called leaflet.

Download leaflet from their website here: http://leafletjs.com/download.html

Here is the code for the HTML page. You may have to alter the references to resources as needed.

<!DOCTYPE html>
	<html lang="en">
	<head>
	<meta charset="utf-8"/>
	<title>Live Weather Warnings</title>
	<link rel="stylesheet" type="text/css" href="leaflet.css" />
	<script src="leaflet.js"></script>
	<script src="polygons.js"></script>

	<script>
	var map;
	function initmap() {
		//set up the map
		map = new L.Map('map');
		var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
		var osmAttrib='Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
		var osm = new L.TileLayer(osmUrl, {minZoom: 4, maxZoom: 22, attribution: osmAttrib});								
		map.setView(new L.LatLng(37.5,-95.35),5	); // center map over US
		map.addLayer(osm);

		drawPolygons();
	}
	</script>

	<style>
		body { background: #444;}
		#map { width:1000px; height:670px; margin: 20px auto;}
	</style>
	</head>

	<body onload="initmap();">
	    <div id="map"></div>
	</body>
	</html>

That’s it. You’re now ready to display your map. Enjoy!

Philippines 2019 Aug 19, 2019

June 2019 Jun 01, 2019

May 2019 May 01, 2019

April 2019 Apr 01, 2019

March 2019 Mar 01, 2019

Team Us Feb 26, 2019

February 2019 Feb 01, 2019

December 2018 Dec 19, 2018

July 2018 Jul 01, 2018

June 2018 Jun 01, 2018

May 2018 May 01, 2018

April 2018 Apr 01, 2018

December 2017 Dec 03, 2017

November 2017 Nov 05, 2017

October 2017 Oct 01, 2017

Bandina Week May 31, 2017

Book Review: The Plot to Kill God Apr 27, 2016

John (10 song series) Apr 27, 2016

Song for Songs Dec 31, 2015

Falling Away Aug 26, 2015

Easy README Files on Your Mac Jan 28, 2015

Word Clouds from the Gospels (and Acts) Sep 30, 2014

Lord of Your Life? Sep 21, 2014

Search the NY Times Archive Jul 24, 2014

The Farthest Peak Jul 08, 2014

Red River (When You See Me) Jun 26, 2014

Mapping shapefile polygons May 10, 2014

Using git to publish a website Sep 05, 2013

Roads We Don't Choose Aug 30, 2013

Killswitch/Mute Pedal Jul 09, 2013

Hold Out Jun 23, 2013

Muddle-headed Tyranny Jun 11, 2013

Arduino Arcade Controller May 13, 2013

A Place We Have Not Met May 04, 2013

Remember the Little Things Mar 27, 2013