Skip to content

Instantly share code, notes, and snippets.

@fabiovalse
Last active September 25, 2017 10:46
Show Gist options
  • Select an option

  • Save fabiovalse/538f0a7f36e035db285412d77b557664 to your computer and use it in GitHub Desktop.

Select an option

Save fabiovalse/538f0a7f36e035db285412d77b557664 to your computer and use it in GitHub Desktop.

Revisions

  1. fabiovalse revised this gist Sep 25, 2017. 2 changed files with 12 additions and 19 deletions.
    15 changes: 6 additions & 9 deletions index.coffee
    Original file line number Diff line number Diff line change
    @@ -22,17 +22,12 @@ sankey = d3.sankey()

    ###
    DATA TRANSFORMATION
    ###

    load = (path) ->
    new Promise (resolve) ->
    fetch path
    .then (response) ->
    resolve(response.json())
    ###

    # Data loading
    draw = (path) ->
    data = await load path
    data = await fetch path
    .then (response) -> response.json()

    # Filter EMPTY data
    data = data.filter (d) -> d.partitions?
    @@ -130,4 +125,6 @@ draw = (path) ->
    dy: '0.35em'
    .text (d) -> d.toUpperCase()

    draw './data.json'
    draw './data.json'

    d3.select(self.frameElement).transition().duration(500).style('height', "25000px");
    16 changes: 6 additions & 10 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    /*
    LAYOUT SETTING
    */
    var draw, height, load, margin, sankey, svg, vis, width,
    var draw, height, margin, sankey, svg, vis, width,
    _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

    width = document.body.getBoundingClientRect().width;
    @@ -30,18 +30,12 @@
    /*
    DATA TRANSFORMATION
    */
    load = function(path) {
    return new Promise(function(resolve) {
    return fetch(path).then(function(response) {
    return resolve(response.json());
    });
    });
    };

    // Data loading
    draw = async function(path) {
    var data, en_links, en_nodes, graph, label_coords, labels, links, nodes, s, x_factor;
    data = (await load(path));
    data = (await fetch(path).then(function(response) {
    return response.json();
    }));
    // Filter EMPTY data
    data = data.filter(function(d) {
    return d.partitions != null;
    @@ -161,4 +155,6 @@

    draw('./data.json');

    d3.select(self.frameElement).transition().duration(500).style('height', "25000px");

    }).call(this);
  2. fabiovalse revised this gist Sep 25, 2017. 7 changed files with 346 additions and 1 deletion.
    11 changes: 10 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,10 @@
    -
    This sankey diagram allows to analyse the stability of the [graph partitioning technique](https://github.com/fabiovalse/Visolario#partition) used for displaying Isolario data.

    Blue bars represent graph partitions and encode the amount of ASes they contain. Bars are placed in rows that represent days. Hence, each row summarizes the status of the ASes in a specific day. Links show the amount of ASes moving from one partition to another in two subsequent days.

    The graph partitioning technique seems to be quite stable since:
    - the amount of partitions is almost equal to 6 except for some cases in which it is 7;
    - the overall amount of ASes slightly changes from one day to another;
    - no significant flow emerges from one day to another.

    (The data set represented covers a time period of 6 months, from March 1 to September 16)
    1 change: 1 addition & 0 deletions data.json
    1 addition, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
    133 changes: 133 additions & 0 deletions index.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,133 @@
    ###
    LAYOUT SETTING
    ###
    width = document.body.getBoundingClientRect().width
    height = document.body.getBoundingClientRect().height
    margin = 40

    svg = d3.select 'svg'
    vis = svg.append 'g'
    .attrs
    width: width
    height: 25000
    transform: "translate(10, #{margin}) rotate(-90) translate(0, #{margin}) scale(-1,1)"

    # Sankey layout setting
    sankey = d3.sankey()
    .nodeId (d) -> d.id
    .nodePadding 5
    .nodeAlign (d) -> d3.sankeyCenter(d)
    .size [height-margin*2, width-margin*2]


    ###
    DATA TRANSFORMATION
    ###

    load = (path) ->
    new Promise (resolve) ->
    fetch path
    .then (response) ->
    resolve(response.json())

    # Data loading
    draw = (path) ->
    data = await load path

    # Filter EMPTY data
    data = data.filter (d) -> d.partitions?

    # Compute nodes
    nodes = data
    .map (d,i) ->
    d.partitions
    .map (p,j) -> {
    p...
    id: "#{i}_#{j}"
    row: i
    cell: j
    }
    .reduce (acc, cur) -> acc.concat(cur)
    # Compute links
    links = data[0...-1]
    .map (d,i) ->
    d.partitions
    .map (p,j) ->
    p.flows
    .map (f,k) -> {
    source: "#{i}_#{j}"
    target: "#{i+1}_#{k}"
    self: j is k
    value: f
    }
    .filter (f) -> f.value > 0
    .reduce (acc, cur) -> acc.concat(cur)
    .reduce (acc, cur) -> acc.concat(cur)
    # Create graph structure
    graph = {nodes: nodes, links: links}

    # Compute sankey layout
    s = sankey(graph)
    # Fix node positions
    x_factor = 0
    s.nodes.forEach (n,i) ->
    if n.cell is 0
    return
    else if n.cell is 1
    x_factor = (s.nodes[i].y0 - 9)

    s.nodes[i].y0 -= x_factor
    s.nodes[i].y1 -= x_factor
    # Update links position
    sankey.update(s)

    ###
    VISUALIZATION
    ###

    # links
    links = vis.selectAll '.link'
    .data graph.links.filter (d) -> not(d.self)

    en_links = links.enter().append 'path'
    .attrs
    class: 'link'
    d: d3.sankeyLinkHorizontal()
    .styles
    'stroke-width': (d) -> Math.max(1, d.width)
    .append 'title'
    .text (d) -> "group#{+d.source.id[-1..]+1} -> group#{+d.target.id[-1..]+1}: #{d.value}"

    # nodes
    nodes = vis.selectAll '.node'
    .data graph.nodes

    en_nodes = nodes.enter().append 'rect'
    .attrs
    class: 'node'
    x: (d) -> d.x0
    y: (d) -> d.y0
    height: (d) -> d.y1 - d.y0
    width: (d) -> d.x1 - d.x0
    .append 'title'
    .text (d) -> "group#{+d.id[-1..]+1}\n#{d.as_n} ASes"

    # Date labels
    label_coords = graph.nodes.filter (d) -> d.cell is 0

    labels = svg.selectAll '.label'
    .data data.map (d) ->
    date = new Date d.date.replace(/_/g, ' ')
    return date.toLocaleDateString('en-en', {month: "short"}) + date.getDate()

    labels.enter().append 'text'
    .attrs
    class: 'label'
    x: 4
    y: (d,i) ->
    if i < label_coords.length
    label_coords[i].x0 + 52
    dy: '0.35em'
    .text (d) -> d.toUpperCase()

    draw './data.json'
    23 changes: 23 additions & 0 deletions index.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    body, html {
    padding: 0;
    margin: 0;
    font-family: sans-serif;
    }
    svg {
    width: 100%;
    height: 25000px;
    }

    .node {
    fill: steelblue;
    }

    .link {
    fill: none;
    stroke: #000;
    stroke-opacity: 0.3;
    }

    .label {
    font-size: 12px;
    }
    15 changes: 15 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>Isolario stability analysis</title>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
    <script src="https://unpkg.com/d3-sankey@0"></script>
    <link rel="stylesheet" href="index.css">
    </head>
    <body>
    <svg></svg>
    <script src="index.js"></script>
    </body>
    </html>
    164 changes: 164 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,164 @@
    // Generated by CoffeeScript 2.0.0
    (function() {
    /*
    LAYOUT SETTING
    */
    var draw, height, load, margin, sankey, svg, vis, width,
    _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

    width = document.body.getBoundingClientRect().width;

    height = document.body.getBoundingClientRect().height;

    margin = 40;

    svg = d3.select('svg');

    vis = svg.append('g').attrs({
    width: width,
    height: 25000,
    transform: `translate(10, ${margin}) rotate(-90) translate(0, ${margin}) scale(-1,1)`
    });

    // Sankey layout setting
    sankey = d3.sankey().nodeId(function(d) {
    return d.id;
    }).nodePadding(5).nodeAlign(function(d) {
    return d3.sankeyCenter(d);
    }).size([height - margin * 2, width - margin * 2]);

    /*
    DATA TRANSFORMATION
    */
    load = function(path) {
    return new Promise(function(resolve) {
    return fetch(path).then(function(response) {
    return resolve(response.json());
    });
    });
    };

    // Data loading
    draw = async function(path) {
    var data, en_links, en_nodes, graph, label_coords, labels, links, nodes, s, x_factor;
    data = (await load(path));
    // Filter EMPTY data
    data = data.filter(function(d) {
    return d.partitions != null;
    });
    // Compute nodes
    nodes = data.map(function(d, i) {
    return d.partitions.map(function(p, j) {
    return _extends({}, p, {
    id: `${i}_${j}`,
    row: i,
    cell: j
    });
    });
    }).reduce(function(acc, cur) {
    return acc.concat(cur);
    });

    // Compute links
    links = data.slice(0, -1).map(function(d, i) {
    return d.partitions.map(function(p, j) {
    return p.flows.map(function(f, k) {
    return {
    source: `${i}_${j}`,
    target: `${i + 1}_${k}`,
    self: j === k,
    value: f
    };
    }).filter(function(f) {
    return f.value > 0;
    });
    }).reduce(function(acc, cur) {
    return acc.concat(cur);
    });
    }).reduce(function(acc, cur) {
    return acc.concat(cur);
    });
    // Create graph structure
    graph = {
    nodes: nodes,
    links: links
    };
    // Compute sankey layout
    s = sankey(graph);
    // Fix node positions
    x_factor = 0;
    s.nodes.forEach(function(n, i) {
    if (n.cell === 0) {
    return;
    } else if (n.cell === 1) {
    x_factor = s.nodes[i].y0 - 9;
    }
    s.nodes[i].y0 -= x_factor;
    return s.nodes[i].y1 -= x_factor;
    });
    // Update links position
    sankey.update(s);
    /*
    VISUALIZATION
    */
    // links
    links = vis.selectAll('.link').data(graph.links.filter(function(d) {
    return !d.self;
    }));
    en_links = links.enter().append('path').attrs({
    class: 'link',
    d: d3.sankeyLinkHorizontal()
    }).styles({
    'stroke-width': function(d) {
    return Math.max(1, d.width);
    }
    }).append('title').text(function(d) {
    return `group${+d.source.id.slice(-1) + 1} -> group${+d.target.id.slice(-1) + 1}: ${d.value}`;
    });
    // nodes
    nodes = vis.selectAll('.node').data(graph.nodes);
    en_nodes = nodes.enter().append('rect').attrs({
    class: 'node',
    x: function(d) {
    return d.x0;
    },
    y: function(d) {
    return d.y0;
    },
    height: function(d) {
    return d.y1 - d.y0;
    },
    width: function(d) {
    return d.x1 - d.x0;
    }
    }).append('title').text(function(d) {
    return `group${+d.id.slice(-1) + 1}\n${d.as_n} ASes`;
    });
    // Date labels
    label_coords = graph.nodes.filter(function(d) {
    return d.cell === 0;
    });
    labels = svg.selectAll('.label').data(data.map(function(d) {
    var date;
    date = new Date(d.date.replace(/_/g, ' '));
    return date.toLocaleDateString('en-en', {
    month: "short"
    }) + date.getDate();
    }));
    return labels.enter().append('text').attrs({
    class: 'label',
    x: 4,
    y: function(d, i) {
    if (i < label_coords.length) {
    return label_coords[i].x0 + 52;
    }
    },
    dy: '0.35em'
    }).text(function(d) {
    return d.toUpperCase();
    });
    };

    draw('./data.json');

    }).call(this);
    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.
  3. fabiovalse created this gist Sep 21, 2017.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    -