block by michalskop 3551d17ace1fbd6c81af583ccbff2459

CZ: voters changes 2014-2019

Full Screen

Ecological inference

using ei package

Analysis flow

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
    <script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
    <style>
        .mcontainer {
            padding-left: 10px;
            padding-right: 10px;
        }
        .header {
            padding-left: 10px;
            padding-right: 10px;
        }
        .h3 {
            position: relative;
            bottom: 20px;
        }
        .note {
            padding: 10px;
        }
        .logo {
            width: 64px;
            height: 64px;
            border-radius: 50%;
            margin: 10px;
            border: 1px solid #eee;
        }
        #chart {
            border: 1px solid #eee;
        }
        .hithit {
            font-size: 1.5em;
            width: 100vw;
            /*background-color: #fed201;*/
            padding: 10px;
            height: 100vh;
            color: white;
        }
    </style>
        <div class="header">
            <h1 id="h1" class="text-center"><span id="h1pic"></span> <span id="h1name"></span></h1>
            <h3 class="text-center h3">Zisky a ztráty voličů 2014 → 2019 <small> Hlasů: <span id="prev_n"></span><span id="curr_n"></span></small></h3>
            <div class="row">
                <div class="col-xs-4 col-xs-offset-1 text-center">
                    <strong>Minule volili <span class="shortname"></span></strong>
                </div>
                <div class="col-xs-4 col-xs-offset-2 text-center">
                    <strong>Odešli od <span class="shortname"></span></strong>
                </div>
            </div>
        </div>
        <div id="chart"></div>
        <div class="note xbg-info">
            <i class="fa fa-info-circle"></i> Odhady metodou ekologické inference. <strong>Zobrazeny přesuny voličů mezi stranami přesahující 10 000 lidí.</strong><br />
            CC-BY Michal Škop, KohoVolit.eu, VolebníKalkulačka.cz
        </div>
        <div class="hithit text-center bg-primary">
            <h3></h3>
            <h3>Podpořte projekty KohoVolit.eu!</h3>
            <h3>projects.KohoVolit.eu</h3>
        </div>
    <script>
        var formatNumber = d3.format(",.0f");

        d3.csv("list_2019_filtered.csv", function (er,d2018) {
            d3.csv("list_2014_filtered.csv", function(err,d2017) {
                d3.csv("matn_chart.csv", function(errr,source) {

                    var d17to19 = {};
                    var party2color = {};
                    d2017.forEach(function(d) {
                        d17to19[d['party']] = {}
                        party2color[d['party']] = d['color']
                    });
                    d2018.forEach(function(d) {
                        party2color[d['party']] = d['color']
                    });
                    var d19to17 = {};
                    source.forEach(function(d) {
                        d19to17[d['name']] = {}
                        for (k in d) {
                            if (k != 'name') {
                                d19to17[d['name']][k] = parseInt(d[k])
                                d17to19[k][d['name']] = parseInt(d[k])
                            }
                        }
                    })



                    var names = source['name'];
                    // var i = QueryString.i;
                    var i = 6
                    if (i === undefined) {
                        i = 1;
                    }
                    var party = d2018[i]['party']
                    var prev_party = d2018[i]['previous']
                    var data = source[i];

                    d3.select("#h1name")
                        .html(d2018[i]['party_name']);
                    d3.select("#h1pic")
                        .html("<img class='logo' src='./" + d2018[i]['party'] + ".png' />");
                    d3.selectAll(".shortname")
                        .html(d2018[i]['party'])
                    d3.select("#curr_n")
                        .html(formatNumber(d2018[i]['votes']));
                    d3.select("#prev_n")
                        .html(formatNumber(d2018[i]['previous_votes']));

                    var sumout = 0
                    for (k in d17to19[prev_party]) {
                        if (k != prev_party) {
                            sumout += d17to19[prev_party][k]
                        }
                    }

                    if (d2018[i]['votes'] > 600000) {
                        var h = 500;
                    } else {
                        var h = 400;
                    }

                    var margin = {top: 10, right: 10, bottom: 10, left: 10},
                        width = 930 - margin.left - margin.right,
                        height = h - margin.top - margin.bottom;
                    var svg = d3.select("#chart").append("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                      .append("g")
                        .attr("transform",
                              "translate(" + margin.left + "," + margin.top + ")");

                    maxsum = Math.max(sumout, d2018[i]['votes'])

                    var x = d3.scale.linear()
              		             .domain([0, 100])
              		             .range([0, width])
              		var y = d3.scale.linear()
              		             .domain([0, maxsum * 1.1])
              		             .range([0, height]);

                    // basic rectangle
                    var offset = (maxsum - d2018[i]['votes']) / 2;
                    svg.append("rect")
                        .attr("width", x(20))
                        .attr("height", y(d2018[i]['votes']))
                        .attr("x", x(40))
                        .attr("y", y(offset))
                        .attr("fill", d2018[i]['color']);

                    svg.append("text")
                        .attr("x", x(50))
                        .attr("y", function() {
                            return y(d2018[i]['votes']/2 + offset);
                        })
                        .attr("dy", 0)
                        .attr("text-anchor", "middle")
                        .attr("fill", "white")
                        .attr("font-size", "35px")
                        .text(party)

                    svg.append("text")
                        .attr("x", x(50))
                        .attr("y", function() {
                            return y(d2018[i]['votes']/2 * 1.3 + offset);
                        })
                        .attr("dy", 0)
                        .attr("text-anchor", "middle")
                        .attr("fill", "white")
                        .attr("font-size", "20px")
                        .text(formatNumber(d2018[i]['votes']))

                    // prepare out and in rectangles
                    var outs = []
                    for (k in d17to19[prev_party]) {
                        if ((d17to19[prev_party][k] > 10000) && (party != k)) {
                            outs.push({
                                'name': k,
                                'value': d17to19[prev_party][k],
                                'color': party2color[k]
                            })
                        }
                    }
                    outs.sort(function(a, b) {
                        return b.value - a.value;
                    });
                    var ins = []
                    for (k in d17to19) {
                        // if ((d17to19[k][party] > 10000) && (prev_party != k)) {
                        if ((d17to19[k][party] > 10000)) {
                            ins.push({
                                'name': k,
                                'value': d17to19[k][party],
                                'color': party2color[k]
                            })
                        }
                    }
                    ins.sort(function(a, b) {
                        return b.value - a.value;
                    });

                    s = 0
                    outs.forEach(function (out,k) {
                        s += y(out['value'])
                        s += 15
                    })
                    s = s - 15
                    var offset = (y(maxsum) - s) / 2;
                    outs.forEach(function (out, k) {
                        outs[k]['y0'] = offset;
                        outs[k]['y1'] = offset + y(out['value'])
                        outs[k]['half'] = (outs[k]['y1'] + outs[k]['y0']) / 2
                        offset = outs[k]['y1'] + 15;
                        outs[k]['arrow'] = [
                            {"x": x(76.98), "y": outs[k]['y0']}, {"x": x(79), "y": outs[k]['half']}, {"x": x(76.98), "y": outs[k]['y1']}, {"x": x(76.98), "y": outs[k]['y0']}
                        ]
                    });

                    s = 0
                    ins.forEach(function (out,k) {
                        s += y(out['value'])
                        s += 15
                    })
                    s = s - 15
                    var offset = (y(maxsum) - s) / 2;
                    ins.forEach(function (inn, k) {
                        ins[k]['y0'] = offset;
                        ins[k]['y1'] = offset + y(inn['value'])
                        ins[k]['half'] = (ins[k]['y1'] + ins[k]['y0']) / 2
                        offset = ins[k]['y1'] + 15;
                        ins[k]['arrow'] = [
                            {"x": x(34.95), "y": ins[k]['y0']}, {"x": x(37), "y": ins[k]['half']}, {"x": x(34.95), "y": ins[k]['y1']},
                             {"x": x(34.95), "y": ins[k]['y0']}
                        ]
                    });


                    var arrowFunction = d3.svg.area()
                                .x(function(d) { return d.x; })
                                .y1(function(d) { return d.y; });

                    // arrows out
                    var rectouts = svg.selectAll(".rectout")
                       .data(outs)
                           .enter()
                       .append("rect")
                            .attr("width", x(14))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(63.05))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", d2018[i]['color']);

                    var arrowouts = svg.selectAll(".arrowout")
                       .data(outs)
                           .enter()
                        .append("path")
                            .attr("d", function(d) {
                                return arrowFunction(d['arrow']);
                            })
                            .attr("fill", d2018[i]['color']);

                    svg.selectAll(".textout")
                       .data(outs)
                           .enter()
                        .append("text")
                            .attr("x", x(70))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4.5), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4.5), 18), 30)
                            })
                            .text(function(d) {
                                return formatNumber(my_round(d['value']))
                            })

                    //arrows in
                    svg.selectAll(".rectin")
                       .data(ins)
                           .enter()
                       .append("rect")
                            .attr("width", x(14))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(21))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".arrowin")
                       .data(ins)
                           .enter()
                        .append("path")
                            .attr("d", function(d) {
                                return arrowFunction(d['arrow']);
                            })
                            .attr("fill", function(d) {
                                return d['color']
                            });

                    svg.selectAll(".textin")
                       .data(ins)
                           .enter()
                        .append("text")
                            .attr("x", x(28))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4.5), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4.5), 18), 30)
                            })
                            .text(function(d) {
                                return formatNumber(my_round(d['value']))
                            })

                    // outs
                    svg.selectAll(".rectend")
                       .data(outs)
                           .enter()
                       .append("rect")
                            .attr("width", x(16))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(84))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".textout")
                       .data(outs)
                           .enter()
                        .append("text")
                            .attr("x", x(92))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4), 20), 30)
                            })
                            .text(function(d) {
                                return d['name']
                            })
                    // ins
                    svg.selectAll(".rectstart")
                       .data(ins)
                           .enter()
                       .append("rect")
                            .attr("width", x(16))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(0))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".textstart")
                       .data(ins)
                           .enter()
                        .append("text")
                            .attr("x", x(8))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.max(y(d['value'] / 4), 20)
                            })
                            .text(function(d) {
                                return d['name']
                            })



                    var pause = 0;

                })
            })
        })

        function my_round(n) {
            if (n < 100000) {
                return Math.round(n/5000)*5000;
            }
            return Math.round(n/10000)*10000;
        }
        var QueryString = function () {
        // This function is anonymous, is executed immediately and
        // the return value is assigned to QueryString!
          var query_string = {};
          var query = window.location.search.substring(1);
          var vars = query.split("&");
          for (var i=0;i<vars.length;i++) {
            var pair = vars[i].split("=");
                // If first entry with this name
            if (typeof query_string[pair[0]] === "undefined") {
              query_string[pair[0]] = decodeURIComponent(pair[1]);
                // If second entry with this name
            } else if (typeof query_string[pair[0]] === "string") {
              var arr = [ query_string[pair[0]],decodeURIComponent(pair[1]) ];
              query_string[pair[0]] = arr;
                // If third or later entry with this name
            } else {
              query_string[pair[0]].push(decodeURIComponent(pair[1]));
            }
          }
          return query_string;
        }();

    </script>
