Plots der Sitzverteilung im Deutschen Bundestag

Die Sitzverteilung in einem Parlament wird häufig mit einer Grafik dargestellt, für die es keinen richtigen Namen gibt. Am treffendsden sind noch die Bezeichnungen Halbkreisdiagramm oder besser noch Halbringdiagramm. Ein solches Diagramm mit ggplot2 zu erstellen, erfordert einige Umwege.

So erstellt man eine Art Gauge, wobei man dann jedes Polygon, das den Sitzen einer Partei entspricht, separat einzeichnet. Dementsprechend lang ist das R-Sktipt, das die Sitzverteilungen der vier Legislaturperioden von 2002 bis 2017 darstellt. Die Grafik dokumentiert in erster Linie den Niedergang der SPD, der vor allem die Große Koalition 2005 bis 2009 geschadet hat. Sie hat 76 Sitze gekostet.

Sitzverteilung im Deutschen Bundestag

Klicke auf das Bild für eine vergrößerte Darstellung

library(gdata)
library(ggplot2)
library(extrafont)
library(grid)
library(gridExtra)

partei <- c("CDU/CSU","SPD","FDP","Die Linke","Bündnis 90/Die Grünen")
col=c("black","red","yellow2","pink","green")

sitze_15 <- c(248, 251, 47, 2, 55)
sitze_16 <- c(226, 222, 61, 54, 51)
sitze_17 <- c(239, 146, 93, 76, 68)
sitze_18 <- c(311, 193, 0, 64, 63)

sparlament_15 <- sum(sitze_15)
sparlament_16 <- sum(sitze_16)
sparlament_17 <- sum(sitze_17)
sparlament_18 <- sum(sitze_18)

prozent_15 <- sitze_15 / sparlament_15 * 100
prozent_16 <- sitze_16 / sparlament_16 * 100
prozent_17 <- sitze_17 / sparlament_17 * 100
prozent_18 <- sitze_18 / sparlament_18 * 100

seg_15 <- c(0, prozent_15[1], prozent_15[1] + prozent_15[2], prozent_15[1] + prozent_15[2] + prozent_15[3], 
            prozent_15[1] + prozent_15[2] + prozent_15[3] + prozent_15[4], 
            prozent_15[1] + prozent_15[2] + prozent_15[3] + prozent_15[4] + prozent_15[5])
seg_16 <- c(0, prozent_16[1], prozent_16[1] + prozent_16[2], prozent_16[1] + prozent_16[2] + prozent_16[3], 
           prozent_16[1] + prozent_16[2] + prozent_16[3] + prozent_16[4], 
           prozent_16[1] + prozent_16[2] + prozent_16[3] + prozent_16[4] + prozent_16[5])
seg_17 <- c(0, prozent_17[1], prozent_17[1] + prozent_17[2], prozent_17[1] + prozent_17[2] + prozent_17[3], 
            prozent_17[1] + prozent_17[2] + prozent_17[3] + prozent_17[4], 
            prozent_17[1] + prozent_17[2] + prozent_17[3] + prozent_17[4] + prozent_17[5])
seg_18 <- c(0, prozent_18[1], prozent_18[1] + prozent_18[2], prozent_18[1] + prozent_18[2] + prozent_18[3], 
            prozent_18[1] + prozent_18[2] + prozent_18[3] + prozent_18[4], 
            prozent_18[1] + prozent_18[2] + prozent_18[3] + prozent_18[4] + prozent_18[5])

gg.gauge_15 <- function(pos,breaks=c()) {
  require(ggplot2)
  get.poly <- function(a,b,r1=0.5,r2=1.0) {
    th.start <- pi*(1-a/100)
    th.end   <- pi*(1-b/100)
    th       <- seq(th.start,th.end,length=100)
    x        <- c(r1*cos(th),rev(r2*cos(th)))
    y        <- c(r1*sin(th),rev(r2*sin(th)))
    return(data.frame(x,y))
  }
  ggplot()+ 
    geom_polygon(data=get.poly(breaks[1],breaks[2]),aes(x,y),fill="black")+
    geom_polygon(data=get.poly(breaks[2],breaks[3]),aes(x,y),fill="red")+
    geom_polygon(data=get.poly(breaks[3],breaks[4]),aes(x,y),fill="yellow2")+
    geom_polygon(data=get.poly(breaks[4],breaks[5]),aes(x,y),fill="pink")+
    geom_polygon(data=get.poly(breaks[5],breaks[6]),aes(x,y),fill="green")+
    annotate("text", x= cos(pi/1.5), y = sin(pi/6), label = sitze_15[1], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/2.4), y = sin(pi/4), label = sitze_15[2], size=8, colour="white", fontface="bold")+
    annotate("text", x =cos(pi/3.8), 0.2, y = sin(pi/10), label = sitze_15[3], size=8, 
             colour="white", fontface="bold")+
    annotate("text", x = cos(pi/4.6), y = sin(pi/13), label = sitze_15[4], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/5), y = sin(pi/30), label = sitze_15[5], size=8, colour="white", fontface="bold")+
    ggtitle("15. Deutscher Bundestag (2002-2005)")+
    coord_fixed()+
    theme_bw()+
    theme(plot.title = element_text(size=15, hjust=0.5, family="Lato Black"))+
    theme(axis.text=element_blank(),
          axis.title=element_blank(),
          axis.ticks=element_blank(),
          panel.grid=element_blank(),
          panel.border=element_blank())
}

