Peilingwijzer
  • Alle cijfers
  • Updates & analyse
  • Hoe werkt de Peilingwijzer?
  • Over
  • Archief
  1. Grafieken
  2. Coalities
  • Grafieken
    • Trends
    • Alle peilingen
    • Winst en verlies
    • Verschillen
    • Huiseffecten
    • Coalities
  • Data
    • Data downloaden
    • Brongegevens
  1. Grafieken
  2. Coalities

Coalitiemogelijkheden op basis van de Peilingwijzer

De Peilingwijzer combineert de Tweede Kamerpeilingen van Ipsos I&O & Verian/EenVandaag

d3 = require("d3@7")

// Load data using FileAttachment
seats = await FileAttachment("resources/coa_seats.csv").csv({typed: true})
seats_av = await FileAttachment("resources/coa_seats_av.csv").csv({typed: true})

// Get party names from coa_seats_av.csv
partyNames = seats_av.map(d => d.party)

// Controls: party selection
viewof selectedParties = Inputs.checkbox(partyNames, {label: "Kies partijen voor coalitie:", value: ["VVD", "BBB", "NSC"]})

// Compute coalition seats for each simulation
coalitionSeats = selectedParties.length > 0
  ? seats.map(row => d3.sum(selectedParties.map(party => row[party])))
  : []

// Filter average seats for selected parties
averageSeats = seats_av.filter(d => selectedParties.includes(d.party))

// Load party colors
partycolours = await FileAttachment("resources/partycolours.csv").csv({typed: true})

// Create color domain and range from the CSV
partyColorDomain = partycolours.map(d => d.party)
partyColorRange = partycolours.map(d => d.colour)

// Only show legend for selected parties
selectedPartyColors = partycolours.filter(d => selectedParties.includes(d.party))
selectedPartyColorDomain = selectedPartyColors.map(d => d.party)
selectedPartyColorRange = selectedPartyColors.map(d => d.colour)

ciLower = d3.quantile(coalitionSeats, 0.025)
ciUpper = d3.quantile(coalitionSeats, 0.975)

meanAndCI = [{
  mean: averageSeats,
  ciLower: ciLower,
  ciUpper: ciUpper
}]
d3 = Object {format: ƒ(t), formatPrefix: ƒ(t, n), timeFormat: ƒ(t), timeParse: ƒ(t), utcFormat: ƒ(t), utcParse: ƒ(t), Adder: class, Delaunay: class, FormatSpecifier: ƒ(t), InternMap: class, InternSet: class, Node: ƒ(t), Path: class, Voronoi: class, ZoomTransform: ƒ(t, n, e), active: ƒ(t, n), arc: ƒ(), area: ƒ(t, n, e), areaRadial: ƒ(), ascending: ƒ(t, n), …}
seats = Array(2500) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, …]
seats_av = Array(15) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, columns: Array(3)]
partyNames = Array(15) ["PVV", "GL/PvdA", "VVD", "NSC", "D66", "BBB", "CDA", "SP", "Denk", "PvdD", "FvD", "SGP", "CU", "Volt", "JA21"]
selectedParties = Array(3) ["VVD", "NSC", "BBB"]
coalitionSeats = Array(2500) [29, 29, 28, 27, 28, 30, 30, 31, 31, 30, 29, 29, 28, 30, 29, 28, 31, 31, 30, 31, …]
averageSeats = Array(3) [Object, Object, Object]
partycolours = Array(15) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, columns: Array(3)]
partyColorDomain = Array(15) ["PVV", "GL/PvdA", "VVD", "NSC", "D66", "BBB", "CDA", "SP", "Denk", "PvdD", "FvD", "SGP", "CU", "Volt", "JA21"]
partyColorRange = Array(15) ["#00B9FF", "#dd2132", "#455493", "#181d37", "#4aab2d", "#94c11f", "#00894b", "#c73d77", "#41BAC1", "#EBC30A", "#6e0c13", "#7f8084", "#0094b4", "#4e2277", "#242b57"]
selectedPartyColors = Array(3) [Object, Object, Object]
selectedPartyColorDomain = Array(3) ["VVD", "NSC", "BBB"]
selectedPartyColorRange = Array(3) ["#455493", "#181d37", "#94c11f"]
ciLower = 28
ciUpper = 32
meanAndCI = Array(1) [Object]

Gemiddeld aantal zetels voor deze coalitie

