Arquivo da categoria: Diagrama

D3.js Sankey Plugin – Lista de Presidentes por Mandato, Partido e Estado

Untitled-3

Demostração

Com o arquivo abaixo criei um gráfico listando todos os presidentes do Brasil, contabilizando os Mandatos, Partidos e Estados.

index.html

<!DOCTYPE html>
<html>
<head lang="pt-BR">
    <meta charset="UTF-8">
    <title></title>
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="chart"></div>
<script src="d3.v3.min.js"></script>
<script src="sankey.js"></script>
<script src="custom.js"></script>
</body>
</html>

custom.js

var margin = {top: 1, right: 1, bottom: 6, left: 1},
    width = 1260 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

var formatNumber = d3.format(""),
    format = function(d) { return formatNumber(d).replace('.', '!').replace(',', '.').replace('!', ','); },
    color = d3.scale.category20();
var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var sankey = d3.sankey()
    .nodeWidth(100)
    .nodePadding(10)
    .size([width, height]);

var path = sankey.link();

d3.json("arquivo.json", function(energy) {

    var nodeMap = {};
    energy.nodes.forEach(function(x) { nodeMap[x.node] = x; });
    energy.links = energy.links.map(function(x) {
        console.log(x);
        return {
            source: nodeMap[x.source],
            target: nodeMap[x.target],
            value: x.value
        };
    });

    sankey
        .nodes(energy.nodes)
        .links(energy.links)
        .layout(32);

    var link = svg.append("g").selectAll(".link")
        .data(energy.links)
        .enter().append("a")
        .append("path")
        .attr("class", "link")
        .attr("d", path)
        .style("stroke-width", function(d) { return Math.max(1, d.dy); })

        .sort(function(a, b) { return b.dy - a.dy; });

    link.append("title")
        .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value).replace('.', '!').replace(',', '.').replace('!', ','); });

    var node = svg.append("g").selectAll(".node")
        .data(energy.nodes)
        .enter().append("g")
        .append("a")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })

        .call(d3.behavior.drag()
            .origin(function(d) { return d; })
            .on("dragstart", function() { this.parentNode.appendChild(this); })
            .on("drag", dragmove))
        .on("mouseover", fade(0.2))
        .on("mouseout", fade(1));

    node.append("rect")
        .attr("height", function(d) { return d.dy; })


        .attr("width", sankey.nodeWidth())
        .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
        .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
        .append("title")
        .text(function (d) {
            var titleText = d.name + " - " +
                format(d.value) + " total" + "\n" + "\n";
            var sourcesText = "";
            d.targetLinks.forEach(function (dstLnk) {
                sourcesText += "a partir de " + dstLnk.source.name + " - " +
                    format(dstLnk.value) + "\n";
            });
            return titleText + sourcesText;
        });

    node.append("text")
        .attr("class","nodeValue")
        .text(function(d) { return d.name + "\n" + format(d.value).replace('.', '!').replace(',', '.').replace('!', ','); });

    ///align vertically???
    node.selectAll("text.nodeValue")
        .attr("x", sankey.nodeWidth() / 2)
        .attr("y", function (d) { return (d.dy / 2) })
        .text(function (d) { return formatNumber(d.value).replace('.', '!').replace(',', '.').replace('!', ','); })
        .attr("dy", 5)
        .attr("text-anchor", "middle");

    node.append("text")
        .attr("class","nodeLabel");

    node.selectAll("text.nodeLabel")
        .attr("x", -6)
        .attr("y", function(d) { return d.dy / 2; })
        .attr("dy", ".35em")
        .attr("text-anchor", "end")
        .attr("transform", null)
        .text(function(d) { return d.name; })
        .filter(function(d) { return d.x < width / 2; })
        .attr("class", function (d) { if (d.categoria === 1) return "titulo"; })
        .attr("x", 6 + sankey.nodeWidth())
        .attr("text-anchor", "start");

    function dragmove(d) {
        d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
        sankey.relayout();
        link.attr("d", path);
    }
    function fade(opacity) {
        return function (g, i) {
            var elements = svg.selectAll(".node");
            elements = elements.filter(function (d) { return d.node != energy.nodes[i].node });
            elements.transition()
                .style("opacity", opacity);
            svg.selectAll(".link")
                .filter(function (d) { return d.source.node != energy.nodes[i].node && d.target.node != energy.nodes[i].node  })
                .transition()
                .style("opacity", opacity);
        };
    }
});