</body>
</html>

ei.r

# Ecological inference using ei package
path = "/home/michal/dev/prechody/2014-2019/"

Ntotal = 8316737  # Voliči v seznamu

list_previous_name = "list_2014_filtered.csv"
list_current_name = "list_2019_filtered.csv"

setwd(path)

library(ei)

# Prepare data and variables
data = read.csv("data_filtered_random.csv", header = TRUE, fileEncoding = "utf-8", encoding = "utf-8")
variables = names(data)
As = variables[which(grepl("A", variables) == TRUE)]
Bs = variables[which(grepl("B", variables) == TRUE)]

# Run EI
# Example:
# dbuf = ei(cbind(B5, B9, B26, B27, B28, B30, B39, B997, B998, B999) ~ cbind(A1, A4, A7, A8, A15, A20, A21, A24, A29, A997, A998, A999), data = data)
eval(parse(text = paste0( "dbuf = ei(cbind(" , paste(Bs, collapse = ", "), ") ~ cbind(", paste(As, collapse = ", "), "), data = data)")))

# create and save result matrices
list_previous = read.csv(list_previous_name, header = TRUE, fileEncoding = "utf-8", encoding = "utf-8")
list_current = read.csv(list_current_name, header = TRUE, fileEncoding = "utf-8", encoding = "utf-8")

