Skip to content

Instantly share code, notes, and snippets.

@tlfrd
Last active July 11, 2018 14:43
Show Gist options
  • Save tlfrd/4e4be0b07ef5be6625d2c4d0322a6891 to your computer and use it in GitHub Desktop.
Save tlfrd/4e4be0b07ef5be6625d2c4d0322a6891 to your computer and use it in GitHub Desktop.

Revisions

  1. Cale Tilford revised this gist Aug 14, 2017. No changes.
  2. Cale Tilford revised this gist Aug 14, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@
    }

    var svg = d3.select("svg"),
    margin = {top: 20, right: 120, bottom: 30, left: 140},
    margin = {top: 50, right: 160, bottom: 50, left: 180},
    width = +svg.attr("width") -margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

  3. Cale Tilford revised this gist Aug 14, 2017. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,4 @@
    A sankey diagram of a poll I conducted for Felix, Imperial's Student Newspaper.
    We asked students who voted in 2015 who they intended to vote for in the 2017 general election.
    We asked students who voted in 2015 who they intended to vote for in the 2017 general election. Featured in [Issue 1666](http://felixonline.co.uk/issuearchive/issue/1514/download/) of Felix.

    Uses [d3-sankey](https://github.com/d3/d3-sankey).
  4. Cale Tilford revised this gist Aug 14, 2017. No changes.
  5. Cale Tilford revised this gist Jul 26, 2017. 1 changed file with 9 additions and 6 deletions.
    15 changes: 9 additions & 6 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -118,14 +118,17 @@
    .attr("stroke", function(d) {
    return colours[d.source.name];
    })
    .on("mouseover", function() {
    d3.select(this)
    .style("opacity", 0);
    })

    .on("mouseover", function() {
    d3.select(this)
    .attr("stroke-opacity", 0.6);
    })
    .on("mouseout", function() {
    d3.select(this)
    .attr("stroke-opacity", 0.2);
    })

    link.append("title")
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; });
    .text(function(d) { return d.value; });

    node = node
    .data(pollNodes.nodes)
  6. Cale Tilford revised this gist Jul 26, 2017. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -117,13 +117,15 @@
    .attr("stroke-width", function(d) { return Math.max(1, d.dy); })
    .attr("stroke", function(d) {
    return colours[d.source.name];
    });
    link.append("title")
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; })
    .on("mouseover", function() {
    })
    .on("mouseover", function() {
    d3.select(this)
    .style("opacity", 0);
    })


    link.append("title")
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; });

    node = node
    .data(pollNodes.nodes)
  7. Cale Tilford revised this gist Jul 26, 2017. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -119,7 +119,11 @@
    return colours[d.source.name];
    });
    link.append("title")
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; });
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; })
    .on("mouseover", function() {
    d3.select(this)
    .style("opacity", 0);
    })

    node = node
    .data(pollNodes.nodes)
  8. Cale Tilford revised this gist Jul 18, 2017. No changes.
  9. Cale Tilford revised this gist Jul 18, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,2 @@
    A sankey diagram of a poll I conducted for Felix, Imperial's Student Newspaper.
    We asked students who intended to vote in 2017 who they voted for in 2015.
    We asked students who voted in 2015 who they intended to vote for in the 2017 general election.
  10. Cale Tilford revised this gist Jul 18, 2017. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,2 @@
    Built with [blockbuilder.org](http://blockbuilder.org)
    A sankey diagram of a poll I conducted for Felix, Imperial's Student Newspaper.
    We asked students who intended to vote in 2017 who they voted for in 2015.
  11. Cale Tilford revised this gist Jul 18, 2017. No changes.
  12. Building blocks revised this gist Jul 18, 2017. 1 changed file with 0 additions and 0 deletions.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  13. Cale Tilford revised this gist Jul 18, 2017. 2 changed files with 152 additions and 32 deletions.
    39 changes: 7 additions & 32 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    <!DOCTYPE html>
    <svg width="760" height="800"></svg>
    <svg width="960" height="500"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://unpkg.com/[email protected]"></script>
    <script>
    @@ -24,38 +24,13 @@
    }

    var svg = d3.select("svg"),
    margin = {top: 40, right: 120, bottom: 30, left: 140},
    margin = {top: 20, right: 120, bottom: 30, left: 140},
    width = +svg.attr("width") -margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

    var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var defs = svg.append("defs");

    function generateGradient(firstParty, secondParty) {
    var gradient = defs.append("linearGradient")
    .attr("id", firstParty + secondParty)
    .attr("x1", "0%")
    .attr("x2", "100%")
    .attr("y1", "0%")
    .attr("y2", "100%");

    gradient.append("stop")
    .attr('class', 'start')
    .attr("offset", "0%")
    .attr("stop-color", colours[firstParty] || "#000")
    .attr("stop-opacity", 1);

    gradient.append("stop")
    .attr('class', 'end')
    .attr("offset", "100%")
    .attr("stop-color", colours[secondParty] || "#000")
    .attr("stop-opacity", 1);

    return firstParty + secondParty;
    }

    var formatNumber = d3.format(",.0f"),
    color = d3.scaleOrdinal(d3.schemeCategory10);

    @@ -87,7 +62,9 @@

    d3.json("poll.json", function(error, poll) {
    if (error) throw error;


    // first convert the data into a suitable format for generating a sankey diagram

    // generate 2015 nodes
    for (var party2017 in poll) {
    if (party2017 == "Conservative") {
    @@ -101,7 +78,6 @@
    }
    }
    }

    if (party2017 !== "UKIP" && party2017 !== "Green" && party2017 !== "SNP"
    && party2017 !== "ICannotVote" && party2017 !== "IWillSpoilMyBallot"
    && party2017 !== "IDoNotIntendToVote(ButIAmEligibleTo)") {
    @@ -131,10 +107,9 @@
    }
    }



    // generate sankey layout
    sankey(pollNodes);

    link = link
    .data(pollNodes.links)
    .enter().append("path")
    145 changes: 145 additions & 0 deletions poll.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    {
    "Labour": {
    "Conservative": 9,
    "Labour": 21,
    "LiberalDemocrat": 11,
    "UKIP": 1,
    "Green": 9,
    "SNP": 1,
    "Other": 2,
    "ICouldNotVote": 18,
    "Abstained": 6,
    "Spoiled": 1,
    "Total": 79
    },
    "Conservative": {
    "Conservative": 15,
    "Labour": 2,
    "LiberalDemocrat": 0,
    "UKIP": 2,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 8,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 27
    },
    "LiberalDemocrat": {
    "Conservative": 6,
    "Labour": 0,
    "LiberalDemocrat": 2,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 2,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 10
    },
    "Other": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 1,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 1,
    "Spoiled": 0,
    "Total": 2
    },
    "UKIP": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "Green": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "SNP": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "ICannotVote": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "IDoNotIntendToVote(ButIAmEligibleTo)": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "IWillSpoilMyBallot": {
    "Conservative": 0,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 0,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 0
    },
    "Undecided": {
    "Conservative": 1,
    "Labour": 0,
    "LiberalDemocrat": 0,
    "UKIP": 0,
    "Green": 0,
    "SNP": 0,
    "Other": 0,
    "ICouldNotVote": 2,
    "Abstained": 0,
    "Spoiled": 0,
    "Total": 3
    }
    }
  14. Cale Tilford created this gist Jul 18, 2017.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    license: mit
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Built with [blockbuilder.org](http://blockbuilder.org)
    175 changes: 175 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,175 @@
    <!DOCTYPE html>
    <svg width="760" height="800"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://unpkg.com/[email protected]"></script>
    <script>

    var colours = {
    "Conservative_2015": "#0087DC",
    "Conservative_2017": "#0087DC",
    "Labour_2015": "#DC241f",
    "Labour_2017": "#DC241f",
    "Green_2015": "#6AB023",
    "Green_2017": "#6AB023",
    "UKIP_2015": "#70147A",
    "UKIP_2017": "#70147A",
    "LiberalDemocrat_2015": "#FDBB30",
    "LiberalDemocrat_2017": "#FDBB30",
    "SNP_2015": "#FFFF00",
    "SNP_2017": "#FFFF00",
    "Abstained_2015": "#614126",
    "Spoiled_2015": "#C3834C",
    "Other_2015": "#7F7F7F",
    "Other_2017": "#7F7F7F"
    }

    var svg = d3.select("svg"),
    margin = {top: 40, right: 120, bottom: 30, left: 140},
    width = +svg.attr("width") -margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

    var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var defs = svg.append("defs");

    function generateGradient(firstParty, secondParty) {
    var gradient = defs.append("linearGradient")
    .attr("id", firstParty + secondParty)
    .attr("x1", "0%")
    .attr("x2", "100%")
    .attr("y1", "0%")
    .attr("y2", "100%");

    gradient.append("stop")
    .attr('class', 'start')
    .attr("offset", "0%")
    .attr("stop-color", colours[firstParty] || "#000")
    .attr("stop-opacity", 1);

    gradient.append("stop")
    .attr('class', 'end')
    .attr("offset", "100%")
    .attr("stop-color", colours[secondParty] || "#000")
    .attr("stop-opacity", 1);

    return firstParty + secondParty;
    }

    var formatNumber = d3.format(",.0f"),
    color = d3.scaleOrdinal(d3.schemeCategory10);

    var sankey = d3.sankey()
    .nodeWidth(15)
    .nodePadding(10)
    .iterations(1)
    .extent([[1, 1], [width - 1, height - 6]]);

    var link = g.append("g")
    .attr("class", "links")
    .attr("fill", "none")
    .attr("stroke", "#000")
    .attr("stroke-opacity", 0.2)
    .selectAll("path");

    var node = g.append("g")
    .attr("class", "nodes")
    .attr("font-family", "sans-serif")
    .attr("font-size", 10)
    .selectAll("g");

    var indexLookup = {};

    var pollNodes = {
    "nodes": [],
    "links": []
    };

    d3.json("poll.json", function(error, poll) {
    if (error) throw error;

    // generate 2015 nodes
    for (var party2017 in poll) {
    if (party2017 == "Conservative") {
    for (var party2015 in poll[party2017]) {
    if (party2015 !== "Total" && party2015 !== "ICouldNotVote") {
    pollNodes["nodes"].push({
    "name": party2015 + "_2015"
    });
    var currentSize = pollNodes["nodes"].length - 1;
    indexLookup[party2015 + "_2015"] = currentSize;
    }
    }
    }

    if (party2017 !== "UKIP" && party2017 !== "Green" && party2017 !== "SNP"
    && party2017 !== "ICannotVote" && party2017 !== "IWillSpoilMyBallot"
    && party2017 !== "IDoNotIntendToVote(ButIAmEligibleTo)") {
    // generate 2017 nodes
    pollNodes["nodes"].push({
    "name": party2017 + "_2017"
    });
    }
    var currentSize = pollNodes["nodes"].length - 1;
    indexLookup[party2017 + "_2017"] = currentSize;
    }

    var total = 0;

    for (var party2017 in poll) {
    for (var party2015 in poll[party2017]) {
    if (party2015 !== "Total" && party2015 !== "ICouldNotVote") {
    if (poll[party2017][party2015] !== 0) {
    pollNodes["links"].push({
    "source": indexLookup[party2015 + "_2015"],
    "target": indexLookup[party2017 + "_2017"],
    "value": poll[party2017][party2015]
    });
    total += poll[party2017][party2015];
    }
    }
    }
    }



    sankey(pollNodes);

    link = link
    .data(pollNodes.links)
    .enter().append("path")
    .attr("d", d3.sankeyLinkHorizontal())
    .attr("stroke-width", function(d) { return Math.max(1, d.dy); })
    .attr("stroke", function(d) {
    return colours[d.source.name];
    });
    link.append("title")
    .text(function(d) { return d.source.name + "->" + d.target.name + "\n" + d.value; });

    node = node
    .data(pollNodes.nodes)
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node.append("rect")
    .attr("height", function(d) { return d.dy; })
    .attr("width", sankey.nodeWidth())
    .attr("fill", function(d) {
    return colours[d.name] || "#D3D3D3";
    })
    .append("title")
    .text(function(d) { return d.name + "\n" + d.value; });

    node.append("text")
    .attr("x", sankey.nodeWidth() + 10)
    .attr("y", function(d) { return d.dy / 2; })
    .attr("dy", "0.35em")
    .attr("text-anchor", "start")
    .attr("transform", null)
    .text(function(d) { return d.name.slice(0, -5) + ": " + Math.round(d.value / total * 100) + "%"; })
    .filter(function(d) { return d.x < width / 2; })
    .attr("x", sankey.nodeWidth() - 25)
    .attr("text-anchor", "end");
    });

    </script>