A Script to Make Pretty Political Google Maps
A while back I wrote I script for converting and styling KML files from ERSI Shapefiles, like you might download or export form a program like Quantum GIS. It requires you have the web programming language PHP 5 installed, along with the ogr2ogr command.
‘ ?>
View Larger Map ‘ ?>
This program extensively uses the PHP/DOM model, to read and write the XML file. I am not an expert programmer — it’s a hobby, but I am very happy with the results. You might consider using the LATFOR data and Census TIGER/Line for this if your a New York State resident.
#!/usr/bin/php -q <?php // POLITICAL STYLING FOR KML // Converts a Shapefile with Election Results in Percentage // // Input: // File_Title = Title for KML Name Field (as Seen in Google Maps) // District_Name = Field with District Name In It // Percent_as_Decimal = Election Result with Percent. // 0.00 - 0.49 = Shade of Red // 0.50 = White // 0.50 - 1.00 = Blue // Shapefile_Name = Path to Shapefile // // Output: // Google Maps KML File, Nicely Styled if (!isset($argv[4])) { echo "usage: php politicalKML.php [File_Title] [District_Name] [Percent_as_Decimal] [Shapefile_Name]\n"; exit; } // required fields $fileTitle = $argv[1]; $nameField = $argv[2]; $percentField = $argv[3]; // filename $filename = $argv[4]; $KMLfileName = substr($filename,0,-4).'.kml'; // convert shapefile to kml using ogr2ogr system("ogr2ogr -f \"KML\" -sql \"SELECT * FROM ". substr($filename,0,-4)." ORDER BY $fileTitle ASC\" $KMLfileName $filename -dsco NameField=$nameField -dsco DescriptionField=$percentField"); // load our new kml file $doc = new DOMDocument(); $doc->load($KMLfileName); // first let's replace the name field with a nicer one $oldnode = $doc->getElementsByTagName('name')->item(0); $node = $doc->createElement('name', $fileTitle); $doc->getElementsByTagName('Folder')->item(0)->replaceChild($node, $oldnode); // delete schema field to save space $oldnode = $doc->getElementsByTagName('Schema')->item(0); $doc->getElementsByTagName('Folder')->item(0)->removeChild($oldnode); // load each placemark, search for maximum — used for making color judgements foreach ($doc->getElementsByTagName('SimpleData') as $data) { if( $data->getAttribute('name') == $percentField) { $max[] = abs(substr($data->nodeValue,0)-0.5); } } // maximum in the political race sort($max); $max = array_pop($max); // calcuate multiplier for each race $multiple = 255/$max; // load each placemark, then set styling and percentage description foreach ($doc->getElementsByTagName('Placemark') as $placemark) { foreach ($placemark->getElementsByTagName('SimpleData') as $data) { if( $data->getAttribute('name') == $percentField) { $value = $data->nodeValue; $color = substr($value,0); } } // decide if we want to do this blue or red, and then calculate // the amount of color versus white // republican leaning if ($color <= 0.5) { $colorStr = sprintf('%02x', 255-floor(abs($color-0.5)*$multiple)); $colorStr = "a0{$colorStr}{$colorStr}ff"; } // democratic leaning if ($color > 0.5) { $colorStr = sprintf('%02x', 255-floor(abs($color-0.5)*$multiple)); $colorStr = "a0ff{$colorStr}{$colorStr}"; } if ($color == 0) { $colorStr = '00ffffff'; } // stylize the node based on color $node = $doc->createElement('Style'); $linestyle = $doc->createElement('LineStyle'); $node->appendChild($linestyle); $linestyle->appendChild($doc->createElement('width', 0.1)); $linestyle->appendChild($doc->createElement('color', 'ffffffff')); $polystyle = $doc->createElement('PolyStyle'); $node->appendChild($polystyle); $polystyle->appendChild($doc->createElement('color', $colorStr)); $oldnode = $placemark->getElementsByTagName('Style')->item(0); $placemark->replaceChild($node, $oldnode); // delete extended data to save KML space $data = $placemark->getElementsByTagName('ExtendedData')->item(0); $placemark->removeChild($data); // update the description $oldnode = $placemark->getElementsByTagName('description')->item(0); $node = $doc->createElement('description', 'Recieved '.($color*100).'% of the vote.'); $placemark->replaceChild($node, $oldnode); } // finally write to the file $doc->save($KMLfileName); // calculate size in MB $filesize = filesize($KMLfileName)/1024/1024; if ( $filesize < 10) { $zipCommand = "zip ".substr($KMLfileName,0,-4).".kmz $KMLfileName"; system($zipCommand); $kmzfilesize = filesize(substr($KMLfileName,0,-4).".kmz")/1024/1024; echo "KMZ is " .sprintf('%01.2f', $kmzfilesize)." MB, while the KML file is ".sprintf('%01.2f',$filesize)." MB.\n"; } else { echo "Woah Horsey! The produced file is greater then 10 MB, at a size of ".sprintf('%01.2f',$filesize)." MB uncompressed. You need to simply your polygons before proceeding, otherwise Google Maps won't be able to read it. \n"; } >