block by michalskop f42018b539662bf64e01

CZ: spatial model president., senate cand., parties 2012-2014

Full Screen

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech senate candidates and political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before elections 2012-2014</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each small solid bubble represents one senate candidate.
      <p>Each empty bubble represents one political party, the size represents election result.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the other parties and the senate candidates were projected into the model.
      <p>Other charts are c1.html, c2.html, c3.html, c4.html, c5.html, c6.html

    
<script type="text/javascript">

d3.csv("all_data_ten_4.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

average_distance.py

import csv

li1 = ['pirati']
li2 = ['kdu-csl']

distances = []
with open("distances.csv") as f:
    csvr = csv.DictReader(f)
    for r in csvr:
        distances.append(r)

meta = {}
with open("all_data.csv") as f:
    csvr = csv.DictReader(f)
    for r in csvr:
        meta[r['voter_id']] = r

s = 0
n = 0
data = []
for r in distances:
    if (meta[r['voter_id1']]['group_id'] in li1) and (meta[r['voter_id2']]['group_id'] in li2):
#    if r['voter_id2'] == 'president_1' and (meta[r['voter_id1']]['group_id'] in li2):
        s += float(r['sum'])
        n += int(r['n'])
        data.append([r['distance'],r['n']])

print(s/n,s,n)

with open("tmp.csv","w") as fout:
    csvw = csv.writer(fout)
    for row in data:
        csvw.writerow(row) 

c1.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0;
              opacity: 0.7;
            }
            #chart {
              padding-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before general elections 2013</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each bubble represents one political party, the size represents election result.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the others were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_1.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

c2.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">
    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:1;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:2;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before general elections 2013</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each bubble represents one political party, the size represents election result.
      <p>Each line represents one question in the VAA (it is its cutting line)
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the others were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_1.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

c3.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech presidential candidates and political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before elections 2013</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each solid bubble represents one presidential candidate, the size represents election result.
      <p>Each empty bubble represents one political party, the size represents election result.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the other parties and the presidential candidates were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_2.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

c4.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech senate candidates and political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before elections 2012-2014</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each small solid bubble represents one senate candidate.
      <p>Each empty bubble represents one political party, the size represents election result.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the other parties and the senate candidates were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_4.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

c5.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplotellipses.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech senate candidates from main parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before elections 2012-2014</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each ellipse represents senate candidates from one political party from elections in 2012 and 2014 (it is 90% prediction interval for the party). Main parties only.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the other parties and the senate candidates were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_5.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
      d3.csv("ellipses.csv", function(ellipses) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        
        //ellipses = [{"x":0.1854215,"y":0.1954918,"rx":0.8353391,"ry":0.4825057,"arc":-39.44572, color:"#660066"}];
        
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected,
          "ellipses": ellipses
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    
      })    
    })
})
</script>
  </body>
</html>

c6.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplotellipses.js"></script>
    <script src="./d3.tips.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/united/bootstrap.min.css">

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0.25;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:0.25;
              opacity: 0.7;
            }
            #chart {
              margin-top:30px;
            }
		</style>
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <h2>Spatial distribution of Czech presidential and senate candidates and political parties based on their answers in VAA <a href="//volebnikalkulacka.cz" class="text-success">VolebniKalkulacka.cz</a> before elections 2012-2014</h2>
        </div>
      </div>
    </nav>
    <div id="chart"></div>
    <div class="alert alert-info">
      <p>Each bigger solid bubble represents one presidential candidate, the size represents election result.
      <p>Each small solid bubble represents one senate candidate.
      <p>Each empty bubble represents one political party, the size represents election result.
      <p>Each line represents one question in the VAA (it is its cutting line)
      <p>Each ellipse represents senate candidates from one political party from elections in 2012 and 2014 (it is 90% prediction interval for the party). Main parties only.
      <p><a href="//bl.ocks.org/michalskop/8514867">W-PCA</a> model is used, the model is estimated using 10 biggest parties, the other parties and the senate candidates were projected into the model.

    
<script type="text/javascript">

d3.csv("all_data_ten_6.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
      d3.csv("ellipses.csv", function(ellipses) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        
        //ellipses = [{"x":0.1854215,"y":0.1954918,"rx":0.8353391,"ry":0.4825057,"arc":-39.44572, color:"#660066"}];
        
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":500,"height":500},
          "lines": linesselected,
          "ellipses": ellipses
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    
      })    
    })
})
</script>
  </body>
</html>

calculate_distances.py

import csv

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

master = []
with open("xap_scaled_rot.csv") as f1:
    i = 0
    csvr1 = csv.reader(f1)
    for r1 in csvr1:
        if i>0:
            master.append(r1)
        i += 1
        
i = 0
data = []
for r1 in master:
    j = 0
    for r2 in master:
        if i > j:
            s = 0
            n = 0
            for k in range(1,len(r1)):
                if is_number(r1[k]) and is_number(r2[k]):
                    s += abs(float(r1[k])-float(r2[k]))/2
                    n += 1
            data.append([r1[0],r2[0],s/n,s,n])
        j += 1
#        print(i,j)
    i += 1
                            
with open("distances.csv","w") as fout:
    csvw = csv.writer(fout)
    csvw.writerow(["voter_id1","voter_id2","distance","sum","n"])
    for row in data:
        csvw.writerow(row)                   
        
        

chart1.html

<!DOCTYPE html>
<html lang="cs">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:0.5;
             opacity: .5;
            }
            .perfect {
              stroke: gray;
              stroke-width:0.5;
              opacity: 0.5;
            }
            #chart {
              margin-top:100px;
            }
		</style>
  </head>
  <body>
    <div id="chart"></div>

    
<script type="text/javascript">