nrows = dim(data)[1]
mat_ave = matrix(nrow=length(As), ncol=length(Bs), dimnames=list(As, Bs))
for (B in Bs) {
    for (A in As) {
        s = 0
        for (r in 1:nrows) {
            a = paste0("beta.", A, ".", B, ".", r)
            s = s + mean(dbuf$draws$Beta[,a]) * data[r, A]
        }
        mat_ave[A, B] = s
    }
}
rownames(mat_ave) = list_previous[, "party"]
colnames(mat_ave) = list_current[, "party"]

matp = mat_ave / apply(mat_ave,1,'sum')

tmat_ave = t(mat_ave)

write.csv(mat_ave, "matn_filtered.csv")
write.csv(tmat_ave, "matn_chart_filtered.csv")
write.csv(matp, "matp_filtered.csv")

n = sum(data)/2

write.csv(mat_ave * Ntotal / n, "matn.csv")
write.csv(tmat_ave * Ntotal / n, "matn_chart.csv")

generate.py

import os

for i in range(0, 7):
    command = "chromium-browser --headless --disable-gpu --screenshot --hide-scrollbars --window-size=952,756 --save-to-png=q50.png http://localhost/michal/dev/prechody/2014-2019/index_cs.html?i=" + str(i)
    # command = "chromium-browser --headless --disable-gpu --screenshot --hide-scrollbars --window-size=952,1065 --save-to-png=q50.png http://localhost/michal/dev/prechody/2014-2019/index_cs.html?i=" + str(i)
    os.system(command)
    command = "cp screenshot.png parties/party_" + str(i) + ".png"
    os.system(command)
    print(i)