arquivo.json

{
  "nodes": [
    {
      "name": "Marechal Deodoro da Fonseca",
      "node": 0,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Floriano Peixoto",
      "node": 1,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Prudente de Morais",
      "node": 2,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Campos Sales",
      "node": 3,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Rodrigues Alves",
      "node": 4,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Afonso Pena",
      "node": 5,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Nilo Peçanha",
      "node": 6,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Hermes da Fonseca",
      "node": 7,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Venceslau Brás",
      "node": 8,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Delfim Moreira",
      "node": 9,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Epitácio Pessoa",
      "node": 10,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Artur Bernardes",
      "node": 11,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Washington Luís",
      "node": 12,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Getúlio Vargas",
      "node": 13,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "José Linhares",
      "node": 14,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Eurico Gaspar Dutra",
      "node": 15,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Café Filho",
      "node": 16,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Carlos Luz",
      "node": 17,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Nereu Ramos",
      "node": 18,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Juscelino Kubitschek",
      "node": 19,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Jânio Quadros",
      "node": 20,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Ranieri Mazzilli",
      "node": 21,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "João Goulart",
      "node": 22,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Castelo Branco",
      "node": 23,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Costa e Silva",
      "node": 24,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Emilio Medici",
      "node": 25,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Ernesto Geisel",
      "node": 26,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "João Figueiredo",
      "node": 27,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "José Sarney",
      "node": 28,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Fernando Collor",
      "node": 29,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Itamar Franco",
      "node": 30,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Fernando Henrique Cardoso",
      "node": 31,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Luís Inácio Lula da Silva",
      "node": 32,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "Dilma Rousseff",
      "node": 33,
      "categoria": 0,
      "xPos": 0
    },
    {
      "name": "militar",
      "node": 34,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Partido Republicano Federal",
      "node": 35,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Partido Republicano Paulista",
      "node": 36,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Partido Republicano Fluminense",
      "node": 37,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Partido Republicano Conservador",
      "node": 38,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Partido Republicano Mineiro",
      "node": 39,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Aliança Liberal",
      "node": 40,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "nenhum",
      "node": 41,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PSP",
      "node": 42,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PTN",
      "node": 43,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PTB",
      "node": 44,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PSD",
      "node": 45,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "ARENA (militar)",
      "node": 46,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PDS (militar)",
      "node": 47,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PRN",
      "node": 48,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PMDB",
      "node": 49,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PSDB",
      "node": 50,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "PT",
      "node": 51,
      "categoria": 0,
      "xPos": 1
    },
    {
      "name": "Alagoas",
      "node": 52,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Paraíba",
      "node": 53,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Mato Grosso",
      "node": 54,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Rio Grande do Norte",
      "node": 55,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Santa Catarina",
      "node": 56,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Mato Grosso do Sul",
      "node": 57,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "São Paulo",
      "node": 58,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Ceará",
      "node": 59,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Rio Grande do Sul",
      "node": 60,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Maranhão",
      "node": 61,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Rio de Janeiro",
      "node": 62,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Pernambuco",
      "node": 63,
      "categoria": 0,
      "xPos": 2
    },
    {
      "name": "Minas Gerais",
      "node": 64,
      "categoria": 0,
      "xPos": 2
    }
  ],
  "links": [
    {
      "source": 0,
      "target": 34,
      "value": 1
    },
    {
      "source": 1,
      "target": 34,
      "value": 1
    },
    {
      "source": 2,
      "target": 35,
      "value": 1
    },
    {
      "source": 3,
      "target": 36,
      "value": 1
    },
    {
      "source": 4,
      "target": 36,
      "value": 1
    },
    {
      "source": 5,
      "target": 39,
      "value": 1
    },
    {
      "source": 6,
      "target": 37,
      "value": 1
    },
    {
      "source": 7,
      "target": 38,
      "value": 1
    },
    {
      "source": 8,
      "target": 39,
      "value": 1
    },
    {
      "source": 9,
      "target": 39,
      "value": 1
    },
    {
      "source": 10,
      "target": 39,
      "value": 1
    },
    {
      "source": 11,
      "target": 39,
      "value": 1
    },
    {
      "source": 12,
      "target": 36,
      "value": 1
    },
    {
      "source": 13,
      "target": 40,
      "value": 1
    },
    {
      "source": 14,
      "target": 41,
      "value": 1
    },
    {
      "source": 15,
      "target": 45,
      "value": 1
    },
    {
      "source": 13,
      "target": 44,
      "value": 1
    },
    {
      "source": 16,
      "target": 42,
      "value": 1
    },
    {
      "source": 17,
      "target": 45,
      "value": 1
    },
    {
      "source": 18,
      "target": 45,
      "value": 1
    },
    {
      "source": 19,
      "target": 45,
      "value": 1
    },
    {
      "source": 20,
      "target": 43,
      "value": 1
    },
    {
      "source": 21,
      "target": 45,
      "value": 1
    },
    {
      "source": 22,
      "target": 44,
      "value": 1
    },
    {
      "source": 21,
      "target": 45,
      "value": 1
    },
    {
      "source": 23,
      "target": 46,
      "value": 1
    },
    {
      "source": 24,
      "target": 46,
      "value": 1
    },
    {
      "source": 25,
      "target": 46,
      "value": 1
    },
    {
      "source": 26,
      "target": 46,
      "value": 1
    },
    {
      "source": 27,
      "target": 47,
      "value": 1
    },
    {
      "source": 28,
      "target": 49,
      "value": 1
    },
    {
      "source": 29,
      "target": 48,
      "value": 1
    },
    {
      "source": 30,
      "target": 49,
      "value": 1
    },
    {
      "source": 30,
      "target": 49,
      "value": 1
    },
    {
      "source": 31,
      "target": 50,
      "value": 1
    },
    {
      "source": 31,
      "target": 50,
      "value": 1
    },
    {
      "source": 32,
      "target": 51,
      "value": 1
    },
    {
      "source": 32,
      "target": 51,
      "value": 1
    },
    {
      "source": 33,
      "target": 51,
      "value": 1
    },
    {
      "source": 33,
      "target": 51,
      "value": 1
    },
    {
      "source": 34,
      "target": 52,
      "value": 1
    },
    {
      "source": 34,
      "target": 52,
      "value": 1
    },
    {
      "source": 35,
      "target": 58,
      "value": 1
    },
    {
      "source": 36,
      "target": 58,
      "value": 1
    },
    {
      "source": 36,
      "target": 58,
      "value": 1
    },
    {
      "source": 39,
      "target": 64,
      "value": 1
    },
    {
      "source": 37,
      "target": 62,
      "value": 1
    },
    {
      "source": 38,
      "target": 60,
      "value": 1
    },
    {
      "source": 39,
      "target": 64,
      "value": 1
    },
    {
      "source": 39,
      "target": 64,
      "value": 1
    },
    {
      "source": 39,
      "target": 53,
      "value": 1
    },
    {
      "source": 39,
      "target": 64,
      "value": 1
    },
    {
      "source": 36,
      "target": 62,
      "value": 1
    },
    {
      "source": 40,
      "target": 60,
      "value": 1
    },
    {
      "source": 41,
      "target": 59,
      "value": 1
    },
    {
      "source": 45,
      "target": 54,
      "value": 1
    },
    {
      "source": 44,
      "target": 60,
      "value": 1
    },
    {
      "source": 42,
      "target": 55,
      "value": 1
    },
    {
      "source": 45,
      "target": 64,
      "value": 1
    },
    {
      "source": 45,
      "target": 56,
      "value": 1
    },
    {
      "source": 45,
      "target": 64,
      "value": 1
    },
    {
      "source": 43,
      "target": 57,
      "value": 1
    },
    {
      "source": 45,
      "target": 58,
      "value": 1
    },
    {
      "source": 44,
      "target": 60,
      "value": 1
    },
    {
      "source": 45,
      "target": 58,
      "value": 1
    },
    {
      "source": 46,
      "target": 59,
      "value": 1
    },
    {
      "source": 46,
      "target": 60,
      "value": 1
    },
    {
      "source": 46,
      "target": 60,
      "value": 1
    },
    {
      "source": 46,
      "target": 60,
      "value": 1
    },
    {
      "source": 47,
      "target": 62,
      "value": 1
    },
    {
      "source": 49,
      "target": 61,
      "value": 1
    },
    {
      "source": 48,
      "target": 62,
      "value": 1
    },
    {
      "source": 49,
      "target": 64,
      "value": 1
    },
    {
      "source": 49,
      "target": 64,
      "value": 1
    },
    {
      "source": 50,
      "target": 62,
      "value": 1
    },
    {
      "source": 50,
      "target": 62,
      "value": 1
    },
    {
      "source": 51,
      "target": 63,
      "value": 1
    },
    {
      "source": 51,
      "target": 64,
      "value": 1
    }
  ]
}