d3.csv("all_data.csv", function(voters) {
    d3.csv("cutting_lines_psp.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":400,"height":400},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

chart1ten.html

<!DOCTYPE html>
<html lang="cs">
  <head>
    <meta charset="utf-8">
    <title>W-PCA Scatterplot Chart</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="WPCA scatter plot">
    <meta name="author" content="Michal Škop">
	
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="./d3.scatterplotwithlineplot.js"></script>
    <script src="./d3.tips.js"></script>

    <style type="text/css">
			
			/* note: we duplicate some of the styles (css, and as attributes of svg elements), so FF displays it correctly, and it is possible to generate png */
			.tick {
			  fill-opacity: 0;
			  stroke: #000000;
			  stroke-width: 1;
			}
			
			.domain {
			    fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
			}
			.axis line {
				fill: none;
				fill-opacity: 0;
				stroke: black;
				stroke-width: 1;
				shape-rendering: crispEdges;
			}
			
			.axis text {
				font-family: sans-serif;
				font-size: 11px;
				stroke: gray;
			}
			circle:hover {
			  fill-opacity: 1;
			}
			.label {
			  font-family: sans-serif;
			  font-size: 15px;
			}

			.d3-tip {
                line-height: 1;
                font-weight: bold;
                padding: 12px;
                background: rgba(0, 0, 0, 0.8);
                color: #fff;
                border-radius: 2px;
                pointer-events: none;
                max-width: 400px;
            }
            /* Creates a small triangle extender for the tooltip */
            .d3-tip:after {
                box-sizing: border-box;
                display: inline;
                font-size: 10px;
                width: 100%;
                line-height: 1;
                color: rgba(0, 0, 0, 0.8);
                position: absolute;
                pointer-events: none;
            }
            /* Northward tooltips */
            .d3-tip:after {
                content: "\25BC";
                margin: -1px 0 0 0;
                top: 100%;
                left: 0;
                text-align: center;
            }
            line {
             stroke:gray;
             stroke-width:1;
             opacity: .3;
            }
            .perfect {
              stroke: gray;
              stroke-width:2;
              opacity: 0.7;
            }
            #chart {
              margin-top:100px;
            }
		</style>
  </head>
  <body>
    <div id="chart"></div>

    
<script type="text/javascript">

d3.csv("all_data_ten_1.csv", function(voters) {
    d3.csv("cutting_lines_ten.csv", function(lines) {
        linesselected = [];
        for (k in lines) {
          if ((parseFloat(lines[k]['loss']) < 1.5) && (parseFloat(lines[k]['cl_beta0']) < 50)) {
              beta = [lines[k]['normal_x'],lines[k]['normal_y']];
              beta0 = lines[k]['cl_beta0'];
              if (beta[1] != 0) {
                lines[k]['a'] = -beta0/beta[1];
                lines[k]['b'] = -beta[0]/beta[1];
              } else {
                lines[k]['a'] = 0;
                lines[k]['b'] = 0;
              }
              //add class for a perfect cut:
              if (lines[k]['loss'] == 0) {
                lines[k]['class'] = 'perfect';
              } else {
                lines[k]['class'] = 'non-perfect';
              }
              lines[k]['name'] = lines[k]["motion:name"];
              linesselected.push(lines[k]);
          }
        }

        spdata = [];
        voters.forEach(function(d) {
          spdata.push({"x":d["wpca:d1"],"y":d["wpca:d2"],"r":d["r"],"color":d["color"],"name":d["name"],"opacity":d["opacity"]})
        });
        var scatterplotwithlineplot = [{
          "data": spdata,
          "margin": {top: 10, right: 10, bottom: 30, left: 30},
          "axes": {"labels":{"x":"DIM 1", "y":"DIM 2"}},
          "minmax":{"x":{'min':-1,'max':1},"y":{'min':-1,'max':1},"r":{'min':0,'max':1},"rrange":{'min':0,'max':100}},
          "size":{"width":400,"height":400},
          "lines": linesselected
        }];

         var svg = d3.select("#chart")
            .append("svg")
            .attr("width",scatterplotwithlineplot[0]['size']['width'])
            .attr("height",scatterplotwithlineplot[0]['size']['height']);
            
        /* Initialize tooltip */
        tip = d3.tip().attr('class', 'd3-tip').html(function(d) { 
          return "<span class=\'stronger\'>" + d["name"] + "</span><br>";
        });

        /* Invoke the tip in the context of your visualization */
        svg.call(tip)

        var sp = d3.scatterplotwithlineplot()
            .data(function(d) {return d.data})
            .margin(function(d) {return d.margin})
            .axes(function(d) {return d.axes})
            .minmax(function(d) {return d.minmax})
            .size(function(d) {return d.size})
            .lines(function(d) {return d.lines})

        var scatter = svg.selectAll(".scatterplot")
            .data(scatterplotwithlineplot)
          .enter()
            .append("svg:g")
            .attr("transform", "translate(" + scatterplotwithlineplot[0].margin.left + "," + scatterplotwithlineplot[0].margin.top + ")")
            .call(sp);
    })
})
</script>
  </body>
</html>

cutting_lines_psp.csv

id,normal_x,normal_y,cl_beta0,loss,motion:name
2,-1.0895605184,-1.7874774452,-0.409384351,2.0597993177,Armáda v zahraničí
3,2.858824173,-0.7021271992,0.0740528148,0.6684917546,Daňová progrese
6,-1.9856576346,-0.0336073275,1.1785596299,0.4221367819,Školné na VŠ
9,1.6500625165,2.5402994233,-0.4573632594,0.4440145789,Zrušení zdravotnických poplatků
10,0.7185340372,0.8080120722,0.5297227756,0.1479300998,Vystoupení z NATO
12,1.9948258467,1.6676777396,-0.4565715533,0.4051624483,Důchodová reforma
13,-0.3043558891,1.6069451172,0.8902842069,0,Vystoupení z EU
15,-1.8997625577,-1.7969121137,-0.2173801745,2.2634296101,Církevní restituce
16,1.5767311851,-2.7881101727,0.3455325806,0,Zavedení eura
18,2.1199658427,-0.3639415849,-1.1139402534,0,Zákon o prokázání nabytí majetku
22,-0.7122041842,-0.4128283819,-0.3599414426,0.6697527425,Poplatek za prázdná média
33,0.3797368619,0.0910697377,-2360.6798105263,0,Zveřejňování platů politiků a úředníků
35,-0.2168889515,-2.5912819717,-0.6267564234,1.0077217686,Protikorupční státní zastupitelství
37,0.5051872011,0.4068718171,0.1757664658,1.0568448599,Zavedení eutanazie
38,-0.4308963023,-0.4677245548,-0.1510060535,1.466152529,Zachování prezidentských milostí
40,1.6201749705,-0.8293202547,-0.5025842556,0.9153265032,Přímá volba prezidenta
43,1.2767959642,-0.8334613707,0.3913074416,0.9198078281,Adopce homosexuálními páry
44,0.7181444179,2.078382798,0.2271990984,2.2167999267,Zákaz stavby mešit
47,-1.0039664314,-0.84638247,-0.576004264,0.245811248,Zákon o vyrovnaném státním rozpočtu
48,1.3088868257,-0.774428373,-0.0485106311,2.4633206908,Rovnoměrné rozmístění státních institucí
49,1.4425796573,-0.7835014033,0.8776057309,0.1136228399,Kvóty pro ženy
50,1.4257779039,-2.5077067934,0.3141055622,0,Zákaz kouření v restauracích
54,2.3432853234,0.8206853362,-0.5248003596,0.560372937,Celostátní referendum
57,0.25951896,1.7661417566,0.6624101648,1.3121046769,Zrušení Senátu
59,2.1655304029,0.2163870165,-0.4767160958,1.6669589921,Lidová iniciativa
72,3.2829249498,-0.2777794433,0.302370041,0.2384178051,Měly by být zavedeny tzv. registrační pokladny.
76,0.2678020437,-0.6084454331,-0.3063780961,0.3659055008,Platnost smluv uzavřených veřejnou správnou by měla být podmíněna jejich zveřejněním v registru smluv.
77,1.0864306239,-0.1659529977,-0.746113929,0.1839079411,Kontrolní pravomoci NKÚ by měly být rozšířeny na samosprávy a obchodní společnosti s vlastnickou účastí veřejné správy.
80,0.2968335973,-1.8151422718,-0.9608286881,0,Účetnictví politických stran včetně smluv a dokladů by mělo být pravidelně zveřejňováno na internetu.
81,1.3153915221,-2.0487874992,-0.0029664509,1.1832452918,Povinné přidávání biosložek do paliv by mělo být i nadále zachováno.
82,2.585981981,0.1874601574,-0.7451542037,0,Sazba DPH na základní potraviny by měla být nejvýše 10 %.
83,-2.6836891021,-0.3537693825,0.7848518362,0,Národní podnik Budějovický Budvar by měl být privatizován.
84,-0.6899949946,-1.2201289273,0.0015530395,2.6574605368,Soudci by nadále měli být jmenováni do funkce doživotně.
85,2.2000058459,-0.3991894495,-0.7460606575,1.2822761287,Finanční podpora místo školek
86,1.5030124592,0.190843793,-0.6218209241,1.7401237058,Obchodní řetězce by měly nabízet povinně předepsaný podíl potravin od českých výrobců.
87,0.946177312,0.5476554965,-0.1736385439,1.4974957178,Spotřební daň z pohoných hmot by se měla snížit alespoň o 2 Kč/litr.
88,2.5941698968,-0.3181397875,-0.3342821646,0.8410983532,Regulace ČNB nebankovních společností
89,1.0629454636,-1.0267090805,-0.5068865866,1.306851903,Daňové zvýhodnění pro starší lidi
90,0.9502446112,-0.0244179382,0.4564959465,0.9375346503,Spotřební daň na alkohol by se měla zvýšit.

cutting_lines_ten.csv

,normal_x,normal_y,cl_beta0,loss,motion:name
2,0.387203485,1.653567751,0.2262220402,0.1080728926,Armáda v zahraničí
3,-1.4383536766,0.5658304435,-0.1192870994,0.646509282,Daňová progrese
6,1.1079983829,-0.3383725325,-0.7099132901,0.3884413667,Školné na VŠ
9,-0.7317462198,-1.8291834039,-0.3803369219,0.1125535031,Zrušení zdravotnických poplatků
10,-0.4757468355,-0.3828744801,-0.4085634698,0,Vystoupení z NATO
12,-1.1874902188,-1.0999196098,0.2284742597,1.0656287254,Důchodová reforma
13,0.682780333,-0.7926673505,-0.881653224,0,Vystoupení z EU
15,0.0561319092,1.9750720865,0.5209197447,0,Církevní restituce
16,-1.8969382269,1.0078213289,0.3585907041,0.0975226719,Zavedení eura
18,-1.4615330955,0.3268646241,0.7158384842,0,Zákon o prokázání nabytí majetku
22,0.140925252,-0.1178094667,0.1027905894,0.1296643579,Poplatek za prázdná média
33,-0.46633172,-0.3250100841,2360.6798105263,0,Zveřejňování platů politiků a úředníků
35,-0.484390216,1.0714390332,0.8536981284,0,Protikorupční státní zastupitelství
37,0.0480310536,-1.4849706795,0.0914309516,0,Zavedení eutanazie
38,-0.6750579955,0.9669047593,0.1124368111,0.739608605,Zachování prezidentských milostí
40,-0.682780333,0.7926673505,0.7301583207,0,Přímá volba prezidenta
43,-1.1949403733,-1.4460152236,-0.2564261257,0,Adopce homosexuálními páry
44,0.46633172,0.3250100841,-5278.6403435454,0,Zákaz stavby mešit
47,0.5548088232,-0.1292196575,0.4085635066,0,Zákon o vyrovnaném státním rozpočtu
48,-1.4373629777,-0.1898862499,0.2632822771,0.8048254618,Rovnoměrné rozmístění státních institucí
49,-1.4941038407,-0.0056276494,-1.0275955103,0,Kvóty pro ženy
50,-1.8491306036,0.5804938944,-0.3001133059,0,Zákaz kouření v restauracích
54,-1.0862985157,-1.8227528847,0.5040000726,0,Celostátní referendum
57,-0.5152755302,-0.3212849323,-0.3481357237,0.1556995638,Zrušení Senátu
59,-2.0095682114,-0.9979828616,0.4056635805,0.0291025904,Lidová iniciativa
72,-2.0518063001,0.554681227,-0.6188331629,0,Měly by být zavedeny tzv. registrační pokladny.
76,-0.454836184,-0.5978367361,0.5577143362,0,Platnost smluv uzavřených veřejnou správnou by měla být podmíněna jejich zveřejněním v registru smluv.
77,-1.4829663985,-0.0184370213,0.8708709834,0,Kontrolní pravomoci NKÚ by měly být rozšířeny na samosprávy a obchodní společnosti s vlastnickou účastí veřejné správy.
80,-0.4580229715,0.5317374238,2360.6798105263,0,Účetnictví politických stran včetně smluv a dokladů by mělo být pravidelně zveřejňováno na internetu.
81,-1.4213505141,1.2602798567,0.1401109614,0,Povinné přidávání biosložek do paliv by mělo být i nadále zachováno.
82,-1.561059382,-0.6271549404,0.6354144674,0,Sazba DPH na základní potraviny by měla být nejvýše 10 %.
83,1.9192904896,0.1344678585,-0.7378328044,0,Národní podnik Budějovický Budvar by měl být privatizován.
84,-0.2254760395,-0.8225533664,0.0559737647,0.525940964,Soudci by nadále měli být jmenováni do funkce doživotně.
85,-1.4501986729,-0.3868877533,0.4684139848,0.766553969,Finanční podpora místo školek
86,-2.5634651845,0.4685492641,-0.1958030125,0,Obchodní řetězce by měly nabízet povinně předepsaný podíl potravin od českých výrobců.
87,-0.7492864173,0.2598188538,0.137822455,0.7252315778,Spotřební daň z pohoných hmot by se měla snížit alespoň o 2 Kč/litr.
88,-2.1588920405,0.4811199951,0.3680732334,0.0457674052,Regulace ČNB nebankovních společností
89,0.0785559389,1.2401474039,0.6115178504,0.1533025832,Daňové zvýhodnění pro starší lidi
90,-0.4799846936,-0.5232260728,-0.2876314109,0.0072653199,Spotřební daň na alkohol by se měla zvýšit.

d3.scatterplotwithlineplot.js

/* requires D3 + https://github.com/Caged/d3-tip */
d3.scatterplotwithlineplot = function() {
  unit_circle = true;
  function scatterplotwithlineplot(selection) {
    selection.each(function(d, i) {
      //options
      var data = (typeof(data) === "function" ? data(d) : d.data),
          lines = (typeof(lines) === "function" ? lines(d) : d.lines),
          margin = (typeof(margin) === "function" ? margin(d) : d.margin),
          axes = (typeof(axes) === "function" ? axes(d) : d.axes),
          minmax = (typeof(minmax) === "function" ? minmax(d) : d.minmax),
          size = (typeof(size) === "function" ? size(d) : d.size),
          unit_circle_val = (typeof(unit_circle) === "function" ? unit_circle(d) : unit_circle);
      
      // chart sizes
      var width = size['width'] - margin.left - margin.right,
          height = size['height'] - margin.top - margin.bottom;
      
      //scales
      var xScale = d3.scale.linear()
			 .domain([minmax['x']['min'], minmax['x']['max']])
			 .range([0, width])

      var yScale = d3.scale.linear()
			 .domain([minmax['y']['min'], minmax['y']['max']])
			 .range([height, 0])

      var rScale = d3.scale.linear()
		     .domain([minmax['r']['min'],minmax['r']['max']])
		     .range([minmax['rrange']['min'],minmax['rrange']['max']]);

      //axes
      var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom");
        //.ticks(5);
        //.tickSize(16, 0);  
      var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left");
        //.ticks(5); 
      

      var element = d3.select(this);
      
		//Create X axis
      element.append("g")
			.attr("class", "axis x-axis")
			.attr("transform", "translate(0," + height + ")")
			.call(xAxis);
		
		//Create Y axis
      element.append("g")
			.attr("class", "axis y-axis")
			.call(yAxis);
      
      limits = {"x":[minmax["x"]["min"],minmax["x"]["max"]],"y":[minmax["y"]["min"],minmax["y"]["max"]]}
      for (k in lines) {
        ps = linecross(lines[k],limits);
        if (ps.length == 2) {
          lines[k].x1 = ps[0][0];
          lines[k].y1 = ps[0][1];
          lines[k].x2 = ps[1][0];
          lines[k].y2 = ps[1][1];
        }
        way = get_sign(lines[k].b,lines[k].n1,lines[k].n2);
        lines[k].path =[corners(lines[k],limits,way),corners(lines[k],limits,-1*way)];
      }
      
      //ellipse ~ unit_circle
      if (unit_circle_val) {
          element.selectAll(".ellipse")
              .data([0])
            .enter()
              .append("ellipse")
                .attr("cx", xScale(0))
                .attr("cy", yScale(0))
                .attr("rx", Math.abs(xScale(1)-xScale(0)))
                .attr("ry", Math.abs(yScale(1)-yScale(0)))
                .attr("fill-opacity",0)
                .attr("stroke","red")
                .style("stroke-dasharray", ("10,3"));
      }
      
      //lines
      var line = element.selectAll ('.line')
         .data(lines)
         .enter()
            .append("line")
         .attr("x1",function(d) {return xScale(d.x1)})
         .attr("y1",function(d) {return yScale(d.y1)})
         .attr("x2",function(d) {return xScale(d.x2)})
         .attr("y2",function(d) {return yScale(d.y2)})
         .attr("id", function (d, i) {return "q-" + i;})
         .attr("class", function(d) {
		   		if (typeof(d['class'] != 'undefined')) return d['class'];
		   		else return 'line';
		   })
		    //putting it here and not in css, because it is used for generating png:
		 .attr("stroke","gray")
		 .attr("stroke-width","1")
		 .attr("opacity", 0.15)
		 
         .on('mouseover', tip.show)
         .on('mouseout', tip.hide);
      
      //points
      element.selectAll(".circle")
        .data(data)
		   .enter()
		 .append("circle")
		   .attr("cx", function(d) {
		   		return xScale(d.x);
		   })
		   .attr("cy", function(d) {
		   		return yScale(d.y);
		   })
		   .attr("r", function(d) {
		        if ((typeof(d['r']) != 'undefined') && (d['r'] != ''))
		            return rScale(d.r);
		   		else return rScale(0.075);
		   })
		   .attr("class", function(d) {
		   		if ((typeof(d['class']) != 'undefined') && (d['class'] != ''))
		   		     return d['class'];
		   		else return 'circle';
		   })
		   .attr("fill",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#eee";
    	   })
		   .attr("stroke",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#bbb";
    	   })
    	   .attr("stroke-width",function(d) {
		        if ((typeof(d['r']) != 'undefined') && (d['r'] != ''))
		            return Math.max(d.r*5,1);
		   		else return 1;
    	   })
		   .attr("fill-opacity",function(d) {
		       if ((typeof(d['opacity']) != 'undefined') && (d['opacity'] != ''))
    		     return d.opacity;
    		   else
    		     return 1;
    	   })
		   .on('mouseover', tip.show)
           .on('mouseout', tip.hide);
     
	
      //axis labels
	  element.append("text")
			.attr("class", "x-label label")
			.attr("text-anchor", "end")
			.attr("x", width)
			.attr("y", height-5)
			.text(axes['labels']['x']);
	  element.append("text")
			.attr("class", "y label")
			.attr("text-anchor", "end")
			.attr("y", 5)
			.attr("x", 0)
			.attr("dy", ".75em")
			.attr("transform", "rotate(-90)")
			.text(axes['labels']['y']);
			 
	    
	  // putting it here and not in css, because it is used for generating png: 
	  element.selectAll(".domain")
	        	.attr("fill","none")
				.attr("fill-opacity",0)
				.attr("stroke","black")
				.attr("stroke-width",1);
      element.selectAll(".tick")
                .attr("fill-opacity",0)
                .attr("stroke","#000")
                .attr("stroke-width",1);
      element.selectAll("text")
                .attr("font-family","sans-serif")
                .attr("font-size",11)
      element.selectAll(".label")
                .attr("font-size",15)
                .attr("font-weight","bold")
                //convert dy("0.71em") to dy("10"), inkscape feature https://www.ruby-forum.com/topic/5505193 :
      element.selectAll("text")
                .attr("dy",function(d) {
                    if (d3.select(this).attr("dy")) {
                        em = parseFloat(d3.select(this).attr("dy").replace("em",""));
                        if (d3.select(this).attr("font-size"))
                            px = parseFloat(d3.select(this).attr("font-size"));
                        else
                            px = 11;
                        return em*px + "px";
                    } else {
                        return 0;
                    }
                })
    });
  }
  scatterplotwithlineplot.data = function(value) {
    if (!arguments.length) return value;
    data = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.lines = function(value) {
    if (!arguments.length) return value;
    lines = value;
    return scatterplotwithlineplot;
  };    
  scatterplotwithlineplot.margin = function(value) {
    if (!arguments.length) return value;
    margin = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.axes = function(value) {
    if (!arguments.length) return value;
    axes = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.minmax = function(value) {
    if (!arguments.length) return value;
    minmax = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.size = function(value) {
    if (!arguments.length) return value;
    size = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.unit_circle = function(value) {
    if (!arguments.length) return value;
    unit_circle = value;
    return scatterplotwithlineplot;
  };
  return scatterplotwithlineplot;
  
  
    function corners(l,e,o) {
      //l = {"a":0,"b":1}  //line, a and slope, i.e., y=a+bx
      //e = {"x": [-10,10], "y": [-10,10]} //limits
      //o = 1 //orientation -1 or 1

      //crossing x0, x1  
      //crossing y0, y1
      outp = linecross (l,e);
      
      out = [];

      //vertices
      for (i=0;i<=1;i++){
        for (j=0;j<=1;j++){
          if (o*(l.a+l.b*e.x[i]-e.y[j]) > 0)
            outp.push([e.x[i],e.y[j]]);
        }
      }
      //sort the outps, anticlockwise
      if (outp.length > 0) {
        mid = [0,0];
        for (i in outp) {
          mid[0] += outp[i][0];
          mid[1] += outp[i][1];
        }
        mid[0] = mid[0] / outp.length;
        mid[1] = mid[1] / outp.length;
        for (i in outp) {
          p = outp[i][1] - mid[1];
          q = outp[i][0] - mid[0];
          if (q != 0)
            outp[i][2] = Math.atan(p/q) + (q<0 ? Math.PI : 0);
          else
            outp[i][2] = Math.PI/2 + Math.PI*sign(p);
        }
        outp = outp.sort(function(w,z) {
          return w[2] > z[2];
        });
        for (i in outp) {
          outp[i].splice(2,1);
          out.push({"x":outp[i][0],"y":outp[i][1]});
        }
      }
      return out;
    }
  
  function linecross (l,e) {
      out = [];
      //crossing x0, x1
      for (i=0;i<=1;i++){
        Y = l.a + l.b*e.x[i];
        if ((Y > e.y[0]) && (Y < e.y[1]))
          out.push([e.x[i],Y]);
      }
      //crossing y0, y1
      for (j=0;j<=1;j++){
        if (l.b != 0) {
          X = (e.y[j] - l.a)/l.b;
          if ((X > e.x[0]) && (X < e.x[1]))
            out.push([X,e.y[j]]);
        }
      }
      return out;
    }

    function get_sign(b,d1,d2) {
      t = b*d1-d2;
      if (t > 0) return 1;
      if (t < 0) return -1;
      return 0;
    }
  
}

d3.scatterplotwithlineplotellipses.js

/* requires D3 + https://github.com/Caged/d3-tip */
d3.scatterplotwithlineplot = function() {
  unit_circle = true;
  function scatterplotwithlineplot(selection) {
    selection.each(function(d, i) {
      //options
      var data = (typeof(data) === "function" ? data(d) : d.data),
          lines = (typeof(lines) === "function" ? lines(d) : d.lines),
          margin = (typeof(margin) === "function" ? margin(d) : d.margin),
          axes = (typeof(axes) === "function" ? axes(d) : d.axes),
          minmax = (typeof(minmax) === "function" ? minmax(d) : d.minmax),
          size = (typeof(size) === "function" ? size(d) : d.size),
          unit_circle_val = (typeof(unit_circle) === "function" ? unit_circle(d) : unit_circle),
          ellipses = (typeof(ellipses) === "function" ? ellipses(d) : d.ellipses);
      
      // chart sizes
      var width = size['width'] - margin.left - margin.right,
          height = size['height'] - margin.top - margin.bottom;
      
      //scales
      var xScale = d3.scale.linear()
			 .domain([minmax['x']['min'], minmax['x']['max']])
			 .range([0, width])

      var yScale = d3.scale.linear()
			 .domain([minmax['y']['min'], minmax['y']['max']])
			 .range([height, 0])

      var rScale = d3.scale.linear()
		     .domain([minmax['r']['min'],minmax['r']['max']])
		     .range([minmax['rrange']['min'],minmax['rrange']['max']]);

      //axes
      var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom");
        //.ticks(5);
        //.tickSize(16, 0);  
      var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left");
        //.ticks(5); 
      

      var element = d3.select(this);
      
		//Create X axis
      element.append("g")
			.attr("class", "axis x-axis")
			.attr("transform", "translate(0," + height + ")")
			.call(xAxis);
		
		//Create Y axis
      element.append("g")
			.attr("class", "axis y-axis")
			.call(yAxis);
      
      limits = {"x":[minmax["x"]["min"],minmax["x"]["max"]],"y":[minmax["y"]["min"],minmax["y"]["max"]]}
      for (k in lines) {
        ps = linecross(lines[k],limits);
        if (ps.length == 2) {
          lines[k].x1 = ps[0][0];
          lines[k].y1 = ps[0][1];
          lines[k].x2 = ps[1][0];
          lines[k].y2 = ps[1][1];
        }
        way = get_sign(lines[k].b,lines[k].n1,lines[k].n2);
        lines[k].path =[corners(lines[k],limits,way),corners(lines[k],limits,-1*way)];
      }
      
      //ellipse ~ unit_circle
      if (unit_circle_val) {
          element.selectAll(".ellipse")
              .data([0])
            .enter()
              .append("ellipse")
                .attr("cx", xScale(0))
                .attr("cy", yScale(0))
                .attr("rx", Math.abs(xScale(1)-xScale(0)))
                .attr("ry", Math.abs(yScale(1)-yScale(0)))
                .attr("fill-opacity",0)
                .attr("stroke","red")
                .style("stroke-dasharray", ("10,3"));
      }
      
      //lines
      var line = element.selectAll ('.line')
         .data(lines)
         .enter()
            .append("line")
         .attr("x1",function(d) {return xScale(d.x1)})
         .attr("y1",function(d) {return yScale(d.y1)})
         .attr("x2",function(d) {return xScale(d.x2)})
         .attr("y2",function(d) {return yScale(d.y2)})
         .attr("id", function (d, i) {return "q-" + i;})
         .attr("class", function(d) {
		   		if (typeof(d['class'] != 'undefined')) return d['class'];
		   		else return 'line';
		   })
		    //putting it here and not in css, because it is used for generating png:
		 .attr("stroke","gray")
		 .attr("stroke-width","1")
		 .attr("opacity", 0.15)
		 
         .on('mouseover', tip.show)
         .on('mouseout', tip.hide);
      
      //ellipses
      var ellipse = element.selectAll('.ellipse')
        .data(ellipses)
        .enter()
            .append("ellipse")
            .attr("cx", function(d) {
		   		return xScale(d.x);
		    })
		    .attr("cy", function(d) {
		   		return yScale(d.y);
		    })
		    .attr("rx", function(d) {
		   		return  Math.abs(xScale(d.rx) - xScale(0));
		    })
		    .attr("ry", function(d) {
		   		return  Math.abs(yScale(d.ry) - yScale(0));
		    })
		    .attr("transform", function(d) {
		        return "rotate("+d.arc+","+xScale(d.x)+","+yScale(d.y)+")";
		    })
		    .attr("fill",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#eee";
    	   })
		   .attr("stroke",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#bbb";
    	   })
    	   .attr("stroke-width",function(d) {
		        if ((typeof(d['width']) != 'undefined') && (d['width'] != ''))
		            return Math.max(d.width*d.width*16,1);
		   		else return 2;
    	   })
		   .attr("fill-opacity",function(d) {
		       if ((typeof(d['opacity']) != 'undefined') && (d['opacity'] != ''))
    		     return d.opacity;
    		   else
    		     return 0.01;
    	   })
    	   .on('mouseover', tip.show)
           .on('mouseout', tip.hide);;
      
      //points
      element.selectAll(".circle")
        .data(data)
		   .enter()
		 .append("circle")
		   .attr("cx", function(d) {
		   		return xScale(d.x);
		   })
		   .attr("cy", function(d) {
		   		return yScale(d.y);
		   })
		   .attr("r", function(d) {
		        if ((typeof(d['r']) != 'undefined') && (d['r'] != ''))
		            return rScale(d.r);
		   		else return rScale(0.075);
		   })
		   .attr("class", function(d) {
		   		if ((typeof(d['class']) != 'undefined') && (d['class'] != ''))
		   		     return d['class'];
		   		else return 'circle';
		   })
		   .attr("fill",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#eee";
    	   })
		   .attr("stroke",function(d) {
		       if ((typeof(d['color']) != 'undefined') && (d['color'] != ''))
    		     return d.color;
    		   else
    		     return "#bbb";
    	   })
    	   .attr("stroke-width",function(d) {
		        if ((typeof(d['r']) != 'undefined') && (d['r'] != ''))
		            return Math.max(d.r*5,1);
		   		else return 1;
    	   })
		   .attr("fill-opacity",function(d) {
		       if ((typeof(d['opacity']) != 'undefined') && (d['opacity'] != ''))
    		     return d.opacity;
    		   else
    		     return 1;
    	   })
		   .on('mouseover', tip.show)
           .on('mouseout', tip.hide);
     
	
      //axis labels
	  element.append("text")
			.attr("class", "x-label label")
			.attr("text-anchor", "end")
			.attr("x", width)
			.attr("y", height-5)
			.text(axes['labels']['x']);
	  element.append("text")
			.attr("class", "y label")
			.attr("text-anchor", "end")
			.attr("y", 5)
			.attr("x", 0)
			.attr("dy", ".75em")
			.attr("transform", "rotate(-90)")
			.text(axes['labels']['y']);
			 
	    
	  // putting it here and not in css, because it is used for generating png: 
	  element.selectAll(".domain")
	        	.attr("fill","none")
				.attr("fill-opacity",0)
				.attr("stroke","black")
				.attr("stroke-width",1);
      element.selectAll(".tick")
                .attr("fill-opacity",0)
                .attr("stroke","#000")
                .attr("stroke-width",1);
      element.selectAll("text")
                .attr("font-family","sans-serif")
                .attr("font-size",11)
      element.selectAll(".label")
                .attr("font-size",15)
                .attr("font-weight","bold")
                //convert dy("0.71em") to dy("10"), inkscape feature https://www.ruby-forum.com/topic/5505193 :
      element.selectAll("text")
                .attr("dy",function(d) {
                    if (d3.select(this).attr("dy")) {
                        em = parseFloat(d3.select(this).attr("dy").replace("em",""));
                        if (d3.select(this).attr("font-size"))
                            px = parseFloat(d3.select(this).attr("font-size"));
                        else
                            px = 11;
                        return em*px + "px";
                    } else {
                        return 0;
                    }
                })
    });
  }
  scatterplotwithlineplot.data = function(value) {
    if (!arguments.length) return value;
    data = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.lines = function(value) {
    if (!arguments.length) return value;
    lines = value;
    return scatterplotwithlineplot;
  };    
  scatterplotwithlineplot.margin = function(value) {
    if (!arguments.length) return value;
    margin = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.axes = function(value) {
    if (!arguments.length) return value;
    axes = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.minmax = function(value) {
    if (!arguments.length) return value;
    minmax = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.size = function(value) {
    if (!arguments.length) return value;
    size = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.unit_circle = function(value) {
    if (!arguments.length) return value;
    unit_circle = value;
    return scatterplotwithlineplot;
  };
  scatterplotwithlineplot.ellipses = function(value) {
    if (!arguments.length) return value;
    ellipses = value;
    return scatterplotwithlineplot;
  };
  return scatterplotwithlineplot;
  
  
    function corners(l,e,o) {
      //l = {"a":0,"b":1}  //line, a and slope, i.e., y=a+bx
      //e = {"x": [-10,10], "y": [-10,10]} //limits
      //o = 1 //orientation -1 or 1

      //crossing x0, x1  
      //crossing y0, y1
      outp = linecross (l,e);
      
      out = [];

      //vertices
      for (i=0;i<=1;i++){
        for (j=0;j<=1;j++){
          if (o*(l.a+l.b*e.x[i]-e.y[j]) > 0)
            outp.push([e.x[i],e.y[j]]);
        }
      }
      //sort the outps, anticlockwise
      if (outp.length > 0) {
        mid = [0,0];
        for (i in outp) {
          mid[0] += outp[i][0];
          mid[1] += outp[i][1];
        }
        mid[0] = mid[0] / outp.length;
        mid[1] = mid[1] / outp.length;
        for (i in outp) {
          p = outp[i][1] - mid[1];
          q = outp[i][0] - mid[0];
          if (q != 0)
            outp[i][2] = Math.atan(p/q) + (q<0 ? Math.PI : 0);
          else
            outp[i][2] = Math.PI/2 + Math.PI*sign(p);
        }
        outp = outp.sort(function(w,z) {
          return w[2] > z[2];
        });
        for (i in outp) {
          outp[i].splice(2,1);
          out.push({"x":outp[i][0],"y":outp[i][1]});
        }
      }
      return out;
    }
  
  function linecross (l,e) {
      out = [];
      //crossing x0, x1
      for (i=0;i<=1;i++){
        Y = l.a + l.b*e.x[i];
        if ((Y > e.y[0]) && (Y < e.y[1]))
          out.push([e.x[i],Y]);
      }
      //crossing y0, y1
      for (j=0;j<=1;j++){
        if (l.b != 0) {
          X = (e.y[j] - l.a)/l.b;
          if ((X > e.x[0]) && (X < e.x[1]))
            out.push([X,e.y[j]]);
        }
      }
      return out;
    }

    function get_sign(b,d1,d2) {
      t = b*d1-d2;
      if (t > 0) return 1;
      if (t < 0) return -1;
      return 0;
    }
  
}

d3.tips.js

// d3.tip
// Copyright (c) 2013 Justin Palmer
//
// Tooltips for d3.js SVG visualizations

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module with d3 as a dependency.
    define(['d3'], factory)
  } else if (typeof module === 'object' && module.exports) {
    // CommonJS
    module.exports = function(d3) {
      d3.tip = factory(d3)
      return d3.tip
    }
  } else {
    // Browser global.
    root.d3.tip = factory(root.d3)
  }
}(this, function (d3) {

  // Public - contructs a new tooltip
  //
  // Returns a tip
  return function() {
    var direction = d3_tip_direction,
        offset    = d3_tip_offset,
        html      = d3_tip_html,
        node      = initNode(),
        svg       = null,
        point     = null,
        target    = null

    function tip(vis) {
      svg = getSVGNode(vis)
      point = svg.createSVGPoint()
      document.body.appendChild(node)
    }

    // Public - show the tooltip on the screen
    //
    // Returns a tip
    tip.show = function() {
      var args = Array.prototype.slice.call(arguments)
      if(args[args.length - 1] instanceof SVGElement) target = args.pop()

      var content = html.apply(this, args),
          poffset = offset.apply(this, args),
          dir     = direction.apply(this, args),
          nodel   = d3.select(node),
          i       = directions.length,
          coords,
          scrollTop  = document.documentElement.scrollTop || document.body.scrollTop,
          scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft

      nodel.html(content)
        .style({ opacity: 1, 'pointer-events': 'all' })

      while(i--) nodel.classed(directions[i], false)
      coords = direction_callbacks.get(dir).apply(this)
      nodel.classed(dir, true).style({
        top: (coords.top +  poffset[0]) + scrollTop + 'px',
        left: (coords.left + poffset[1]) + scrollLeft + 'px'
      })

      return tip
    }

    // Public - hide the tooltip
    //
    // Returns a tip
    tip.hide = function() {
      var nodel = d3.select(node)
      nodel.style({ opacity: 0, 'pointer-events': 'none' })
      return tip
    }

    // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
    //
    // n - name of the attribute
    // v - value of the attribute
    //
    // Returns tip or attribute value
    tip.attr = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).attr(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.attr.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
    //
    // n - name of the property
    // v - value of the property
    //
    // Returns tip or style property value
    tip.style = function(n, v) {
      if (arguments.length < 2 && typeof n === 'string') {
        return d3.select(node).style(n)
      } else {
        var args =  Array.prototype.slice.call(arguments)
        d3.selection.prototype.style.apply(d3.select(node), args)
      }

      return tip
    }

    // Public: Set or get the direction of the tooltip
    //
    // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
    //     sw(southwest), ne(northeast) or se(southeast)
    //
    // Returns tip or direction
    tip.direction = function(v) {
      if (!arguments.length) return direction
      direction = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: Sets or gets the offset of the tip
    //
    // v - Array of [x, y] offset
    //
    // Returns offset or
    tip.offset = function(v) {
      if (!arguments.length) return offset
      offset = v == null ? v : d3.functor(v)

      return tip
    }

    // Public: sets or gets the html value of the tooltip
    //
    // v - String value of the tip
    //
    // Returns html value or tip
    tip.html = function(v) {
      if (!arguments.length) return html
      html = v == null ? v : d3.functor(v)

      return tip
    }

    function d3_tip_direction() { return 'n' }
    function d3_tip_offset() { return [0, 0] }
    function d3_tip_html() { return ' ' }

    var direction_callbacks = d3.map({
      n:  direction_n,
      s:  direction_s,
      e:  direction_e,
      w:  direction_w,
      nw: direction_nw,
      ne: direction_ne,
      sw: direction_sw,
      se: direction_se
    }),

    directions = direction_callbacks.keys()

    function direction_n() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.n.y - node.offsetHeight,
        left: bbox.n.x - node.offsetWidth / 2
      }
    }

    function direction_s() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.s.y,
        left: bbox.s.x - node.offsetWidth / 2
      }
    }

    function direction_e() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.e.y - node.offsetHeight / 2,
        left: bbox.e.x
      }
    }

    function direction_w() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.w.y - node.offsetHeight / 2,
        left: bbox.w.x - node.offsetWidth
      }
    }

    function direction_nw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.nw.y - node.offsetHeight,
        left: bbox.nw.x - node.offsetWidth
      }
    }

    function direction_ne() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.ne.y - node.offsetHeight,
        left: bbox.ne.x
      }
    }

    function direction_sw() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.sw.y,
        left: bbox.sw.x - node.offsetWidth
      }
    }

    function direction_se() {
      var bbox = getScreenBBox()
      return {
        top:  bbox.se.y,
        left: bbox.e.x
      }
    }

    function initNode() {
      var node = d3.select(document.createElement('div'))
      node.style({
        position: 'absolute',
        top: 0,
        opacity: 0,
        'pointer-events': 'none',
        'box-sizing': 'border-box'
      })

      return node.node()
    }

    function getSVGNode(el) {
      el = el.node()
      if(el.tagName.toLowerCase() === 'svg')
        return el

      return el.ownerSVGElement
    }

    // Private - gets the screen coordinates of a shape
    //
    // Given a shape on the screen, will return an SVGPoint for the directions
    // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
    // sw(southwest).
    //
    //    +-+-+
    //    |   |
    //    +   +
    //    |   |
    //    +-+-+
    //
    // Returns an Object {n, s, e, w, nw, sw, ne, se}
    function getScreenBBox() {
      var targetel   = target || d3.event.target;

      while ('undefined' === typeof targetel.getScreenCTM && 'undefined' === targetel.parentNode) {
          targetel = targetel.parentNode;
      }

      var bbox       = {},
          matrix     = targetel.getScreenCTM(),
          tbbox      = targetel.getBBox(),
          width      = tbbox.width,
          height     = tbbox.height,
          x          = tbbox.x,
          y          = tbbox.y

      point.x = x
      point.y = y
      bbox.nw = point.matrixTransform(matrix)
      point.x += width
      bbox.ne = point.matrixTransform(matrix)
      point.y += height
      bbox.se = point.matrixTransform(matrix)
      point.x -= width
      bbox.sw = point.matrixTransform(matrix)
      point.y -= height / 2
      bbox.w  = point.matrixTransform(matrix)
      point.x += width
      bbox.e = point.matrixTransform(matrix)
      point.x -= width / 2
      point.y -= height / 2
      bbox.n = point.matrixTransform(matrix)
      point.y += height
      bbox.s = point.matrixTransform(matrix)

      return bbox
    }

    return tip
  };

}));