index_cs.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
    <script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
    <style>
        .mcontainer {
            padding-left: 10px;
            padding-right: 10px;
        }
        .header {
            padding-left: 10px;
            padding-right: 10px;
        }
        .h3 {
            position: relative;
            bottom: 20px;
        }
        .note {
            padding: 10px;
        }
        .logo {
            width: 64px;
            height: 64px;
            border-radius: 50%;
            margin: 10px;
            border: 1px solid #eee;
        }
        #chart {
            border: 1px solid #eee;
        }
        .hithit {
            font-size: 1.5em;
            width: 100vw;
            /*background-color: #fed201;*/
            padding: 10px;
            height: 100vh;
            color: white;
        }
    </style>
        <div class="header">
            <h1 id="h1" class="text-center"><span id="h1pic"></span> <span id="h1name"></span></h1>
            <h3 class="text-center h3">Zisky a ztráty voličů 2014 → 2019 <small> Hlasů: <span id="prev_n"></span><span id="curr_n"></span></small></h3>
            <div class="row">
                <div class="col-xs-4 col-xs-offset-1 text-center">
                    <strong>Minule volili <span class="shortname"></span></strong>
                </div>
                <div class="col-xs-4 col-xs-offset-2 text-center">
                    <strong>Odešli od <span class="shortname"></span></strong>
                </div>
            </div>
        </div>
        <div id="chart"></div>
        <div class="note xbg-info">
            <i class="fa fa-info-circle"></i> Odhady metodou ekologické inference. <strong>Zobrazeny přesuny voličů mezi stranami přesahující 10 000 lidí.</strong><br />
            CC-BY Michal Škop, KohoVolit.eu, VolebníKalkulačka.cz
        </div>
        <div class="hithit text-center bg-primary">
            <h3></h3>
            <h3>Podpořte projekty KohoVolit.eu!</h3>
            <h3>projects.KohoVolit.eu</h3>
        </div>
    <script>
        var formatNumber = d3.format(",.0f");

        d3.csv("list_2019_filtered.csv", function (er,d2018) {
            d3.csv("list_2014_filtered.csv", function(err,d2017) {
                d3.csv("matn_chart.csv", function(errr,source) {

                    var d17to19 = {};
                    var party2color = {};
                    d2017.forEach(function(d) {
                        d17to19[d['party']] = {}
                        party2color[d['party']] = d['color']
                    });
                    d2018.forEach(function(d) {
                        party2color[d['party']] = d['color']
                    });
                    var d19to17 = {};
                    source.forEach(function(d) {
                        d19to17[d['name']] = {}
                        for (k in d) {
                            if (k != 'name') {
                                d19to17[d['name']][k] = parseInt(d[k])
                                d17to19[k][d['name']] = parseInt(d[k])
                            }
                        }
                    })



                    var names = source['name'];
                    var i = QueryString.i;
                    if (i === undefined) {
                        i = 1;
                    }
                    var party = d2018[i]['party']
                    var prev_party = d2018[i]['previous']
                    var data = source[i];

                    d3.select("#h1name")
                        .html(d2018[i]['party_name']);
                    d3.select("#h1pic")
                        .html("<img class='logo' src='./" + d2018[i]['party'] + ".png' />");
                    d3.selectAll(".shortname")
                        .html(d2018[i]['party'])
                    d3.select("#curr_n")
                        .html(formatNumber(d2018[i]['votes']));
                    d3.select("#prev_n")
                        .html(formatNumber(d2018[i]['previous_votes']));

                    var sumout = 0
                    for (k in d17to19[prev_party]) {
                        if (k != prev_party) {
                            sumout += d17to19[prev_party][k]
                        }
                    }

                    if (d2018[i]['votes'] > 600000) {
                        var h = 500;
                    } else {
                        var h = 400;
                    }

                    var margin = {top: 10, right: 10, bottom: 10, left: 10},
                        width = 930 - margin.left - margin.right,
                        height = h - margin.top - margin.bottom;
                    var svg = d3.select("#chart").append("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                      .append("g")
                        .attr("transform",
                              "translate(" + margin.left + "," + margin.top + ")");

                    maxsum = Math.max(sumout, d2018[i]['votes'])

                    var x = d3.scale.linear()
              		             .domain([0, 100])
              		             .range([0, width])
              		var y = d3.scale.linear()
              		             .domain([0, maxsum * 1.1])
              		             .range([0, height]);

                    // basic rectangle
                    var offset = (maxsum - d2018[i]['votes']) / 2;
                    svg.append("rect")
                        .attr("width", x(20))
                        .attr("height", y(d2018[i]['votes']))
                        .attr("x", x(40))
                        .attr("y", y(offset))
                        .attr("fill", d2018[i]['color']);

                    svg.append("text")
                        .attr("x", x(50))
                        .attr("y", function() {
                            return y(d2018[i]['votes']/2 + offset);
                        })
                        .attr("dy", 0)
                        .attr("text-anchor", "middle")
                        .attr("fill", "white")
                        .attr("font-size", "35px")
                        .text(party)

                    svg.append("text")
                        .attr("x", x(50))
                        .attr("y", function() {
                            return y(d2018[i]['votes']/2 * 1.3 + offset);
                        })
                        .attr("dy", 0)
                        .attr("text-anchor", "middle")
                        .attr("fill", "white")
                        .attr("font-size", "20px")
                        .text(formatNumber(d2018[i]['votes']))

                    // prepare out and in rectangles
                    var outs = []
                    for (k in d17to19[prev_party]) {
                        if ((d17to19[prev_party][k] > 10000) && (party != k)) {
                            outs.push({
                                'name': k,
                                'value': d17to19[prev_party][k],
                                'color': party2color[k]
                            })
                        }
                    }
                    outs.sort(function(a, b) {
                        return b.value - a.value;
                    });
                    var ins = []
                    for (k in d17to19) {
                        // if ((d17to19[k][party] > 10000) && (prev_party != k)) {
                        if ((d17to19[k][party] > 10000)) {
                            ins.push({
                                'name': k,
                                'value': d17to19[k][party],
                                'color': party2color[k]
                            })
                        }
                    }
                    ins.sort(function(a, b) {
                        return b.value - a.value;
                    });

                    s = 0
                    outs.forEach(function (out,k) {
                        s += y(out['value'])
                        s += 15
                    })
                    s = s - 15
                    var offset = (y(maxsum) - s) / 2;
                    outs.forEach(function (out, k) {
                        outs[k]['y0'] = offset;
                        outs[k]['y1'] = offset + y(out['value'])
                        outs[k]['half'] = (outs[k]['y1'] + outs[k]['y0']) / 2
                        offset = outs[k]['y1'] + 15;
                        outs[k]['arrow'] = [
                            {"x": x(76.98), "y": outs[k]['y0']}, {"x": x(79), "y": outs[k]['half']}, {"x": x(76.98), "y": outs[k]['y1']}, {"x": x(76.98), "y": outs[k]['y0']}
                        ]
                    });

                    s = 0
                    ins.forEach(function (out,k) {
                        s += y(out['value'])
                        s += 15
                    })
                    s = s - 15
                    var offset = (y(maxsum) - s) / 2;
                    ins.forEach(function (inn, k) {
                        ins[k]['y0'] = offset;
                        ins[k]['y1'] = offset + y(inn['value'])
                        ins[k]['half'] = (ins[k]['y1'] + ins[k]['y0']) / 2
                        offset = ins[k]['y1'] + 15;
                        ins[k]['arrow'] = [
                            {"x": x(34.95), "y": ins[k]['y0']}, {"x": x(37), "y": ins[k]['half']}, {"x": x(34.95), "y": ins[k]['y1']},
                             {"x": x(34.95), "y": ins[k]['y0']}
                        ]
                    });


                    var arrowFunction = d3.svg.area()
                                .x(function(d) { return d.x; })
                                .y1(function(d) { return d.y; });

                    // arrows out
                    var rectouts = svg.selectAll(".rectout")
                       .data(outs)
                           .enter()
                       .append("rect")
                            .attr("width", x(14))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(63.05))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", d2018[i]['color']);

                    var arrowouts = svg.selectAll(".arrowout")
                       .data(outs)
                           .enter()
                        .append("path")
                            .attr("d", function(d) {
                                return arrowFunction(d['arrow']);
                            })
                            .attr("fill", d2018[i]['color']);

                    svg.selectAll(".textout")
                       .data(outs)
                           .enter()
                        .append("text")
                            .attr("x", x(70))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4.5), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4.5), 18), 30)
                            })
                            .text(function(d) {
                                return formatNumber(my_round(d['value']))
                            })

                    //arrows in
                    svg.selectAll(".rectin")
                       .data(ins)
                           .enter()
                       .append("rect")
                            .attr("width", x(14))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(21))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".arrowin")
                       .data(ins)
                           .enter()
                        .append("path")
                            .attr("d", function(d) {
                                return arrowFunction(d['arrow']);
                            })
                            .attr("fill", function(d) {
                                return d['color']
                            });

                    svg.selectAll(".textin")
                       .data(ins)
                           .enter()
                        .append("text")
                            .attr("x", x(28))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4.5), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4.5), 18), 30)
                            })
                            .text(function(d) {
                                return formatNumber(my_round(d['value']))
                            })

                    // outs
                    svg.selectAll(".rectend")
                       .data(outs)
                           .enter()
                       .append("rect")
                            .attr("width", x(16))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(84))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".textout")
                       .data(outs)
                           .enter()
                        .append("text")
                            .attr("x", x(92))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.min(Math.max(y(d['value'] / 4), 20), 30)
                            })
                            .text(function(d) {
                                return d['name']
                            })
                    // ins
                    svg.selectAll(".rectstart")
                       .data(ins)
                           .enter()
                       .append("rect")
                            .attr("width", x(16))
                            .attr("height", function(d) {
                                return d['y1'] - d['y0'];
                            })
                            .attr("x", x(0))
                            .attr("y", function(d) {
                                return d['y0'];
                            })
                            .attr("fill", function(d){
                                return d['color'];
                            });

                    svg.selectAll(".textstart")
                       .data(ins)
                           .enter()
                        .append("text")
                            .attr("x", x(8))
                            .attr("y", function(d){
                                return d['half'] + Math.max(y(d['value'] / 4), 20)/3
                            })
                            .attr("text-anchor", "middle")
                            .attr("fill", "white")
                            .attr("font-size", function(d) {
                                return Math.max(y(d['value'] / 4), 20)
                            })
                            .text(function(d) {
                                return d['name']
                            })



                    var pause = 0;

                })
            })
        })

        function my_round(n) {
            if (n < 100000) {
                return Math.round(n/5000)*5000;
            }
            return Math.round(n/10000)*10000;
        }
        var QueryString = function () {
        // This function is anonymous, is executed immediately and
        // the return value is assigned to QueryString!
          var query_string = {};
          var query = window.location.search.substring(1);
          var vars = query.split("&");
          for (var i=0;i<vars.length;i++) {
            var pair = vars[i].split("=");
                // If first entry with this name
            if (typeof query_string[pair[0]] === "undefined") {
              query_string[pair[0]] = decodeURIComponent(pair[1]);
                // If second entry with this name
            } else if (typeof query_string[pair[0]] === "string") {
              var arr = [ query_string[pair[0]],decodeURIComponent(pair[1]) ];
              query_string[pair[0]] = arr;
                // If third or later entry with this name
            } else {
              query_string[pair[0]].push(decodeURIComponent(pair[1]));
            }
          }
          return query_string;
        }();

    </script>
