Idea
Generate a map of the UK showing the general election voting distribution of 2005, 2010 and 2015. Existing election result maps did not really show the subtlety in voting, this is due to the first-past-the-post voting system (winner-takes-all).
Result

Now published on Wikipedia UK_General_Election_2010#Voting_distribution_per_constituency and UK General_Election_2015#Voting_distribution_per_constituency
The Plan
- Gather election data (number of votes per constituency per party & turnout percentage)
- Produce textures
– One per constituency
– Number of pixels per party (pixel colour) proportional to vote count - Find a programmatically usable map of the UK and its constituencies
- Link constituencies in the data to the constituencies on the map
- Alter map to apply this custom texture per constituency
Java Program
[pullquote]I spent a good while trying to ‘debug’ missing data for one constituency in Northern Ireland, which turned out to be a lake (Lough Neagh)[/pullquote]
The program does the following (see below for the source);
- Read in a map of the UK in SVG format
- For each election year
- Read in election data
- Look up party colours (no vote = BLACK)
- For each constituency
- Calculate a voting distribution
- Generate a ‘voting distribution’ image
- Link the constituencies in the image map with the generated images
- Write the updated SVG file
Input
Data
Year | Source |
2005 | Electoral Commission – Electoral Data |
2010 | Electoral Commission – Electoral Data |
2015 | Electoral Commission – Electoral Data (Currently provisional data – final data to be published in July) |
2015 | Guardian – Election Live Results |
Image
I used these Creative Commons images from Wikipedia as a base. The image format is SVG, which is an XML formatted vector graphics image. This allows for programatic access to the image description data.


Read in and Writing to a Map of the UK in SVG
As the SVG image format is XML, we can use the standard XML tools in Java, in this case DOM + XPath.
public static Document loadAsXmlDocument(File xmlFile) throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); return domFactory.newDocumentBuilder().parse(xmlFile.getAbsolutePath()); } public static void writeXmlDocumentToFile(Document doc, String fileName) throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(doc), new StreamResult( new File(fileName) )); }
XPath
XPath xpath = XPathFactory.newInstance().newXPath(); // Iterate over all constituency SVG paths using XPath to select the DOM nodes NodeList pathNodes = ((NodeList) xpath.compile("//path") .evaluate(doc, XPathConstants.NODESET)); // Regular DOM node Node firstPathNode = pathNodes.item(0);
Adding an XML Namespace
/** * Add XLink namespace to XML document * xmlns:xlink="http://www.w3.org/1999/xlink" */ private static void addXlinkNamespace(Document doc) { Element root = doc.getDocumentElement(); Attr attr = doc.createAttribute("xmlns:xlink"); attr.setValue("http://www.w3.org/1999/xlink"); root.setAttributeNodeNS(attr); }
Processing Excel Spreadsheet
Add Apache POI – the Java API for Microsoft Documents – to the Maven pom.xml:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.12</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.12</version> </dependency>

Example using Apache POI to iterate over the first cell of each row
Workbook workBook; try(InputStream inputStream = new FileInputStream(inputDataFile)){ workBook = WorkbookFactory.create(inputStream); } Sheet sheet = workBook.getSheetAt(0); for (Row row : sheet) { Cell cell = row.getCell(0); String stringValue = cell.getRichStringCellValue().getString(); }
2005 UK General Election
A number of constituency changes were made before 2010 – meaning that not all 2005 data could be applied to the 2015 UK constituency map. The 2005 UK constituency map did not have the required meta data to link the data to the SVG image, so I included a lookup file using the table data on the 2005 UK constituency map page.
Textures
Pixels represent the party colour and appear in frequency proportional to the votes.
Source
git clone https://github.com/eelcodevlieger/mapimage.git
Main class: com.knocksfornometer.mapimage.Main
Input Files: src\main\resources
Output Files: target\map
Java 8
Convert map key and output result to separate map.
Map<String, String> constituencyKeyNameToImageMap = images.keySet() .stream() .collect( Collectors.toMap( electionData.getConstituencyKeyGenerator()::toKey, Function.identity() ) );
JSON property file as String lookup map
I wanted to use some JSON as property files and looked for a Java JSON library. Gson turned out to be a joy to work with!
Add to Maven pom.xml:
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.3.1</version> </dependency>
Source JSON:
// http://en.wikipedia.org/wiki/Wikipedia:Index_of_United_Kingdom_political_parties_meta_attributes { 'CON': '#0087DC', 'LAB': '#DC241f', 'SNP': '#FFFF00', 'LD': '#FDBB30', 'GREEN': '#6AB023', 'UKIP': '#70147A', 'PC': '#008142', // Plaid Cymru 'SF': '#008800', // Sinn Fein 'DUP': '#D46A4C', // Democratic Unionist Party 'UUP': '#9999FF', // Ulster Unionist Party 'SDLP': '#99FF66', // Social Democratic and Labour Party 'TUSC': '#EC008C', // Trade Unionist and Socialist Coalition 'BNP': '#00008B', // British National Party 'CPA': '#AA00AA', // Christian Peoples Alliance 'CSA': '#F84651', // Cannabis is Safer than Alcohol 'Eng Dem': '#915F6D', // English Democrats 'IND': '#DDDDDD' }
Load String to String Map from a JSON file:
public static Map<String, String> loadStringMapFromJsonFile(String filePath) throws IOException { Gson gson = new GsonBuilder().create(); Type type = new TypeToken<Map<String, String>>(){}.getType(); try(Reader reader = new FileReader(filePath)){ return gson.fromJson(reader, type); } }
I also used it to parse the data from the Guardian website. You create a plain Java object (POJO) with a default constructor, that represents the data. In this case I had to specify a date format, as the source JSON used a format different from the default.
public static <T> T fromJson(Reader reader, Class<T> classOfT, String dateFormat) throws IOException { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setDateFormat(dateFormat); Gson gson = gsonBuilder.create(); T jsonDataObject; try{ jsonDataObject = gson.fromJson(reader, classOfT); }finally{ if(reader != null) reader.close(); } return jsonDataObject; }
If a JSON field name starts with a number (invalid for Java fields), you can add an annotation to link the fields, like:
@SerializedName("2015") public Year year;