D3.js Sankey Diagrama com posição por coluna fixada dinamicamente pelo json

Untitled-2

Foi modificado o plugin D3 Sankey plugin para atender o formato de gráfico que queria utiliza-lo, para este exemplo vou disponibilizar os códigos.

index.html

<!DOCTYPE html>
<html>
<head lang="pt-BR">
    <meta charset="UTF-8">
    <title></title>
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="chart"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="sankey.js"></script>
<script src="custom.js"></script>
</body>
</html>

sankey.js (Modificado)

d3.sankey = function() {
    var sankey = {},
        nodeWidth = 24,
        nodePadding = 8,
        size = [1, 1],
        nodes = [],
        links = [];

    sankey.nodeWidth = function(_) {
        if (!arguments.length) return nodeWidth;
        nodeWidth = +_;
        return sankey;
    };

    sankey.nodePadding = function(_) {
        if (!arguments.length) return nodePadding;
        nodePadding = +_;
        return sankey;
    };

    sankey.nodes = function(_) {
        if (!arguments.length) return nodes;
        nodes = _;
        return sankey;
    };

    sankey.links = function(_) {
        if (!arguments.length) return links;
        links = _;
        return sankey;
    };

    sankey.size = function(_) {
        if (!arguments.length) return size;
        size = _;
        return sankey;
    };

    sankey.layout = function(iterations) {
        computeNodeLinks();
        computeNodeValues();
        computeNodeBreadths();
        computeNodeDepths(iterations);
        computeLinkDepths();
        return sankey;
    };

    sankey.relayout = function() {
        computeLinkDepths();
        return sankey;
    };

    sankey.link = function() {
        var curvature = .5;

        function link(d) {
            var x0 = d.source.x + d.source.dx,
                x1 = d.target.x,
                xi = d3.interpolateNumber(x0, x1),
                x2 = xi(curvature),
                x3 = xi(1 - curvature),
                y0 = d.source.y + d.sy + d.dy / 2,
                y1 = d.target.y + d.ty + d.dy / 2;
            return "M" + x0 + "," + y0
                + "C" + x2 + "," + y0
                + " " + x3 + "," + y1
                + " " + x1 + "," + y1;
        }

        link.curvature = function(_) {
            if (!arguments.length) return curvature;
            curvature = +_;
            return link;
        };

        return link;
    };

    // Populate the sourceLinks and targetLinks for each node.
    // Also, if the source and target are not objects, assume they are indices.
    function computeNodeLinks() {
        nodes.forEach(function(node) {
            node.sourceLinks = [];
            node.targetLinks = [];
        });
        links.forEach(function(link) {
            var source = link.source,
                target = link.target;
            if (typeof source === "number") source = link.source = nodes[link.source];
            if (typeof target === "number") target = link.target = nodes[link.target];
            source.sourceLinks.push(link);
            target.targetLinks.push(link);
        });
    }

    // Compute the value (size) of each node by summing the associated links.
    function computeNodeValues() {
        nodes.forEach(function(node) {
            node.value = Math.max(
                d3.sum(node.sourceLinks, value),
                d3.sum(node.targetLinks, value)
            );
        });
    }

    // Iteratively assign the breadth (x-position) for each node.
    // Nodes are assigned the maximum breadth of incoming neighbors plus one;
    // nodes with no incoming links are assigned breadth zero, while
    // nodes with no outgoing links are assigned the maximum breadth.
    function computeNodeBreadths() {
        var remainingNodes = nodes,
            nextNodes,
            x = 0;

        while (remainingNodes.length) {
            nextNodes = [];
            remainingNodes.forEach(function(node) {

                if (node.xPos) {
                    node.x = node.xPos;
                } else {
                    node.x = x;
                }

                node.dx = nodeWidth;
                node.sourceLinks.forEach(function(link) {
                    nextNodes.push(link.target);
                });
            });
            remainingNodes = nextNodes;
            ++x;
        }

        //
        moveSinksRight(x);
        scaleNodeBreadths((width - nodeWidth) / (x - 1));

    }


    function moveSinksRight(x) {
        nodes.forEach(function(node) {
            if (!node.sourceLinks.length) {
                //node.x = x - 1;
                node.x = node.xPos;
            }
        });
    }

    function scaleNodeBreadths(kx) {
        nodes.forEach(function(node) {
            node.x *= kx;
        });
    }

    function computeNodeDepths(iterations) {
        var nodesByBreadth = d3.nest()
            .key(function(d) { return d.x; })
            .sortKeys(d3.ascending)
            .entries(nodes)
            .map(function(d) { return d.values; });

        //
        initializeNodeDepth();
        resolveCollisions();
        for (var alpha = 1; iterations > 0; --iterations) {
            relaxRightToLeft(alpha *= .99);
            resolveCollisions();
            relaxLeftToRight(alpha);
            resolveCollisions();
        }

        function initializeNodeDepth() {
            var ky = d3.min(nodesByBreadth, function(nodes) {
                return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value);
            });

            nodesByBreadth.forEach(function(nodes) {
                nodes.forEach(function(node, i) {
                    node.y = i;
                    node.dy = node.value * ky;
                });
            });

            links.forEach(function(link) {
                link.dy = link.value * ky;
            });
        }

        function relaxLeftToRight(alpha) {
            nodesByBreadth.forEach(function(nodes, breadth) {
                nodes.forEach(function(node) {
                    if (node.targetLinks.length) {
                        var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value);
                        node.y += (y - center(node)) * alpha;
                    }
                });
            });

            function weightedSource(link) {
                return center(link.source) * link.value;
            }
        }

        function relaxRightToLeft(alpha) {
            nodesByBreadth.slice().reverse().forEach(function(nodes) {
                nodes.forEach(function(node) {
                    if (node.sourceLinks.length) {
                        var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value);
                        node.y += (y - center(node)) * alpha;
                    }
                });
            });

            function weightedTarget(link) {
                return center(link.target) * link.value;
            }
        }

        function resolveCollisions() {
            nodesByBreadth.forEach(function(nodes) {
                var node,
                    dy,
                    y0 = 0,
                    n = nodes.length,
                    i;

                // Push any overlapping nodes down.
                nodes.sort(ascendingDepth);
                for (i = 0; i < n; ++i) {
                    node = nodes[i];
                    dy = y0 - node.y;
                    if (dy > 0) node.y += dy;
                    y0 = node.y + node.dy + nodePadding;
                }

                // If the bottommost node goes outside the bounds, push it back up.
                dy = y0 - nodePadding - size[1];
                if (dy > 0) {
                    y0 = node.y -= dy;

                    // Push any overlapping nodes back up.
                    for (i = n - 2; i >= 0; --i) {
                        node = nodes[i];
                        dy = node.y + node.dy + nodePadding - y0;
                        if (dy > 0) node.y -= dy;
                        y0 = node.y;
                    }
                }
            });
        }

        function ascendingDepth(a, b) {
            return a.y - b.y;
        }
    }

    function computeLinkDepths() {
        nodes.forEach(function(node) {
            node.sourceLinks.sort(ascendingTargetDepth);
            node.targetLinks.sort(ascendingSourceDepth);
        });
        nodes.forEach(function(node) {
            var sy = 0, ty = 0;
            node.sourceLinks.forEach(function(link) {
                link.sy = sy;
                sy += link.dy;
            });
            node.targetLinks.forEach(function(link) {
                link.ty = ty;
                ty += link.dy;
            });
        });

        function ascendingSourceDepth(a, b) {
            return a.source.y - b.source.y;
        }

        function ascendingTargetDepth(a, b) {
            return a.target.y - b.target.y;
        }
    }

    function center(node) {
        return node.y + node.dy / 2;
    }

    function value(link) {
        return link.value;
    }

    return sankey;
};