</body>
</html>

join_data.py

"""Join the 2017 and 2019 data for ei."""
import csv
import random

path = "/home/michal/dev/prechody/2014-2019/"

previous = '2014'
current = '2019'

parties = {
    previous: [5, 7, 10, 14, 16, 20, 22, 23, 24, 32],
    current: [5, 9, 26, 27, 28, 30, 39]
}

# how many okrseks should be selected
select = 0.1


def _n2(n):
    if n < 10:
        return "0" + str(n)
    else:
        return str(n)


def _n(s):
    if s == '':
        return 0
    else:
        return int(s)


# data rows
d = {
    previous: {},
    current: {}
}
# stations in municipality for matching in changed numbering municipality
stations = {
    previous: {},
    current: {}
}
# selected data, filtered out 6 % of polling stations
data = {}
for y in d:
    with open(path + "data_" + y + ".csv") as fin:
        dr = csv.DictReader(fin)
        for row in dr:
            try:
                stations[y][row['OBEC']]
            except Exception:
                stations[y][row['OBEC']] = []
                d[y][row['OBEC']] = {}
            stations[y][row['OBEC']].append(row['OKRSEK'])
            d[y][row['OBEC']][row['OKRSEK']] = row

for muni in d[current]:
    same = True
    for okr in stations[current][muni]:
        try:
            d[previous][muni][okr]
        except Exception:
            same = False
    if same:
        data[muni] = {}
        for okr in stations[current][muni]:
            data[muni][okr] = {}
            data[muni][okr][previous] = d[previous][muni][okr]
            data[muni][okr][current] = d[current][muni][okr]
    else:
        try:
            if len(stations[previous][muni]) == len(stations[current][muni]):
                data[muni] = {}
                for i in range(0, len(stations[previous][muni])):
                    o_current = stations[current][muni][i]
                    o_previous = stations[previous][muni][i]
                    data[muni][o_current] = {}
                    data[muni][o_current][previous] = d[previous][muni][o_previous]
                    data[muni][o_current][current] = d[current][muni][o_current]
            else:
                print(muni, len(stations[current][muni]), '::not the same number or stations')
        except Exception:
            print(muni, len(stations[current][muni]), '::not in preious year')

# filter parties, randomly select some districts to be able to perfomr EI
with open(path + "data_filtered_random.csv", "w") as foutR:
    header = []
    for k in parties[previous]:
        header.append('A' + str(k))
    header.append('A997')   # ostatní strany
    header.append('A998')   # odešlí
    header.append('A999')   # nevoliči
    for k in parties[current]:
        header.append('B' + str(k))
    header.append('B997')
    header.append('B998')
    header.append('B999')
    drR = csv.DictWriter(foutR, header)
    drR.writeheader()
    with open("data_filtered.csv", "w") as fout:
        dr = csv.DictWriter(fout, header)
        dr.writeheader()
        for muni in data:
            for okr in data[muni]:
                row = {}
                for y in parties:
                    if y == previous:
                        code = 'A'
                    else:
                        code = 'B'
                    s = 0
                    for k in parties[y]:
                        try:
                            num = round(float(data[muni][okr][y]['HLASY_' + _n2(k)]))
                        except Exception:
                            num = 0
                        s += num
                        row[code + str(k)] = num
                    row[code + '997'] = int(data[muni][okr][y]['HLASY']) - s
                    row[code + '999'] = int(data[muni][okr][y]['VOLICI']) - int(data[muni][okr][y]['HLASY'])

                if int(data[muni][okr][previous]['VOLICI']) >= int(data[muni][okr][current]['VOLICI']):
                    row['B998'] = round(float(data[muni][okr][previous]['VOLICI'])) - int(data[muni][okr][current]['VOLICI'])
                    row['A998'] = 0
                else:
                    row['A998'] = int(data[muni][okr][current]['VOLICI']) - round(float(data[muni][okr][previous]['VOLICI']))
                    row['B998'] = 0
                if (1.25 * int(data[muni][okr][previous]['VOLICI']) >= int(data[muni][okr][current]['VOLICI'])) and (0.8 * round(float(data[muni][okr][previous]['VOLICI'])) <= int(data[muni][okr][current]['VOLICI'])):
                    dr.writerow(row)
                    if random.random() < select:
                        drR.writerow(row)

list_2014_filtered.csv

party_id,party_name,party,color,party_group,votes
5,Křesťanská a demokratická unie – ČSL,KDU-ČSL,#fee000,KDU-ČSL,150792
7,Koalice TOP 09 a STAN,STAN-TOP,#5d8c00,STAN,241747
10,Komunistická strana Čech a Moravy,KSČM,#8c0000,KSČM,166478
14,Česká str.sociálně demokrat.,ČSSD,#f1953e,ČSSD,214800
16,ANO 2011,ANO,#261060,ANO,244501
20,Občanská demokratická strana,ODS,#004494,ODS,116389
22,Úsvit přímé demokr.T.Okamury,Úsvit,#eb1b26,Úsvit,47306
23,Strana zelených,Zelení,#06b15d,Zelení,57240
24,Strana svobodných občanů,Svobodní,#009982,Svobodní,79540
32,Česká pirátská strana,Piráti,#000000,Piráti,72514
997,Ostatní,Ostatní,#888,ostatní,
998,Pribylí,Pribylí,#888,přibylí,
999,Nevoliči,Nevoliči,#888,nevoliči,

list_2019_filtered.csv

"party_id","party_name","party","color","party_group","votes","previous","previous_votes"
5,"Občanská demokratická strana","ODS","#004494","ODS",344885,"ODS",116389
9,"Komunistická strana Čech a Moravy","KSČM","#8c0000","KSČM",164624,"KSČM",166478
26,"Koalice STAN a TOP 09","STAN-TOP","#5d8c00","STAN",276220,"STAN-TOP",241747
27,"Česká pirátská strana","Piráti","#000000","Piráti",330844,"Piráti",72514
28,"Strana přímé demokracie - Tomio Okamura","SPD","#eb1b26","SPD",216718,"Úsvit",47306
30,"ANO 2011","ANO","#261060","ANO",502343,"ANO",244501
39,"Křesťanská a demokratická unie – ČSL","KDU-ČSL","#fee000","KDU-ČSL",171723,"KDU-ČSL",150792
997,"Ostatní","Ostatní","#888","ostatní",,,
998,"Pribylí","Pribylí","#888","přibylí",,,
999,"Nevoliči","Nevoliči","#888","nevoliči",,,

