6

I would like to divide a map of Germany vertically by the electoral results of 2013:

> VoteGermany2013
    Party Result
1 CDU/CSU   49.4
2     SPD   30.5
3   LINKE   10.2
4  GRUENE   10.0

What I'm looking for is very simple: a map divided like a one-bar graph, with 49.4% of the lenght for CDU/CSU, 30.5% for SPD and so on. It would be like a single bar divided in parts, but with the form of a country.

For the map, I'm using:

library(maps)
library(mapdata)
map("worldHires","Germany")
Thomas
  • 43,637
  • 12
  • 109
  • 140
Naomi Peer
  • 367
  • 2
  • 10

1 Answers1

10

Create a bar plot with rect, overlay the country border, and trim back the rectangles around the border.

enter image description here

library('maps')
library('mapdata')

## fill = TRUE !important
dat <- map("worldHires", "Germany", fill = TRUE)

## set up plotting window
p <- par('usr')
plot.new()
plot.window(p[1:2], p[3:4])

## make some data and calculate some useful things
pcts <- prop.table(table(sample(1:3, 20, replace = TRUE)))
xx <- range(dat$x, na.rm = TRUE)
yy <- range(dat$y, na.rm = TRUE)
zz <- diff(yy) * pcts

cols <- palette(rainbow(length(zz)))
cols <- c('red','black','gold')

## draw and color rectangles, you can do this many other ways
dy <- 0
for (ii in seq_along(zz)) {
  rect(p[1], yy[1] + dy,
       p[2], yy[1] + (dy <- sum(zz[1:ii])),
       col = cols[ii], border = NA)
}

map('worldHires', 'Germany', col = 'black', add = TRUE)

## trim around borders
xb <- xx + c(-1, 1)
yb <- yy + c(-1, 1)
polypath(c(dat$x, NA, c(xb, rev(xb))), c(dat$y, NA, rep(yb, each = 2)),
         col = 'white', rule = 'evenodd')

polypath part inspired by How can I color the ocean blue in a map of the US?

Edit: function for easier use, added labels

sample data

## examples
pcts <- prop.table(table(sample(1:3, 20, replace = TRUE)))


voteGermany2013 <- read.table(header = TRUE, text = "Party Result
1 CDU/CSU   49.4
2     SPD   30.5
3   LINKE   10.2
4  GRUENE   10.0")

function:

evelyne <- function(x, region, labels, cols) {
  op <- par(no.readonly = TRUE)
  on.exit(par(op))

  require('maps')
  require('mapdata')

  ## fill = TRUE !important
  dat <- map("worldHires", region, fill = TRUE)

  ## set up plotting window
  p <- par('usr')
  plot.new()
  plot.window(p[1:2], p[3:4])

  ## calculate some useful things
  xx <- range(dat$x, na.rm = TRUE)
  yy <- range(dat$y, na.rm = TRUE)
  zz <- diff(yy) * x

  if (missing(cols))
    cols <- palette(rainbow(length(x)))

  ## draw and color rectangles
  dyy <- rep(0, length(zz))
  dy <- 0
  for (ii in seq_along(zz)) {
    rect(p[1], yy[1] + dy, p[2], yy[1] + (dy <- sum(zz[1:ii])),
         col = cols[ii], border = NA)
    ## label y-coordinates
    dyy[ii] <- yy[1] + c(0, cumsum(zz))[ii] + zz[ii] / 2
  }

  map('worldHires', region, col = 'black', add = TRUE)

  ## trim around borders
  xb <- xx + c(-1,1)
  yb <- yy + c(-1,1)
  polypath(c(dat$x, NA, c(xb, rev(xb))), c(dat$y, NA, rep(yb, each = 2)),
           col = 'white', rule = 'evenodd')

  if (!missing(labels))
    text(max(xx), dyy, labels = labels, pos = 4, xpd = NA)
}

ex:

evelyne(pcts, 'Germany', cols = c('red','black','gold'))

enter image description here

with(voteGermany2013,
     evelyne(Result / 100, 'Germany', labels = sprintf('%s (%s%%)', Party, Result)))

enter image description here

Community
  • 1
  • 1
rawr
  • 20,481
  • 4
  • 44
  • 78
  • Thank you very much for this, it really helps. As I'm very new to R, I'm not sure where I can enter my data though... – Naomi Peer Mar 05 '15 at 19:15
  • 1
    @Evelyne1991 just replace `pcts` with yours: `pcts <- VoteGermany2013$Result / 100` – rawr Mar 05 '15 at 20:59
  • 1
    @Evelyne1991 added a function to make it (hopefully) easier to use and also label the sections if you want – rawr Mar 05 '15 at 21:53
  • 1
    I just *have* to comment that this is a *very poor* visualisation of the data, since the coloured areas misrepresent the underlying numbers. It is possible to divide a polygon vertically such that the areas are proportional, but its a bit trickier than just dividing linearly. – Spacedman Mar 06 '15 at 11:47
  • @Spacedman I'm looking at other data that I could use that will be better for that type of visualisation, but thanks for the notice :) – Naomi Peer Mar 06 '15 at 15:03
  • @rawr you can do it by constructing a rectangle that envelopes the lower part of the region, then using gIntersection and gArea from package:rgeos to work out how high the rectangle needs to be to cover 33%, say, of the area. Use a binary search. – Spacedman Mar 06 '15 at 16:00