custom.js (modificado)

var margin = {top: 1, right: 1, bottom: 6, left: 1},
    width = 1260 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var formatNumber = d3.format(",.2f"),
    format = function(d) { return formatNumber(d).replace('.', '!').replace(',', '.').replace('!', ','); },
    color = d3.scale.category20();
var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var sankey = d3.sankey()
    .nodeWidth(100)
    .nodePadding(10)
    .size([width, height]);

var path = sankey.link();

d3.json("package.json", function(energy) {

    var nodeMap = {};
    energy.nodes.forEach(function(x) { nodeMap[x.node] = x; });
    energy.links = energy.links.map(function(x) {
        console.log(x);
        return {
            source: nodeMap[x.source],
            target: nodeMap[x.target],
            value: x.value
        };
    });

    sankey
        .nodes(energy.nodes)
        .links(energy.links)
        .layout(32);

    var link = svg.append("g").selectAll(".link")
        .data(energy.links)
        .enter().append("path")
        .attr("class", "link")
        .attr("d", path)
        .style("stroke-width", function(d) { return Math.max(1, d.dy); })
        .sort(function(a, b) { return b.dy - a.dy; });

    link.append("title")
        .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value).replace('.', '!').replace(',', '.').replace('!', ','); });

    var node = svg.append("g").selectAll(".node")
        .data(energy.nodes)
        .enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
        .call(d3.behavior.drag()
            .origin(function(d) { return d; })
            .on("dragstart", function() { this.parentNode.appendChild(this); })
            .on("drag", dragmove));

    node.append("rect")
        .attr("height", function(d) { return d.dy; })
        .attr("width", sankey.nodeWidth())
        .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
        .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
        .append("title")
        .text(function (d) {
            var titleText = d.name + " - " +
                format(d.value) + " total" + "\n" + "\n";
            var sourcesText = "";
            d.targetLinks.forEach(function (dstLnk) {
                sourcesText += "a partir de " + dstLnk.source.name + " - " +
                    format(dstLnk.value) + "\n";
            });
            return titleText + sourcesText;
        });

    node.append("text")
        .attr("class","nodeValue")
        .text(function(d) { return d.name + "\n" + format(d.value).replace('.', '!').replace(',', '.').replace('!', ','); });

    ///align vertically???
    node.selectAll("text.nodeValue")
        .attr("x", sankey.nodeWidth() / 2)
        .attr("y", function (d) { return (d.dy / 2) })
        .text(function (d) { return formatNumber(d.value).replace('.', '!').replace(',', '.').replace('!', ','); })
        .attr("dy", 5)
        .attr("text-anchor", "middle");

    node.append("text")
        .attr("class","nodeLabel");

    node.selectAll("text.nodeLabel")
        .attr("x", -6)
        .attr("y", function(d) { return d.dy / 2; })
        .attr("dy", ".35em")
        .attr("text-anchor", "end")
        .attr("transform", null)
        .text(function(d) { return d.name; })
        .filter(function(d) { return d.x < width / 2; })
        .attr("class", function (d) { if (d.categoria === 1) return "titulo"; })
        .attr("x", 6 + sankey.nodeWidth())
        .attr("text-anchor", "start");

    function dragmove(d) {
        d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
        sankey.relayout();
        link.attr("d", path);
    }
});