matn.csv

"","ODS","KSČM","STAN-TOP","Piráti","SPD","ANO","KDU-ČSL","Ostatní","Pribylí","Nevoliči"
"KDU-ČSL",7902.52066646142,3710.04524169305,7664.70450948889,12822.5018879205,10953.5413209651,15161.1952338344,76263.718925426,10405.6205588344,1948.3945331815,5120.43352744681
"STAN-TOP",53358.1158587269,3391.96154835698,71391.2292949125,46562.8160791694,5292.00740662077,6082.23716387426,4194.83250180553,24351.1410242712,2351.77253834447,8909.10587780663
"KSČM",5197.06338724021,52734.1572468697,3436.75067823169,6874.98051809606,26820.0745994266,27100.6336872136,2607.38786428168,26090.919387313,2051.27191158657,9328.51749198928
"ČSSD",10135.3174046724,18861.2059261273,6398.81958740629,25713.0552463351,26360.4944270103,33738.7270993172,6067.20573696251,60802.1862625756,3729.77195081468,20661.6474172972
"ANO",42182.784565271,9648.08611157749,19575.3374425446,29647.7254117156,30854.0129400745,45822.3433734248,4180.8313464953,41736.2860941188,2964.4008974097,14243.2680812685
"ODS",26918.3535693254,3107.7729745208,8858.90753059627,18904.1500397941,8136.78355087125,17226.3676698714,3182.40998472968,13606.3290869793,1518.39683219879,12119.4651812784
"Úsvit",4027.17000687799,4615.07416549273,1865.47590157616,5503.43535866508,8265.97832795608,6259.95889485987,2017.66725966274,5070.67677162414,994.946186955969,8014.8199637421
"Zelení",5475.15675314407,2296.43221579228,8389.47882677224,11896.8177556227,2384.17496276938,5309.19019728042,2802.65907394515,10210.91553676,972.991966622136,3131.23088636049
"Svobodní",8024.84342698024,2282.65115945869,9192.59662035283,14865.0768111343,5916.86801898319,5572.85293313121,2662.72619388103,11951.2984994531,1613.91286478916,12604.6803287013
"Piráti",12291.7296988738,3572.90157186639,9106.25077358363,16328.8688945247,3862.11514571879,6925.98257307438,3184.30882016752,5731.94165727966,1231.8241410486,5764.75986213446
"Ostatní",10649.2973190035,8452.00242738954,5982.23702297224,16140.5781418659,9111.62163736297,29877.9244886872,2964.53166039187,22853.4517310939,1733.15077751526,15520.820805389
"Pribylí",11544.6045001565,2907.38734126459,7037.85878763301,11583.9154460258,4135.10360714388,10007.997986567,2039.87985366755,14548.193557729,779.949580218848,62755.9603806054
"Nevoliči",127811.388323227,50044.5133382248,93904.2232778372,97053.3826494513,72145.7526752109,295361.707336463,58128.3265395127,107236.145857065,225181.430130567,5590069.12559816

matn_chart.csv

"name","KDU-ČSL","STAN-TOP","KSČM","ČSSD","ANO","ODS","Úsvit","Zelení","Svobodní","Piráti","Ostatní","Pribylí","Nevoliči"
"ODS",7902.52066646142,53358.1158587269,5197.06338724021,10135.3174046724,42182.784565271,26918.3535693254,4027.17000687799,5475.15675314407,8024.84342698024,12291.7296988738,10649.2973190035,11544.6045001565,127811.388323227
"KSČM",3710.04524169305,3391.96154835698,52734.1572468697,18861.2059261273,9648.08611157749,3107.7729745208,4615.07416549273,2296.43221579228,2282.65115945869,3572.90157186639,8452.00242738954,2907.38734126459,50044.5133382248
"STAN-TOP",7664.70450948889,71391.2292949125,3436.75067823169,6398.81958740629,19575.3374425446,8858.90753059627,1865.47590157616,8389.47882677224,9192.59662035283,9106.25077358363,5982.23702297224,7037.85878763301,93904.2232778372
"Piráti",12822.5018879205,46562.8160791694,6874.98051809606,25713.0552463351,29647.7254117156,18904.1500397941,5503.43535866508,11896.8177556227,14865.0768111343,16328.8688945247,16140.5781418659,11583.9154460258,97053.3826494513
"SPD",10953.5413209651,5292.00740662077,26820.0745994266,26360.4944270103,30854.0129400745,8136.78355087125,8265.97832795608,2384.17496276938,5916.86801898319,3862.11514571879,9111.62163736297,4135.10360714388,72145.7526752109
"ANO",15161.1952338344,6082.23716387426,27100.6336872136,33738.7270993172,45822.3433734248,17226.3676698714,6259.95889485987,5309.19019728042,5572.85293313121,6925.98257307438,29877.9244886872,10007.997986567,295361.707336463
"KDU-ČSL",76263.718925426,4194.83250180553,2607.38786428168,6067.20573696251,4180.8313464953,3182.40998472968,2017.66725966274,2802.65907394515,2662.72619388103,3184.30882016752,2964.53166039187,2039.87985366755,58128.3265395127
"Ostatní",10405.6205588344,24351.1410242712,26090.919387313,60802.1862625756,41736.2860941188,13606.3290869793,5070.67677162414,10210.91553676,11951.2984994531,5731.94165727966,22853.4517310939,14548.193557729,107236.145857065
"Pribylí",1948.3945331815,2351.77253834447,2051.27191158657,3729.77195081468,2964.4008974097,1518.39683219879,994.946186955969,972.991966622136,1613.91286478916,1231.8241410486,1733.15077751526,779.949580218848,225181.430130567
"Nevoliči",5120.43352744681,8909.10587780663,9328.51749198928,20661.6474172972,14243.2680812685,12119.4651812784,8014.8199637421,3131.23088636049,12604.6803287013,5764.75986213446,15520.820805389,62755.9603806054,5590069.12559816

matn_chart_filtered.csv