// Top stacked horizontal bar: average seats per selected party, all in one bar
selectedParties.length > 0 && seatCounts.length > 0
  ? Plot.plot({
  marginLeft: 10,
  color: {
    legend: true,
    label: "Partij",
    domain: selectedPartyColorDomain,
    range: selectedPartyColorRange
  },
  x: {label: "Gemiddeld aantal zetels", domain: [0, 150], grid: true, ticks: d3.range(0, 151, 15)},
  y: {axis: null},
  height: 70,
  width: 800,
  marks: [
    Plot.barX(
      averageSeats,
      Plot.groupZ(
        {x: "sum"}, // sum the zetels for each partij
        {y: "", x: "zetels", fill: "party"}
      )
    ),
    Plot.ruleY(meanAndCI, {
      y: "",
      x1: "ciLower",
      x2: "ciUpper",
      stroke: "lightgrey",
      marker: "none"
    }),
     Plot.ruleX([75], {stroke: "grey", strokeDasharray: "4,4", strokeWidth: 1})
  ]
})
  : md`**Selecteer ten minste één partij om de grafiek te tonen.**`
VVDNSCBBB
0153045607590105120135150Gemiddeld aantal zetels →
selectedParties.length > 0
? md`Deze coalitie haalt nu gemiddeld **${d3.sum(averageSeats, d => d.zetels).toFixed(0)}** zetels in de Peilingwijzer, maar we hebben te maken met een onzekerheidsmarge, dus het kunnen het er ook ${ciLower.toFixed(0)} of ${ciUpper.toFixed(0)} zijn (95% credible interval).`
: md``

Deze coalitie haalt nu gemiddeld 30 zetels in de Peilingwijzer, maar we hebben te maken met een onzekerheidsmarge, dus het kunnen het er ook 28 of 32 zijn (95% credible interval).

Aantal zetels voor deze coalitie per simulatie

seatCounts = Array.from(
  d3.rollup(
    coalitionSeats,
    v => v.length,
    d => d
  ),
  ([seats, count]) => ({
    seats,
    count,
    percentage: 100 * count / coalitionSeats.length
  })
).sort((a, b) => a.seats - b.seats)

// Barplot: percentage simulaties per exact zetelaantal
selectedParties.length > 0 && seatCounts.length > 0
  ? Plot.plot({
      marks: [
        Plot.barY(seatCounts, {
          x: "seats", 
          y: "percentage",
          title: d => `${d.seats} zetels: ${d.percentage.toFixed(1)}% van de simulaties`
        })
      ],
      x: {
        label: "Aantal zetels voor coalitie",
        ticks: seatCounts.length,
        tickFormat: d => Number.isInteger(d) ? d : ""
      },
      y: {label: "Percentage simulaties"},
      height: 200
    })
  : md`**Selecteer ten minste één partij om de grafiek te tonen.**`
seatCounts = Array(8) [Object, Object, Object, Object, Object, Object, Object, Object]
0102030↑ Percentage simulaties2627282930313233Aantal zetels voor coalitie26 zetels: 0.1% van de simulaties27 zetels: 0.8% van de simulaties28 zetels: 6.9% van de simulaties29 zetels: 26.0% van de simulaties30 zetels: 36.0% van de simulaties31 zetels: 23.2% van de simulaties32 zetels: 6.5% van de simulaties33 zetels: 0.6% van de simulaties
percentage76plus = coalitionSeats.length > 0
  ? 100 * coalitionSeats.filter(d => d >= 76).length / coalitionSeats.length
  : 0

// Zoek de modale categorie (de waarde met de hoogste count)
modaal = seatCounts.length > 0
  ? seatCounts.reduce((a, b) => (a.count > b.count ? a : b))
  : {seats: null, percentage: null}
percentage76plus = 0
modaal = Object {seats: 30, count: 899, percentage: 35.96}
// Inline input for threshold
viewof seatThreshold = Inputs.range([0, 150], {step: 1, value: 76, label: html`<span style = "width:60px">Gewenst zetelaantal</span>`})
seatThreshold = 76
percentageThresholdPlus = coalitionSeats.length > 0
  ? 100 * coalitionSeats.filter(d => d >= seatThreshold).length / coalitionSeats.length
  : 0

md`Percentage van simulaties met ${seatThreshold} of meer zetels: **${percentageThresholdPlus.toFixed(1).toLocaleString("nl")}%**`
percentageThresholdPlus = 0

Percentage van simulaties met 76 of meer zetels: 0.0%

Uitleg

Elke Peilingwijzer bestaat uit een grote hoeveelheid simulaties. De steun voor een partij en dus ook voor een coalitie kan per simulatie iets verschillen.

In bovenstaande grafiek is te zien hoeveel zetels de coalitie haalt in alle simulaties. Zo haalt bovenstaande coalitie 30 zetels in 36.0% van de simulaties.

Op basis daaran kun je ook uitrekenen in welk percentage van de gevallen de coalitie een bepaald minimumaantal zetels haalt (bijvoorbeeld 76). Let op: dit geldt voor de huidige situatie en is geen voorspelling van de verkiezingsuitslag.