package.json

{
  "nodes": [
    {
      "node": 0,
      "name": "MERCEARIA",
      "categoria": 1,
      "xPos": 0
    },
    {
      "node": 5,
      "name": "MERCEARIA",
      "categoria": 1,
      "xPos": 3
    },
    {
      "node": 201,
      "name": "MERC SECA SALG",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 202,
      "name": "MERC SECA DOCE",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 203,
      "name": "LIQUIDA",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 204,
      "name": "PERFUMARIAS",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 205,
      "name": "LIMPEZA",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 226,
      "name": "CONVENIENCIA",
      "categoria": 0,
      "xPos": 1
    },
    {
      "node": 32,
      "name": "32-ALIMENT.COMPLEMENTAR",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 31,
      "name": "31-ALIMENTAÇÃO BÁSICA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 39,
      "name": "39-PEIXARIA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 42,
      "name": "42-PERECIVEIS COMPLEMENT",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 38,
      "name": "38-FLV",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 36,
      "name": "36-FOOD SERVICE",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 99,
      "name": "Sem Classificação Comercial",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 33,
      "name": "33-LÍQUIDA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 43,
      "name": "43-PADARIA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 47,
      "name": "47-CASA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 41,
      "name": "41-LATICINIOS",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 34,
      "name": "34-PERFUMARIA",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 49,
      "name": "49-LAZER",
      "categoria": 0,
      "xPos": 2
    },
    {
      "node": 35,
      "name": "35-LIMPEZA",
      "categoria": 0,
      "xPos": 2
    }
  ],
  "links": [
    {
      "source": 0,
      "target": 201,
      "value": 2.78
    },
    {
      "source": 201,
      "target": 35,
      "value": 0.01
    },
    {
      "source": 35,
      "target": 5,
      "value": 0.01
    },

    {
      "source": 0,
      "target": 202,
      "value": 35
    },
    {
      "source": 0,
      "target": 203,
      "value": 54.90
    },
    {
      "source": 0,
      "target": 204,
      "value": 122.64
    },
    {
      "source": 0,
      "target": 205,
      "value": 23.96
    },
    {
      "source": 0,
      "target": 226,
      "value": 32.90
    },
    {
      "source": 32,
      "target": 5,
      "value": 2.78
    },
    {
      "source": 31,
      "target": 5,
      "value": 3.56
    },
    {
      "source": 39,
      "target": 5,
      "value": 5.89
    },
    {
      "source": 42,
      "target": 5,
      "value": 6.48
    },
    {
      "source": 38,
      "target": 5,
      "value": 15.75
    },
    {
      "source": 36,
      "target": 5,
      "value": 139.75
    },
    {
      "source": 99,
      "target": 5,
      "value": 26.90
    },
    {
      "source": 33,
      "target": 5,
      "value": 23
    },
    {
      "source": 43,
      "target": 5,
      "value": 5.47
    },
    {
      "source": 47,
      "target": 5,
      "value": 23.92
    },
    {
      "source": 41,
      "target": 5,
      "value": 62.40
    },
    {
      "source": 34,
      "target": 5,
      "value": 122.64
    },
    {
      "source": 49,
      "target": 5,
      "value": 4.29
    },
    {
      "source": 35,
      "target": 5,
      "value": 23.96
    }
  ]
}

style.css

body{
    font-family: "Arial";
}
#chart {
    height: 500px;
}

.node rect {
    cursor: move;
    fill-opacity: .9;
    shape-rendering: crispEdges;
}

.node text {
    pointer-events: none;
    text-shadow: 0 1px 0 #fff;
    font-size: 12px;
}

text.nodeLabel {
    font-size: 10px;
}

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

.link:hover {
    stroke-opacity: .5;
}
.node text.titulo{
    font-weight: bold;
    font-size: 14px;
}