UK Election Map – Voting Distribution

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

2005 - 2010 - 2015 UKElectionMap_votes

Legend
Legend

Now published on Wikipedia UK_General_Election_2010#Voting_distribution_per_constituency and UK General_Election_2015#Voting_distribution_per_constituency

The Plan

  1. Gather election data (number of votes per constituency per party & turnout percentage)
  2. Produce textures
    – One per constituency
    – Number of pixels per party (pixel colour) proportional to vote count
  3. Find a programmatically usable map of the UK and its constituencies
  4. Link constituencies in the data to the constituencies on the map
  5. 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.

2015 UK Election Map
2005 UK Election Map – Results by Constituency
2015 UK Election Map
2015 UK Election Map – Results by Constituency

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 POIthe 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>
ElectoralCommission-Excel_Screenshot
Screenshot of the election data spreadsheet format

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.

textures

 Source

Map Image source code in GIT

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;

Leave a Reply

Your email address will not be published. Required fields are marked *