ellipse.csv

-0.13243554,-0.1522600828
-0.68471886,-0.0010261919
-0.8835911676,-0.0311023209
-0.3958130732,-0.0230340191
-0.3057725127,0.1671418131
0.0328197225,-0.2313651234
-0.5129676429,-0.4630385507
-0.5076763305,-0.2655502177
-0.7689238121,-0.0134425348
0.358315118,-0.6467933835
-0.5106901927,0.561099789
-0.7836498369,0.0939925745
-0.0931548484,-0.2286317538
-0.4075256861,0.2846337035
-0.5034264454,-0.0374879333
-0.0554032504,-0.4082006321
0.3845995997,0.3844354734
-0.2604025281,-0.4245434299
0.5157953818,-0.249011738
-0.4362793017,-0.3062261803
0.0851092558,-0.5859874624
-0.6809561137,-0.3432697311
-0.5816362422,-0.1194431578

ellipse.r

# calculates prediction interval (ellipse) for 2d scatterplot
d = read.csv("/home/michal/dev/cz-positions/psp_senat_president/chart/ellipse.csv",header=F)
m = apply(d,2,mean)
d0 = t(t(d) - m)
cd0 = cov(d0)
ed0 = eigen(cd0)
dr = t(t(ed0$vectors) %*% t(d0))
sd = apply(dr,2,sd)
axeslen = 1.96*sd
rot = -atan(ed0$vectors[2,1]/ed0$vectors[1,1])/pi*180
m   #mean
axeslen #ellipse axes
rot #ellipse rotation

