Developers can get a wealth of political information from our Cicero API, including address-based geocoding and coordinate-matching to congressional and other legislative districts, Census blocks and watersheds, legislator contact information, and election events from around the world. However, one of my favorite features of Cicero, the map call, is actually one of our least used.
In this blog post, I’ll explain how to:
- secure your Cicero account info, set up PHP cURL, and get a token from Cicero
- get information on a legislative district that represents a particular address
- get a boundary image of that district
- and display that image in a Google Maps widget.
All the example files I refer to in this post are available in the cicero-examples GitHub repository.
Finally, in a few weeks, I’ll be writing a second blog post that expands on the simple example code I use in this one, by employing JQuery and extra features of the Google Maps API to make your district maps even more interactive. Stay tuned!
Step 1: Secure your Cicero Account Details
To get a token from Cicero, you’ll need to pass your username and password to the API via an HTTP POST request. We’re going to use an extension PHP has called cURL to do that in step 2. First we need to secure your account info. While visitors can’t see PHP, in some circumstances (if logging is on by mistake, etc) they could find out your Cicero details if you don’t put some protection in place. I recommend making a separate PHP file with just your Cicero username and password set to constants. Put that file in a folder outside of your website’s main web-accessible directory and then use PHP’s include() or require() statements to bring that separate file into your main PHP code. You can direct PHP to look for include files in other directories either through your php.ini file’s include path or simply specifying a relative path in your include statement. If you don’t have access to a protected directory outside your main web-accessible one, if you’re running the Apache webserver, you can protect include files via clever use of the .htaccess file (hint: it’s the second post in that article).
Here (github) is my include.php file:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/include.php”]
Notice the third variable I put into this file, $search_loc. It doesn’t actually have anything to do with your Cicero account details. This will be the address we will pull the elected official and map info from in this example. We’ll use Azavea’s Philadelphia office for this post, but you can experiment later and set this to a different address. More data (state, country and zip code, as well as city and street) will ensure a greater chance of successful geocoding and could make response time faster. Obviously, in a more complete web application, you might be getting this address from a user-submitted form rather than hardcoding it like we are for our example.
Step 2: Setup PHP cURL
Moving along! We said earlier we’d be using PHP’s cURL extension to make POST and GET requests to Cicero. There are other ways to do this, but cURL is widely used and fairly easy – depending on your server. Sometimes, it’s not enabled by default in certain PHP installations. You can find out if you have it installed by making and navigating to a PHP page with the phpinfo() function:
<?php phpinfo(); ?>
Search the page (Ctrl+F works well) for “curl” info. If it’s there, congrats! If not, and you have access to your php.ini file, search for something like the following line:
If your line has a semicolon in front of it like above (that’s PHP’s line comment symbol), go ahead and delete just the ; to enable the extension. If you can’t find the line, just add it to the file without the semicolon. If you’re using Linux or Mac OS X, the extension will be named php_curl.so instead of .dll – .dll is for Windows.
Next, we’ll need to write a function to use cURL to send data up to Cicero and process the responses we get back. I’ve shamlessly stolen the function in my get_cicero_info.php file (on github) from my colleague Joe Tricarico’s excellent Hello World – PHP example in the Cicero documentation:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “4” end_line = “17” ]
All get_response() does is take any URL, and optionally any data to be used in a POST request ($postfields), initializes cURL, makes the appropriate POST or GET request to the url specified, reads the resulting response into the variable named $json, and then runs $json through a PHP library function called json_decode to give us a variable with data we can manipulate and use in PHP.
Step 3: Get a Cicero Token
OK, we finally get to do something with the API in this step! Also in my get_cicero_info.php file, I’ve written another function, get_cicero_token(), to do exactly that:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “18” end_line = “36” ]
This function I also based off parts of Joe’s Hello World – PHP example, with a few modifications. We take the $username and $password from our previously-included separate file, and use PHP’s urlencode() function to properly encode them before we send them over HTTP to Cicero. (Some characters like commas, apostrophes, and the like can cause problems if they were sent without first URL encoding them.) Then, we use our get_response() function written earlier, give it the url to get a new token, and the username and password as “postfields”, joined by an ampersand (&) just like you might see in a URL. (PHP string interpolation works easily enough we can just put $username and $password into the postfields string – great!). Now that we (hopefully) have a response, we check that the “success” attribute of the response object that Cicero gave us is True. If it’s not, we’ll exit the PHP program because we can’t do anything without a token. Your code may have a bug, or your Internet connection may be down, or Cicero may be temporarily unavailable. If we did get a successful response, this function makes a $token_info array with both our token value and Cicero user ID. We’ll use this array for other API calls.
Step 4: Query Cicero for Officials
This is where it gets exciting. Now we’ll write a PHP function to query Cicero for elected official data, and get what we need to later request a district boundary image from Cicero in step 5 and build a Google Maps widget in step 6.
Let’s take a look at my get_cicero_info.php file’s get_map_info_by_location_and_district_type() function below (boy, that’s a mouthful):
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “37” end_line = “62” ]
This function takes the $token_info array our last function made, as well as the $search_loc that we hardcoded in our include.php file, and $district_type (new) – which I’ve set in this example to STATE_LOWER, one of the many district types available in Cicero. If you wanted something else (like your US House district), just use the appropriate Cicero district type name in place of what I’ve used. Some addresses may belong to multiple districts of a certain district type (the LOCAL type is a good example, when a city might have several at-large seats like a Mayor and Controller, etc), so even when filtering this way you may need to put in extra program logic to find exactly the right one you want. When it returns more than one, Cicero orders officials by last name alphabetically.
Once again, we URL encode the data we’ll pass to Cicero (useful in particular for the $search_loc address, as it converts spaces to +’s and other appropriate URL formatting changes). Our function then builds a $query_string from our information, and specifies that we want JSON output (with “format=json”). Note that since $token_info is an array, we have to add curly braces to our string interpolation syntax here to get at our token and user ID elements:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “40” end_line = “44” ]
We then append our $query_string to the main URL for Cicero’s official call, and get a response:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “44” end_line = “45” ]
With Cicero calls that use geocoding, like official, a list of “candidates” objects will be part of the response. Sometimes a given address will geocode to multiple lat/long points – the official information for each of these points will be a candidate object in the list. Usually, only one candidate object is returned though, so we assume that in this example. In our code, there’s a check to make sure that Cicero was able to find at least one geocoded candidate location and get the officials from the address you gave it:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “46” end_line = “50” ]
Since $candidates is a list, even if it only contains one object like our example right now, we have to reference the 0th element in the rest of our code.
We want to get the geocoded point Cicero produced for our address, because we’ll use this later in the Google Maps widget as the center of the map. To do this, we’ll get the x and y values of the 0th candidate Cicero gave us, and make a new array ($lat_long_of_search_loc) that contains them:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “51” end_line = “54” ]
This function also gets our crucial $unique_district_id for the district we want to display on the map, too. Each district in Cicero has a unique district ID (also called a “primary key”), and while you can request a district map with other information, after you’ve gotten an official object this is the easiest and most fool-proof:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “55” end_line = “56” ]
Finally, we’ll stuff our address’s lat/long and the unique district ID into a new PHP array, $map_info, so we can use them in our final PHP function:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “57” end_line = “60” ]
So we have a latitude and longitude to center a map on, and we have a unique district ID from Cicero. We’re almost done with our PHP server-side programming.
Let’s take a look at the get_cicero_info.php file‘s get_district_map() function, and the last few lines in the file:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/get_cicero_info.php” start_line = “61” end_line = “82” ]
What’s going on here? This function takes our $token_info array again, along with our new $map_info array. We build a new $query_string and $map_url for the map call this time. There are a few parameters in this one that we haven’t seen until now:
- include_image_data – This tells Cicero to send along the base64 image data as well as a link to a PNG image hosted on our servers. This is optional, but has advantages over using the hosted image URL which is why we use it in this example. If you take a look at the JSON response, you’ll see the base64 data as a huge stream of seemingly senseless characters – it’s how we can represent an image in text form. You can actually put this base64 stream in the src= part of the HTML image tag, and browsers will render it as an image. Pretty cool, huh? If you use the URL given to the district map image given in Cicero’s response instead, be warned that image is only guaranteed to stay on our servers for 7 days. The advantage to using base64 data is that we will already have it handy when it comes time to display the map, so we won’t need to download the PNG then which saves us time and bandwidth.
- srs=4326 – If you’re not a geographer, you might not know what a Spatial Reference System (SRS) is, nor would you know what EPSG codes or other SRIDs are. But you don’t really need to! Just know for now that Google Maps takes latitude and longitude data, which is EPSG code 4326, and the one we’ll be using. If you don’t set this, Cicero defaults to a map projection system called “Web Mercator,” which might play nice with other mapping frameworks, but not Google Maps. (Even though Google Maps is based on Web Mercator, the Image Overlay function we’ll be using assumes regular latitude and longitude.)
- width=500&height=500 – These specify the dimensions of the map image Cicero will return, and are only two of a slew of other map style options – including colors! The max is 3300 pixels, but 500 or 1000 loads faster and the visual difference is negligible except when a user zooms in closely. In my upcoming second blog post, we’ll discuss dynamically getting district overlay images of different sizes depending on the user’s browser window size and as a user zooms into the map, which will maintain image quality much better. For now though, we’ll keep it simple and hardcode 500 pixels, and limit the maximum zoom level in Google Maps in step 6.
Our function gets a response from Cicero, verifies that a map actually was returned in the response (exits the script if not), and then gets the data for the map object (including the image URL, and the lat/long data to properly position it on our map widget) and sets that to the $district_map_image_data array.
Step 6: To the Browser!
I’ve used Google’s Ground Overlay tutorial and code sample file as a base for my display_gmaps_overlay.php file. I’ll highlight important parts here, but you should really take a look yourself and follow along.
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “0” end_line = “3” ]
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “16” end_line = “19” ]
Following Google’s code sample, we next need to create a map object centered at our address’s geocoded latitude/longitude. Because map_data_from_php is JSON, we can navigate the fields using simple dot syntax:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “19” end_line = “22” ]
Next comes a tricky part: defining the bounds of our district image – the lat/long of where it starts and ends. If we didn’t define these, Google Maps would have no idea where to put our image. If we define them incorrectly, Google Maps either won’t show our district image at all or it will be horribly contorted:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “22” end_line = “27” ]
Let’s step through this, because the ordering of your arguments is very important here. There are two Google Maps API calls used – google.maps.LatLngBounds(), and google.maps.LatLng(). The first takes two (lat,long) pairs as arguments and makes what we geographers call a “bounding box”. Assuming North is “up”, Google specifies these pairs must be given in the order of southwest (“bottom left”) first, northeast (“top right”) second. IE, LatLngBounds(southwest point, northeast point). For example, if you wanted to draw a bounding box over most of the state of New Jersey, you’d put Philadelphia’s lat/long point first, and New York City’s lat/long point second. The second API call, LatLng(), makes *one* (lat,long) pair given two decimal numbers.
Let’s look at the extent object (note, this is not in the example files):
Like every location in the lower 48 contiguous United States, Philadelphia has a positive, northern latitude and a negative, western longitude. The decimal degree numbers in the extent object above may be confusing if you’re more familiar with the degrees/minutes/seconds way of measuring latitude and longitude (ie, 39°N 59′ 59″), but they represent the same thing and are easily converted. Computation is much easier with decimal degrees, which is why Google Maps and Cicero use that format.
The following can be counter-intuitive to many people: Latitude is Y, Longitude is X. That’s not the way the lines seem to appear on a globe, but it’s true if you think about which axis each is measuring.
So, Google Maps is looking for LatLngBounds(southwest point, northeast point), in that order. Use the extent values Cicero gave you to construct those points: the Southwesterly vertex of the map image will use the pairing (y_min, x_min), and the Northeasterly vertex will use the point (y_max, x_max). Doesn’t make sense? Remember: since the X/longitude values are negative in the Western hemisphere, x_min=-75.16… is actually further West than x_max=-75.09….
Next we need to set some map options and initialize the map, which I’ve kept mostly the same as in Google’s code sample. Set our “azavea” var to the center, and set the maxZoom at 16. Zooming in any higher would make our simple 500 pixel image overlay fuzzy. Note that we’ll improve this later in my next blog:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “28” end_line = “36” ]
If you want a marker at your address, create it:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “36” end_line = “42” ]
Finally, we’ll make our “districtoverlay” variable using the image URL given to us by Cicero, the imageBounds we defined above (and I explained at length), and add the overlay to the map:
[github file = “/andrewbt/cicero-examples/blob/master/Maps_call_blog/display_gmaps_overlay.php” start_line = “42” end_line = “47” ]
That just about covers it! If you put these github files on a server with PHP, and navigate to display_gmaps_overlay.php using a browser, you should see an interactive Google map widget with your district image load! Congratulations! If you’re integrating this into a larger web application, perhaps this page could pop up when a representative’s name is clicked, or the map size could be shrunk down and otherwise embedded into the page. Either way, now you’ll be able to give your politically-minded website viewers some interactive, geographic context as to who their elected officials are.