gg.gauge_16 <- function(pos,breaks=c()) {
  require(ggplot2)
  get.poly <- function(a,b,r1=0.5,r2=1.0) {
    th.start <- pi*(1-a/100)
    th.end   <- pi*(1-b/100)
    th       <- seq(th.start,th.end,length=100)
    x        <- c(r1*cos(th),rev(r2*cos(th)))
    y        <- c(r1*sin(th),rev(r2*sin(th)))
    return(data.frame(x,y))
  }
  ggplot()+ 
    geom_polygon(data=get.poly(breaks[1],breaks[2]),aes(x,y),fill="black")+
    geom_polygon(data=get.poly(breaks[2],breaks[3]),aes(x,y),fill="red")+
    geom_polygon(data=get.poly(breaks[3],breaks[4]),aes(x,y),fill="yellow2")+
    geom_polygon(data=get.poly(breaks[4],breaks[5]),aes(x,y),fill="pink")+
    geom_polygon(data=get.poly(breaks[5],breaks[6]),aes(x,y),fill="green")+
    annotate("text", x= cos(pi/1.5), y = sin(pi/6), label = sitze_16[1], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/2.2), y = sin(pi/4), label = sitze_16[2], size=8, colour="white", fontface="bold")+
    annotate("text", x =cos(pi/3.2), 0.2, y = sin(pi/6), label = sitze_16[3], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/4), y = sin(pi/10), label = sitze_16[4], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/5), y = sin(pi/30), label = sitze_16[5], size=8, colour="white", fontface="bold")+
    ggtitle("16. Deutscher Bundestag (2005-2009)")+
    coord_fixed()+
    theme_bw()+
    theme(plot.title = element_text(size=15, hjust=0.5, family="Lato Black"))+
    theme(axis.text=element_blank(),
          axis.title=element_blank(),
          axis.ticks=element_blank(),
          panel.grid=element_blank(),
          panel.border=element_blank())
}

gg.gauge_17 <- function(pos,breaks=c()) {
  require(ggplot2)
  get.poly <- function(a,b,r1=0.5,r2=1.0) {
    th.start <- pi*(1-a/100)
    th.end   <- pi*(1-b/100)
    th       <- seq(th.start,th.end,length=100)
    x        <- c(r1*cos(th),rev(r2*cos(th)))
    y        <- c(r1*sin(th),rev(r2*sin(th)))
    return(data.frame(x,y))
  }
  ggplot()+ 
    geom_polygon(data=get.poly(breaks[1],breaks[2]),aes(x,y),fill="black")+
    geom_polygon(data=get.poly(breaks[2],breaks[3]),aes(x,y),fill="red")+
    geom_polygon(data=get.poly(breaks[3],breaks[4]),aes(x,y),fill="yellow2")+
    geom_polygon(data=get.poly(breaks[4],breaks[5]),aes(x,y),fill="pink")+
    geom_polygon(data=get.poly(breaks[5],breaks[6]),aes(x,y),fill="green")+
    annotate("text", x= cos(pi/1.5), y = sin(pi/6), label = sitze_17[1], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/2.0), y = sin(pi/4), label = sitze_17[2], size=8, colour="white", fontface="bold")+
    annotate("text", x =cos(pi/2.8), 0.2, y = sin(pi/4.8), label = sitze_17[3], size=8, 
             colour="white", fontface="bold")+
    annotate("text", x = cos(pi/3.8), y = sin(pi/8), label = sitze_17[4], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/5), y = sin(pi/30), label = sitze_17[5], size=8, colour="white", fontface="bold")+
    ggtitle("17. Deutscher Bundestag (2009-2013)")+
    coord_fixed()+
    theme_bw()+
    theme(plot.title = element_text(size=15, hjust=0.5, family="Lato Black"))+
    theme(axis.text=element_blank(),
          axis.title=element_blank(),
          axis.ticks=element_blank(),
          panel.grid=element_blank(),
          panel.border=element_blank())
}