ellipse.txt

cl = CuttingLines$normals[,1:2]
cl = cbind(cl,CuttingLines$parameters$Loss)
cl = CuttingLines$normals[,1:2]
cl = cbind(cl,CuttingLines$parameters$Parameter)
cl = cbind(cl,CuttingLines$parameters$Loss)
dimnames(cl)[[2]] = c("normal_x","normal_y","cl_beta0","loss")
write.csv(cl,"/home/michal/dev/cz-positions/psp_senat_president/cutting_lines_psp.csv")


d = read.csv("/home/michal/dev/cz-positions/psp_senat_president/chart/ellipse.csv",header=F)
m = apply(d,2,mean)
d0 = t(t(d) - m)
cd0 = cov(d0)
ed0 = eigen(cd0)
dr = t(t(ed0$vectors) %*% t(d0))
    #eigen(dr)
sd = apply(dr,2,sd)
axeslen = 1.96*sd
rot = -atan(ed0$vectors[2,1]/ed0$vectors[1,1])/pi*180
m
axeslen
rot

ellipses.csv

id,name,x,y,rx,ry,arc,color,width
top-09,TOP 09,0.1854215,0.1954918,0.6989572061,0.4037292592,-39.44572,#660066,0.3672703364
kdu-csl,KDU-ČSL,-0.3004707,0.2113611,0.6796304755,0.4356661673,-71.46887,yellow,0.2761792896
kscm,KSČM,-0.4130825,-0.4975329,0.4177151959,0.2109323653,36.4545,red,0.4095576882
cssd,ČSSD,-0.5645961,-0.231405,0.5076190755,0.3161001265,48.64932,orange,0.4796483087
sz,Zelení,-0.5796359,-0.2170824,0.4843710714,0.2720517347,-7.494547,green,0.1894399641
svobodni,Svobodní,0.6500235,-0.4048686,0.4310734143,0.1714074449,-61.83275,darkgreen,0.1663580477
ods,ODS,0.4767697,0.2154355,0.6161090918,0.4039229633,-27.25659,darkblue,0.2947032405
pirati,Piráti,-0.1689064,-0.5534283,0.7480496857,0.1139738918,58.58541,black,0.1729884389
ano,ANO,-0.3099298,-0.1321353,0.6659162265,0.4561774633,22.84365,#5f91b3,0.4580529446

