Small Map of Continental US


The goal of this post is to create a small map of the United States which can be used to select different cities which appear on the map. This will be driving another visualization with data about the selected city. For data I’ll need the topojson file for the boundary of the United States, the lat/lon for the cities of interest, and the list of cities to show.

Getting a Geo file and Visualizing it

I’ll start by getting the shp file from the US Government for the nation or at other levels of granularity.

If you have topojson installed, you can do a simple transformation from SHP file to JSON file at the command line:

topojson -o us.json cb_2013_us_nation_20m.shp

You can then use this example, replacing the file “/mbostock/raw/4090846/us.json” with new file (ie “us.json”) and the object “topology.objects.land” with the appropriate name. If you used the nation file, the object will be “topology.objects.cb_2013_us_nation_20m”.

Making the map smaller

In order to make the map smaller and move it to a different location, I can introduce a projection object. In this case, I’ll use the “albersUSA” projection, and include a scale factor and a translation. Note that the translation function takes an array of coordinates. In the scale function, 1000 is no scale change and 200 shrinks the map.

var projection = d3.geo.albersUsa()
    .translate([100,100])
    .scale([200]);

var path = d3.geo.path().projection(projection);

Limit to Continental United States

However, I’d like to just focus on the continental United States. Therefore, I pulled the State-level data from the US Government website here. I also modified my topojson command in order to capture the name of each state.

topojson -o us.json --id-property NAME -- cb_2013_us_state_20m.shp 

The name of the state is coming from the .dbf file associated with the shp file. This .dbf file can be opened in Open Office or Microsoft Excel in order to identify the names of the columns to find the right property to pull out. More information on that here.

Now that I’ve identified the states in the json file, I can remove them before creating the path that draws the US as shown in the code below.

d3.json("us.json", function(error, topology) {
  topology.objects.cb_2013_us_state_20m.geometries = 
    topology.objects.cb_2013_us_state_20m.geometries.filter(
        function(d){if(["Alaska", "Hawaii", "Puerto Rico"].indexOf(d.id) == -1){return d}}
        )
  svg.append("path")
      .datum(topojson.feature(topology, topology.objects.cb_2013_us_state_20m))
      .attr("d", path);
});

Switching to “stroke: none” in the CSS part of the index.html file removes the lines between states.

Now we have a small map of the continental United States.

More information on maps from Mike Bostock here and here.

Adding a point for a city

Next goal is to add a point for a city. Using the tip from stackoverflow here, we can simply add a circle as follows:

 var citiesData = [{"city": "Chicago", location: {"lat": 41.87811, "long": -87.62980}}];

 svg.append("g")
    .attr("class", "cities")
  .selectAll("circle")
    .data(citiesData)
  .enter().append("circle")
    .attr("transform", function(d) {
        return "translate(" + projection([
            d.location.long,
            d.location.lat
            ]) + ")"
        })
    .attr("r", 3);

This is a useful website if you quickly want to get the latitude and longitude of a particular location.

Now we can just add a longer list of interesting cities.

var citiesData = [{"city": "Chicago", location: {"lat": 41.87811, "long": -87.62980}},
                  {"city": "New Orleans", location: {"lat": 29.95107 , "long": -90.07153}},
                  {"city": "Seattle", location: {"lat": 47.60621, "long": -122.33207}},
                  {"city": "Boston", location: {"lat":  42.35849, "long": -71.06010}}];

Of course, we can change the attributes of the circles using CSS. If we change the scale of the projection, it of course adjusts both the map and the city locations since both are based on the same projection object.

For reference, the relevant code is here.