"","KDU-ČSL","STAN-TOP","KSČM","ČSSD","ANO","ODS","Úsvit","Zelení","Svobodní","Piráti","Ostatní","Pribylí","Nevoliči"
"ODS",732.719003730076,4947.34618776099,481.86993342288,939.743150910992,3911.17330605676,2495.86050348184,373.397820750348,507.654654856612,744.06072809927,1139.68495866156,987.399192149103,1070.41176668003,11850.6280552996
"KSČM",343.994121372427,314.501510505475,4889.49295943739,1748.80453954296,894.567232652685,288.15164348438,427.908092544658,212.924406819985,211.646632006949,331.278207379345,783.666763999001,269.571956349306,4640.11009942224
"STAN-TOP",710.668771283692,6619.37027587135,318.654343254021,593.29635581102,1815.01856862639,821.394865502065,172.966285287477,777.86959721039,852.334403368722,844.328446093664,554.670963424654,652.547851111981,8706.76735059943
"Piráti",1188.89797384752,4317.28832462172,637.445833866915,2384.10565668124,2748.92692387762,1752.78630302199,510.276637454161,1103.06885883304,1378.2848196337,1514.00711917311,1496.54886521557,1074.05666408793,8998.75632661681
"SPD",1015.60859158216,490.673110311224,2486.74811112614,2444.13599528617,2860.77348946047,754.439777964073,766.418673350514,221.059884202848,548.609971812072,358.093990677161,844.826430739787,383.405387119831,6689.32942470971
"ANO",1405.74081814665,563.942942165003,2512.76145344653,3128.24319615505,4248.63194950522,1597.22289756543,580.421240060714,492.266292763359,516.713011131746,642.174726898539,2770.27090328081,927.938138165419,27385.8361241711
"KDU-ČSL",7071.14584197734,388.943429731491,241.756107815386,562.549233421138,387.645247416888,295.071961452512,187.077415771045,259.861587350418,246.887058741488,295.248020822551,274.870358004549,189.136959862911,5389.63848475451
"Ostatní",964.805566585935,2257.82943747543,2419.14109013448,5637.55784050026,3869.77412106784,1261.5741627031,470.151409803949,946.752583769824,1108.120294701,531.463663029116,2118.96420027948,1348.90351314509,9942.89863609117
"Pribylí",180.654472348902,218.05554253199,190.193227562949,345.823175071181,274.858233705726,140.78523310636,92.2510689488464,90.2154811750684,149.64144686318,114.214311546235,160.697145203877,72.3166573676983,20878.7449103457
"Nevoliči",474.764839125299,826.04923902531,864.936939933322,1915.74085662,1320.63092763041,1123.71265171825,743.131356028287,290.326653018453,1168.70163364187,534.50655571872,1439.08517770318,5818.7111061098,518309.29058799

matn_filtered.csv

"","ODS","KSČM","STAN-TOP","Piráti","SPD","ANO","KDU-ČSL","Ostatní","Pribylí","Nevoliči"
"KDU-ČSL",732.719003730076,343.994121372427,710.668771283692,1188.89797384752,1015.60859158216,1405.74081814665,7071.14584197734,964.805566585935,180.654472348902,474.764839125299
"STAN-TOP",4947.34618776099,314.501510505475,6619.37027587135,4317.28832462172,490.673110311224,563.942942165003,388.943429731491,2257.82943747543,218.05554253199,826.04923902531
"KSČM",481.86993342288,4889.49295943739,318.654343254021,637.445833866915,2486.74811112614,2512.76145344653,241.756107815386,2419.14109013448,190.193227562949,864.936939933322
"ČSSD",939.743150910992,1748.80453954296,593.29635581102,2384.10565668124,2444.13599528617,3128.24319615505,562.549233421138,5637.55784050026,345.823175071181,1915.74085662
"ANO",3911.17330605676,894.567232652685,1815.01856862639,2748.92692387762,2860.77348946047,4248.63194950522,387.645247416888,3869.77412106784,274.858233705726,1320.63092763041
"ODS",2495.86050348184,288.15164348438,821.394865502065,1752.78630302199,754.439777964073,1597.22289756543,295.071961452512,1261.5741627031,140.78523310636,1123.71265171825
"Úsvit",373.397820750348,427.908092544658,172.966285287477,510.276637454161,766.418673350514,580.421240060714,187.077415771045,470.151409803949,92.2510689488464,743.131356028287
"Zelení",507.654654856612,212.924406819985,777.86959721039,1103.06885883304,221.059884202848,492.266292763359,259.861587350418,946.752583769824,90.2154811750684,290.326653018453
"Svobodní",744.06072809927,211.646632006949,852.334403368722,1378.2848196337,548.609971812072,516.713011131746,246.887058741488,1108.120294701,149.64144686318,1168.70163364187
"Piráti",1139.68495866156,331.278207379345,844.328446093664,1514.00711917311,358.093990677161,642.174726898539,295.248020822551,531.463663029116,114.214311546235,534.50655571872
"Ostatní",987.399192149103,783.666763999001,554.670963424654,1496.54886521557,844.826430739787,2770.27090328081,274.870358004549,2118.96420027948,160.697145203877,1439.08517770318
"Pribylí",1070.41176668003,269.571956349306,652.547851111981,1074.05666408793,383.405387119831,927.938138165419,189.136959862911,1348.90351314509,72.3166573676983,5818.7111061098
"Nevoliči",11850.6280552996,4640.11009942224,8706.76735059943,8998.75632661681,6689.32942470971,27385.8361241711,5389.63848475451,9942.89863609117,20878.7449103457,518309.29058799

matp_filtered.csv

