Based on special questions "We will not be in the government with ..."
- prepare the data (manually)
- helper.py create links
- koalice.html
source,target,value,slug | |
ČSSD,ANO,1 | |
KDU,ANO,1 | |
KDU,ČSSD,1 | |
ODS,ČSSD,1 | |
ODS,KDU,1 | |
Piráti,ČSSD,1 | |
Piráti,KDU,1 | |
Piráti,ODS,1 | |
SPD,ANO,1 | |
SPD,KSČM,1 | |
STAN,ČSSD,1 | |
STAN,KDU,1 | |
STAN,ODS,1 | |
STAN,Piráti,1 | |
TOP 09,ČSSD,1 | |
TOP 09,KDU,1 | |
TOP 09,ODS,1 | |
TOP 09,Piráti,1 | |
TOP 09,STAN,1 | |
Zelení,ČSSD,1 | |
Zelení,KDU,1 | |
Zelení,Piráti,1 | |
Zelení,STAN,1 | |
Zelení,TOP 09,1 | |
Svobodní,ČSSD,1 | |
Svobodní,KDU,1 | |
Svobodní,ODS,1 | |
Svobodní,Piráti,1 | |
Svobodní,SPD,1 | |
Svobodní,TOP 09,1 |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Bootswatch: Free themes for Bootstrap</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<link rel="stylesheet" href="bootstrap.min.css" media="screen"> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> | |
</head> | |
<body> | |
<script src="http://d3js.org/d3.v3.js"></script> | |
<style> | |
path.link { | |
fill: none; | |
stroke: #666; | |
stroke-width: 1.5px; | |
} | |
circle { | |
fill: red; | |
stroke: #fff; | |
stroke-width: 1.5px; | |
} | |
text { | |
fill: #000; | |
font: 10px sans-serif; | |
pointer-events: none; | |
} | |
.logo { | |
width: 28px; | |
height: 28px; | |
border-radius: 50%; | |
} | |
.hithit { | |
width: 100vw; | |
background-color: #fed201; | |
padding: 10px; | |
} | |
.top { | |
width: 100vw; | |
padding: 10px; | |
background-color: #fed201; | |
} | |
</style> | |
<body> | |
<script> | |
// get the data | |
d3.csv("force.csv", function(error, links) { | |
var nodes = {}; | |
// Compute the distinct nodes from the links. | |
links.forEach(function(link) { | |
link.source = nodes[link.source] || | |
(nodes[link.source] = {name: link.source}); | |
link.target = nodes[link.target] || | |
(nodes[link.target] = {name: link.target}); | |
link.value = +link.value; | |
}); | |
var width = 476, | |
height = 400; | |
var force = d3.layout.force() | |
.nodes(d3.values(nodes)) | |
.links(links) | |
.size([width, height]) | |
.linkDistance(150) | |
.charge(-1000) | |
.on("tick", tick) | |
.start(); | |
var svg = d3.select("#chart").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
// build the arrow. | |
svg.append("svg:defs").selectAll("marker") | |
.data(["end"]) // Different link/path types can be defined here | |
// .enter().append("svg:marker") // This section adds in the arrows | |
// .attr("id", String) | |
// .attr("viewBox", "0 -5 10 10") | |
// .attr("refX", 15) | |
// .attr("refY", -1.5) | |
// .attr("markerWidth", 6) | |
// .attr("markerHeight", 6) | |
// .attr("orient", "auto") | |
.append("svg:path") | |
.attr("d", "M0,-5L00,0L0,5"); | |
// add the links and the arrows | |
var path = svg.append("svg:g").selectAll("path") | |
.data(force.links()) | |
.enter().append("svg:path") | |
// .attr("class", function(d) { return "link " + d.type; }) | |
.attr("class", "link") | |
.attr("marker-end", "url(#end)"); | |
// define the nodes | |
var node = svg.selectAll(".node") | |
.data(force.nodes()) | |
.enter().append("g") | |
.attr("class", "node") | |
.call(force.drag); | |
// add the nodes | |
// node.append("circle") | |
// .attr("r", 5); | |
node.append("svg:image") | |
.attr('x',-25) | |
.attr('y',-25) | |
.attr('width', 50) | |
.attr('height', 50) | |
.attr('class', 'logo') | |
.attr("xlink:href", function(d) { | |
return "200x200/" + d.name + ".png" | |
}); | |
// add the text | |
// node.append("text") | |
// .attr("x", 12) | |
// .attr("dy", ".1em") | |
// .text(function(d) { return d.name; }); | |
// add the curvy lines | |
function tick() { | |
path.attr("d", function(d) { | |
var dx = d.target.x - d.source.x, | |
dy = d.target.y - d.source.y, | |
dr = Math.sqrt(dx * dx + dy * dy); | |
return "M" + | |
d.source.x + "," + | |
d.source.y + "A" + | |
dr + "," + dr + " 0 0,1 " + | |
d.target.x + "," + | |
d.target.y; | |
}); | |
node | |
.attr("transform", function(d) { | |
return "translate(" + d.x + "," + d.y + ")"; }); | |
} | |
}); | |
</script> | |
<div class="top text-center"> | |
<h4>Které strany spolu chtějí vládnout.</h4> | |
<h4>Na základě odpovědí pro Volební kalkulačku.</h4> | |
<h6>Otázka zněla "Vylučujeme vládu s ... "</h6> | |
</div> | |
<div id="chart"></div> | |
<div class="hithit text-center"> | |
<h5>Podpořte Volební kalkulačku na Hithitu!</h5> | |
<h5>www.Hithit.cz/VolebniKalkulacka</h5> | |
</div> | |
</body> | |
</html> |
# prepare nodes for D3 | |
import csv | |
import slugify | |
arr = ['ANO', 'ČSSD', 'KDU', 'KSČM', 'ODS', 'Piráti', 'SPD', 'STAN', 'TOP 09', 'Zelení', 'Svobodní'] | |
with open("links.csv") as fin: | |
csvr = csv.reader(fin) | |
print('source,target,value,slug') | |
i = 0 | |
for r in csvr: | |
j = 0 | |
for item in r: | |
if str(item) == '1': | |
# print('{ source: ' + str(i) + ',target: ' + str(j) + '},') | |
print(arr[i] + ',' + arr[j] + ',1') | |
j += 1 | |
i += 1 |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>D3 practice</title> | |
<meta name="viewport" content="width=device-width, initial-scale 1.0"> | |
<style> | |
/*////////////////////////////////////// | |
UNIVERSAL | |
//////////////////////////////////////*/ | |
* { | |
padding: 0; | |
margin: 0; | |
list-style-type: none; | |
font-weight: normal; | |
text-decoration: none; | |
box-sizing: border-box; | |
} | |
h1, | |
h2, | |
h3, | |
h4, | |
h5, | |
h6 { | |
padding: 0; | |
margin: 0; | |
font-weight: normal; | |
} | |
img, | |
video { | |
max-width: 100%; | |
} | |
input, button, select, textarea, submit { | |
border: none; | |
} | |
/* ---- Float clearfix ---- */ | |
@mixin clearfix { | |
&:after { | |
content: ""; | |
display: table; | |
clear: both; | |
} | |
} | |
/*////////////////////////////////////// | |
TEXT TRANSFORM | |
//////////////////////////////////////*/ | |
/*Uppercase*/ | |
/*Lowercase*/ | |
/*////////////////////////////////////// | |
FONTS | |
//////////////////////////////////////*/ | |
/*BUNGEE INLINE*/ | |
/*////////////////////////////////////// | |
COLORS | |
//////////////////////////////////////*/ | |
/*STARK WHITE*/ | |
/*////////////////////////////////////// | |
D3 PRACTICE | |
//////////////////////////////////////*/ | |
</style> | |
</head> | |
<body class="site-container"> | |
<div class="site-content"> | |
</div> | |
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://d3js.org/d3-collection.v1.min.js"></script> | |
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script> | |
<script src="https://d3js.org/d3-quadtree.v1.min.js"></script> | |
<script src="https://d3js.org/d3-timer.v1.min.js"></script> | |
<script src="https://d3js.org/d3-force.v1.min.js"></script> | |
<script> | |
$(document).ready(function() { | |
//Width and height | |
var w = 500; | |
var h = 300; | |
//Original data | |
var dataset = { | |
nodes: [ | |
{ name: "Adam" }, | |
{ name: "Bob" }, | |
{ name: "Carrie" }, | |
{ name: "Donovan" }, | |
{ name: "Edward" }, | |
{ name: "Felicity" }, | |
{ name: "George" }, | |
{ name: "Hannah" }, | |
{ name: "Iris" }, | |
{ name: "Jerry" }, | |
{ name: 'Karel' } | |
], | |
edges: [ | |
{ source: 1,target: 0}, | |
{ source: 2,target: 0}, | |
{ source: 2,target: 1}, | |
{ source: 4,target: 1}, | |
{ source: 4,target: 2}, | |
{ source: 4,target: 3}, | |
{ source: 5,target: 1}, | |
{ source: 5,target: 2}, | |
{ source: 5,target: 4}, | |
{ source: 6,target: 0}, | |
{ source: 6,target: 3}, | |
{ source: 7,target: 1}, | |
{ source: 7,target: 2}, | |
{ source: 7,target: 4}, | |
{ source: 7,target: 5}, | |
{ source: 8,target: 1}, | |
{ source: 8,target: 2}, | |
{ source: 8,target: 4}, | |
{ source: 8,target: 5}, | |
{ source: 8,target: 7}, | |
{ source: 9,target: 1}, | |
{ source: 9,target: 2}, | |
{ source: 9,target: 5}, | |
{ source: 9,target: 7}, | |
{ source: 9,target: 8}, | |
{ source: 10,target: 1}, | |
{ source: 10,target: 2}, | |
{ source: 10,target: 4}, | |
{ source: 10,target: 5}, | |
{ source: 10,target: 6}, | |
{ source: 10,target: 8} | |
] | |
}; | |
//Initialize a default force layout, using the nodes and edges in dataset | |
var force = d3.forceSimulation() | |
.force('link', d3.forceLink()) | |
.force("charge", d3.forceManyBody().strength(100)) | |
.force("x", d3.forceX(w/2)) | |
.force("y", d3.forceY(h/2)) | |
.on("tick", tick); | |
var colors = d3.scaleOrdinal(d3.schemeCategory10); | |
//Create SVG element | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h); | |
start(); | |
function start() { | |
var nodeElements = svg.selectAll(".node") | |
.data(dataset.nodes, function(d){return d.id}); | |
var linkElements = svg.selectAll(".link") | |
.data(dataset.edges); | |
nodeElements.enter() | |
.append("circle") | |
.attr("class", function(d) {return "node " + d.id; }) | |
.attr("r", 10) | |
.style("fill", function(d, i) { | |
return colors(i); | |
}); | |
linkElements.enter() | |
.insert("line", ".node") | |
.attr("class", "link") | |
.style("stroke", "#ccc") | |
.style("stroke-width", 1); | |
nodeElements.exit().remove(); | |
linkElements.exit().remove(); | |
force.nodes(dataset.nodes) | |
force.force("link").links(dataset.edges).distance(150) | |
force.restart(); | |
} | |
function tick() { | |
var nodeElements = svg.selectAll(".node"); | |
var linkElements = svg.selectAll(".link"); | |
nodeElements.attr("cx", function(d,i) {return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
linkElements.attr("x1", function(d) { return d.source.x; }) | |
.attr("y1", function(d) { return d.source.y; }) | |
.attr("x2", function(d) { return d.target.x; }) | |
.attr("y2", function(d) { return d.target.y; }); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
1 | |||||||||
1 | 1 | ||||||||
1 | 1 | ||||||||
1 | 1 | 1 | |||||||
1 | 1 | ||||||||
1 | 1 | 1 | 1 | ||||||
1 | 1 | 1 | 1 | 1 | |||||
1 | 1 | 1 | 1 | 1 | |||||
1 | 1 | 1 | 1 | 1 | 1 |