gg.gauge_18 <- function(pos,breaks=c()) {
  require(ggplot2)
  get.poly <- function(a,b,r1=0.5,r2=1.0) {
    th.start <- pi*(1-a/100)
    th.end   <- pi*(1-b/100)
    th       <- seq(th.start,th.end,length=100)
    x        <- c(r1*cos(th),rev(r2*cos(th)))
    y        <- c(r1*sin(th),rev(r2*sin(th)))
    return(data.frame(x,y))
  }
  ggplot()+ 
    geom_polygon(data=get.poly(breaks[1],breaks[2]),aes(x,y),fill="black")+
    geom_polygon(data=get.poly(breaks[2],breaks[3]),aes(x,y),fill="red")+
    geom_polygon(data=get.poly(breaks[3],breaks[4]),aes(x,y),fill="yellow2")+
    geom_polygon(data=get.poly(breaks[4],breaks[5]),aes(x,y),fill="pink")+
    geom_polygon(data=get.poly(breaks[5],breaks[6]),aes(x,y),fill="green")+
    annotate("text", x= cos(pi/1.5), y = sin(pi/6), label = sitze_18[1], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/2.5), y = sin(pi/4), label = sitze_18[2], size=8, colour="white", fontface="bold")+
  # annotate("text", x =cos(pi/2.8), 0.2, y = sin(pi/4.8), label = sitze_18[3], size=8,colour="white",fontface="bold")+
    annotate("text", x = cos(pi/3.8), y = sin(pi/8), label = sitze_18[4], size=8, colour="white", fontface="bold")+
    annotate("text", x = cos(pi/5), y = sin(pi/30), label = sitze_18[5], size=8, colour="white", fontface="bold")+
    ggtitle("18. Deutscher Bundestag (2013-2017)")+
    coord_fixed()+
    theme_bw()+
    theme(plot.title = element_text(size=15, hjust=0.5, family="Lato Black"))+
    theme(axis.text=element_blank(),
          axis.title=element_blank(),
          axis.ticks=element_blank(),
          panel.grid=element_blank(),
          panel.border=element_blank())
}

p1 <- gg.gauge_15(0, breaks = seg_15)
p2 <- gg.gauge_16(0, breaks = seg_16)
p3 <- gg.gauge_17(0, breaks = seg_17)
p4 <- gg.gauge_18(0, breaks = seg_18)

grid.arrange(p1, p2, p3, p4, ncol=2, top=textGrob("Sitzverteilungen im Bundestag", 
                                                  gp=gpar(fontsize=20, fontface = "bold")))

Das Skript: Zunächst werden manuell die Sitzverteilungen eingetragen und den Variablen sitze_15bissitze_18zugewiesen. Die Summe der Sitze wird anschließend in den Variablen sparlament_15 bis sparlament_18 gespeichert. Um später passende Werte für den Plot zu haben, werden sie Sitze in Prozentwerte umgerechnet und in den Variablen prozent_15 bis prozent_18 abgelegt. Jetzt geht es an die Definition der einzelnen Segmente des Plots. Dazu werden die Prozentwerte der Parteien nacheinander aufsummiert und in den Variablen seg_15 bis seg_18 gespeichert. Damit sind die Vorbereitungen abgeschlossen.
Dem Plot vorangestellt berechnet die Funktion get.poly zunächst die Koordinaten der Polygone für die Sitzverteilung und gibt sie als Data Frame zurück. Es folgt der eigentliche Plot mit ggplot(). geom_polygon zeichnet dann die Polygone für die Sitzverteilung. Der Rest ist Kosmetik. annotate zeichnet die Anzahl der Sitze in die Sitzverteilung ein. Hier musst du ein wenig experimentieren, um eine passende Position zu finden. ggtitle ist für die Überschrift zuständig, und die Angaben bei theme() blenden die Achsen und die Achsenbeschriftungen aus. Die jeweilige Sitzverteilung wird in den Variablen p1 bis p4 abgelegt und anschließend mit grid.arrange() gezeichnet.