"","ODS","KSČM","STAN-TOP","Piráti","SPD","ANO","KDU-ČSL","Ostatní","Pribylí","Nevoliči"
"KDU-ČSL",0.0520064592043492,0.024415793979163,0.0504413919571078,0.0843848373800496,0.072085214818806,0.0997757696179042,0.501891251471172,0.0684793503148509,0.0128223771984457,0.0336975540581516
"STAN-TOP",0.236217827910666,0.015016305887389,0.316050910803636,0.206134851251992,0.023427860499963,0.0269262290949677,0.0185706374012362,0.107803162599095,0.0104113608924747,0.0394408536585805
"KSČM",0.0320328347685222,0.325034431924309,0.0211828985743549,0.0423749141705055,0.1653093206891,0.167038586282426,0.0160710036439132,0.160815069476466,0.0126433043650169,0.057497636105386
"ČSSD",0.0477026980157864,0.0887718040377137,0.0301165662848233,0.121020591709707,0.124067817019602,0.158794070870815,0.0285557986508192,0.286170448756358,0.0175544758919381,0.0972457287624366
"ANO",0.175137618935015,0.0400576407241933,0.0812743403468741,0.123093629047001,0.128101983228572,0.190248609596329,0.0173582861999323,0.173283813409808,0.0123078198865182,0.0591362586257571
"ODS",0.237001282260169,0.0273622299386934,0.0779978032002721,0.166440632705535,0.0716398991514646,0.151668682704912,0.0280193677193535,0.119796236131716,0.0133686480967012,0.106705218091183
"Úsvit",0.086354722652717,0.0989611684885889,0.0400014535817477,0.118010323185514,0.17724761178319,0.13423247919998,0.043264897264349,0.108730668317287,0.0213346597939053,0.171862015732721
"Zelení",0.10356072110498,0.043436231501425,0.158684128357893,0.225024247007964,0.0450958556105361,0.100421520351563,0.0530113397287675,0.193135982001188,0.0184038109292265,0.0592261634064572
"Svobodní",0.10744559250531,0.0305626905425198,0.123080780269852,0.199030298864072,0.0792216565793605,0.0746155972753424,0.0356515608290958,0.160017371075957,0.0216088731932389,0.168765578865252
"Piráti",0.180758914934427,0.0525421423282069,0.13391410723135,0.240128012557194,0.0567952403928884,0.101851661680974,0.0468276004476687,0.0842924128515648,0.0181148789129635,0.0847750286627628
"Ostatní",0.0863790737598725,0.0685562736417637,0.0485233980775658,0.130920205162765,0.07390660753563,0.242347205255954,0.0240460465405082,0.185369976404468,0.0140580128776027,0.12589320074387
"Pribylí",0.0906590807724254,0.0228315369144834,0.0552678793183689,0.0909677872523019,0.032472718482242,0.0785922027750842,0.01601905309248,0.114246083945548,0.00612489687199952,0.492818760575066
"Nevoliči",0.0190282278116926,0.00745049727585171,0.0139802170718304,0.0144490557467289,0.0107408724336692,0.0439726844984699,0.00865399440704843,0.0159650391079063,0.0335244269520894,0.832234984694713

prepare.py

"""Prepare data into table."""

import csv
import json

path = "/home/michal/dev/prechody/2014-2019/"
file1 = "ept2.csv"
file2 = "ept2p.csv"

parties = ['5', '9', '26', '27', '28', '30', '39']

nzast = 1

current_data = "data_2019.csv"
# previous_data = "data_2014.csv"

name4party = 'ESTRANA'  # name in the CzSO file with party number

# parties_prev = ['1', '4', '5', '8', '15', '20', '21', '24', '29']


# ps = ['500054', '500089', '500097', '500119', '500143', '500178', '500186', '500208', '500216', '500224', '538060', '538078', '538124', '538175', '538205', '538213', '538302', '538353', '538361', '538388', '538400', '538531', '538736', '538931', '538949', '539007', '539449', '539465', '539589', '539601', '539635', '539678', '539694', '539724', '539791', '539864', '539899', '547034', '547042', '547051', '547107', '547115', '547140', '547158', '547174', '547271', '547298', '547301', '547310', '547328', '547344', '547361', '547379', '547387', '547395', '547409', '547417']

with open(path + file1) as fin:
    kvt = csv.DictReader(fin, delimiter=';')
    current = {}
    for row in kvt:
        # if row['OBEC'] in ps:
        # if row['KODZASTUP'] == '554782':
            # if not(row['OKRSEK'] in praha2018):
        if row['OBEC'] not in current.keys():
            current[row['OBEC']] = {}
        current[row['OBEC']][row['OKRSEK']] = row


def _n2(n):
    if n < 10:
        return "0" + str(n)
    else:
        return str(n)


len(current)

ps = {}

for obec in current:
    ps[obec] = {}
    for okrsek in current[obec]:
        ps[obec][okrsek] = obec

with open(path + file2) as fin:
    kvhl = csv.DictReader(fin, delimiter=';')
    for row in kvhl:
        current[row['OBEC']][row['OKRSEK']]['HLASY_' + _n2(int(row[name4party]))] = int(row['POC_HLASU']) / nzast

# with open(path + previous_data) as fin:
#     d_previous = csv.DictReader(fin)
#     for row in d_previous:
#         if row['OBEC'] in ps.keys() and row['OKRSEK'] in ps[row['OBEC']].keys():
#             current[row['OBEC']][row['OKRSEK']]['d_previous'] = row

# '500054' in ps.keys()


# praha2018['1001']

n2parties = []
for s in parties:
    n2parties.append('HLASY_' + _n2(int(s)))

#
#
# with open(path + "praha_2014_2017.csv") as fin:
#     dr = csv.DictReader(fin)
#     for row in dr:
#         praha2014[row['okrsek']][row['por_str_hl']] = float(row['poc_hlasu2'])
#         # praha2014[row['okrsek']]['OBEC'] = row['obec']

# k = '1001'

for obec in current:
    for okrsek in current[obec]:
        it = current[obec][okrsek]
        ss = 0
        for s in parties:
            if 'HLASY_' + _n2(int(s)) not in it.keys():
                it['HLASY_' + _n2(int(s))] = 0
            ss += it['HLASY_' + _n2(int(s))]
            celkem = int(it['VOL_SEZNAM'])
            it['ostatni'] = int(it['PL_HL_CELK']) / nzast - ss
            nevoleno = celkem - it['ostatni'] - ss
            it['nevolici'] = celkem - int(it['ODEVZ_OBAL'])
            it['propadlo'] = nevoleno - it['nevolici']


header = ['OBEC', 'OKRSEK', 'HLASY', 'VOLICI', 'HLASY_50'] + n2parties
with open(path + current_data, "w") as fout:
    dw = csv.DictWriter(fout, header)
    dw.writeheader()
    for obec in current:
        for okrsek in current[obec]:
            it = current[obec][okrsek]
            item = {
                'OBEC': it['OBEC'],
                'OKRSEK': it['OKRSEK'],
                'HLASY': int(it['PL_HL_CELK']),
                'VOLICI': int(it['VOL_SEZNAM']),
                # 'HLASY_00': it['propadlo'],
                'HLASY_50': it['ostatni']
            }
            for s in parties:
                item['HLASY_' + _n2(int(s))] = it['HLASY_' + _n2(int(s))]
            dw.writerow(item)