rotate_cutting_lines.txt

Rotation of cutting lines (if rotating dimensions)
unrotated:
y=a+b*x -> y=-(b0/normx)+(normy/normx)*x


rotation over y-axis (1st dimension is changing):
b0' = b0
normx' = -normx
normy' = normy

a' = a
b' = -b

rotation over x-axis (2nd dimension is changing):
b0' = -b0
normx' = -normx
normy' = normy

a' = -a
b' = -b

rotation by 90 degrees (switching 1st->-2nd and 2nd->1st dimensions):
b0' = -(normx/normy)*b0
normx' = normy
normy' = -normx

tmp.csv

0.3005271804470588,34
0.5684986994220589,34
0.4437021761514707,34
0.3090059625985294,34
0.23577003737794122,34
0.43642855493823535,34
0.4098466184470589,34
0.6130568280544116,34
0.44355655183088233,34
0.612739874310294,34
0.5063860776867648,34
0.5407814908794119,34
0.5124356049132353,34
0.32323299088676477,34
0.37601626425882356,34
0.5603817019441176,34
0.3299588653044118,34
0.3778067196176471,34
0.37043649093235304,34
0.4701100595058824,34
0.4652123288117648,34
0.32111213494558827,34
0.452149596364706,34
0.27015493624705883,34
0.3270228633485295,34
0.37505525001029416,34
0.23830358922894743,19
0.37462458938947374,19
0.40224110836578947,19
0.3764393573,19
0.25897522400789474,19
0.4220769145815789,19
0.3357764203105263,19
0.30766967881578955,19
0.29118965943421055,19
0.4202312221184211,19
0.23108800242368424,19
0.2796722402977273,22
0.39669718673409093,22
0.4234561978236842,19
0.504640342731579,19
0.48673452788157884,19
0.5064551106421052,19
0.4475507035342105,19
0.4963182247552632,19
0.524351899836842,19
0.3731002252631579,19
0.3668723152236842,19
0.6645811448131578,19
0.4754379251184211,19
0.46467711088181807,22
0.6322763662954545,22
0.5807490705999999,22
0.36628911314736845,19
0.5618074274078948,19
0.5439016125578947,19
0.5636221953184211,19
0.39038361885789474,19
0.5534853094315789,19
0.4671848151605263,19
0.31593314058684213,19
0.3097052305473684,19
0.607414060136842,19
0.41827084044210533,19
0.41530553775227264,22
0.582904793165909,22
0.6301206437295453,22
0.3879558622363636,22