Skip to content

Instantly share code, notes, and snippets.

@hungvietdo
Last active January 4, 2023 08:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hungvietdo/7f8df0bcd7fba7e531e6 to your computer and use it in GitHub Desktop.
Save hungvietdo/7f8df0bcd7fba7e531e6 to your computer and use it in GitHub Desktop.
VI7: Node-link diagram and Adjacency matrix

Node-link Diagram

I added a new attribute to the dataset which is region.

In the node-link diagram, states in the same region likely stick together as they have links in between.

States in region which has less number of links spread out in the diagram. For example: look at the light-green color (South Atlantic), Florida is far apart with those states (DC, Maryland, Virginia, West Viginia, Delaware).

Thus, although the dataset is non-spatial, users can explore the relationship of nodes by looking the distance or number of hops in between.

Matrix view

I want to encode the region information into the adjacency matrix view.

Using the same dataset with region attribute, it is impossible (or hard) to encode the region information for a pair that each state in that pair has different region (those in blue color).

Or using two half trianges in each link with region colors?

When ordering by region we can see those states in same group are closer together.

Each row or column has at most two colors. For those have one color (Utah, Michigan, or New Hampshire) that mean they does not have border with state that in different region.

forked from anonymous's block: VI7: Node-link diagram and Adjacency matrix

html,body,#wrapper {
width: 80%;
height: 80%;
margin: 0px;
padding: 5px 5px 5px 5px;
padding-top: 20px;
}
.chart {
font-family: Arial, sans-serif;
font-size: 12px;
}
.axis path,.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: #33b5e5;
}
.bar-failed {
fill: #CC0000;
}
.bar-running {
fill: #669900;
}
.bar-succeeded {
fill: #33b5e5;
}
.bar-killed {
fill: #ffbb33;
}
#header1 {
position: center;
top: 0;
left: 10px;
z-index: 10;
}
#header2 {
position: center;
top: 0;
left: 10px;
z-index: 10;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
.background {
fill: #eee;
}
line {
stroke: #fff;
}
text.active {
fill: red;
}
<!DOCTYPE html>
<html class="ocks-org do-not-copy">
<head>
<link type="text/css" href="style.css" rel="stylesheet" />
<link type="text/css" href="example.css" rel="stylesheet" />
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/colorbrewer.v1.min.js"></script>
<script src="legend.js"></script>
</head>
<body>
<div>
<h3>Hung Do - CS725: Information Visualization </h3>
<h3 >Node-link Diagram </h3>
<div width="100%" id="header1"> </div>
<article style="width:1020px">
<h3 >Adjacency Matrix View</h3>
<section id="header2" style="float:left;width:750px">
</section>
<aside style="font-style:italic;
float:right;width:250px;
border:1px solid;
margin: 5em auto auto auto;"
>
<p>Order: <select id="order">
<option value="name">By Name</option>
<option value="count">By Number of Links</option>
<option value="group">By Region</option>
</select>
<p>Built with <a href="http://d3js.org/">d3.js</a>.
</aside>
</article>
<h2 > Reference </h2>
Force-Directed Graph: <a href="http://bl.ocks.org/mbostock/4062045" target="_blank"> http://bl.ocks.org/mbostock/4062045 </a><br>
Matrix View: <a href="https://bost.ocks.org/mike/miserables/" target="_blank"> https://bost.ocks.org/mike/miserables/ </a>
<script type="text/javascript" src="node-link.js"></script>
<script type="text/javascript" src="matrix-view.js"></script>
<div>
</body>
</html>
d3.svg.legend = function() {
var legendValues=[{color: "red", stop: [0,1]},{color: "blue", stop: [1,2]},{color: "purple", stop: [2,3]},{color: "yellow", stop: [3,4]},{color: "Aquamarine", stop: [4,5]}];
var legenTexts=[];
var legendScale;
var cellWidth = 30;
var cellHeight = 20;
var adjustable = false;
var labelFormat = d3.format(".01f");
var labelUnits = "units";
var lastValue = 6;
var changeValue = 1;
var orientation = "horizontal";
var cellPadding = 0;
function legend(g) {
function cellRange(valuePosition, changeVal) {
legendValues[valuePosition].stop[0] += changeVal;
legendValues[valuePosition - 1].stop[1] += changeVal;
redraw();
}
function redraw() {
g.selectAll("g.legendCells").data(legendValues).exit().remove();
g.selectAll("g.legendCells").select("rect").style("fill", function(d) {return d.color});
if (orientation == "vertical") {
g.selectAll("g.legendCells").select("text.breakLabels").style("display", "block").style("text-anchor", "start").attr("x", cellWidth + cellPadding).attr("y", 5 + (cellHeight / 2)).text(function(d) {return labelFormat(d.stop[0]) + (d.stop[1].length > 0 ? " - " + labelFormat(d.stop[1]) : "")})
g.selectAll("g.legendCells").attr("transform", function(d,i) {return "translate(0," + (i * (cellHeight + cellPadding)) + ")" });
}
else {
g.selectAll("g.legendCells").attr("transform", function(d,i) {return "translate(" + (i * cellWidth) + ",0)" });
g.selectAll("text.breakLabels").style("text-anchor", "middle").attr("x", 0).attr("y", -7).style("display", function(d,i) {return i == 0 ? "none" : "block"}).text(function(d) {return labelFormat(d.stop[0])});
}
}
g.selectAll("g.legendCells")
.data(legendValues)
.enter()
.append("g")
.attr("class", "legendCells")
.attr("transform", function(d,i) {return "translate(" + (i * (cellWidth + cellPadding)) + ",0)" })
g.selectAll("g.legendCells")
.append("rect")
.attr("height", cellHeight)
.attr("width", cellWidth)
.style("fill", function(d) {return d.color})
//.style("stroke", "black")
.style("stroke-width", "2px");
g.selectAll("g.legendCells")
.append("text")
.attr("x", 30)
.attr("y", 10)
//.attr("class", "breakLabels")
.text(function(d,i){return legenTexts[i];})
.style("pointer-events", "none");
g.append("text")
.text(labelUnits)
.style("font-size",15)
.attr("y", -10);
//console.log("aaa" + legenTexts[3]) ;
redraw();
}
legend.inputScale = function(newScale,nodes) {
legenTexts = nodes;
if (!arguments.length) return scale;
scale = newScale;
legendValues = [];
if (scale.invertExtent) {
//Is a quantile scale
scale.range().forEach(function(el) {
var cellObject = {color: el, stop: scale.invertExtent(el)}
legendValues.push(cellObject);
//legenTexts.push(el);
// legenTexts[el] = nodes[el];
//console.log(el+nodes[el]);
})
}
else {
scale.domain().forEach(function (el) {
var cellObject = {color: scale(el), stop: [el,""]}
legendValues.push(cellObject);
//legenTexts[el]=el;
//legenTexts[el] = nodes[el];
//console.log(el+nodes[el]);
})
}
return this;
}
legend.scale = function(testValue) {
var foundColor = legendValues[legendValues.length - 1].color;
for (el in legendValues) {
if(testValue < legendValues[el].stop[1]) {
foundColor = legendValues[el].color;
break;
}
}
return foundColor;
}
legend.cellWidth = function(newCellSize) {
if (!arguments.length) return cellWidth;
cellWidth = newCellSize;
return this;
}
legend.cellHeight = function(newCellSize) {
if (!arguments.length) return cellHeight;
cellHeight = newCellSize;
return this;
}
legend.cellPadding = function(newCellPadding) {
if (!arguments.length) return cellPadding;
cellPadding = newCellPadding;
return this;
}
legend.cellExtent = function(incColor,newExtent) {
var selectedStop = legendValues.filter(function(el) {return el.color == incColor})[0].stop;
if (arguments.length == 1) return selectedStop;
legendValues.filter(function(el) {return el.color == incColor})[0].stop = newExtent;
return this;
}
legend.cellStepping = function(incStep) {
if (!arguments.length) return changeValue;
changeValue = incStep;
return this;
}
legend.units = function(incUnits) {
if (!arguments.length) return labelUnits;
labelUnits = incUnits;
return this;
}
legend.orientation = function(incOrient) {
if (!arguments.length) return orientation;
orientation = incOrient;
return this;
}
legend.labelFormat = function(incFormat) {
if (!arguments.length) return labelFormat;
labelFormat = incFormat;
if (incFormat == "none") {
labelFormat = function(inc) {return inc};
}
return this;
}
return legend;
}
var margin = {top: 80, right: 180, bottom: 100, left: 80},
width = 750,
height = 750;
var x = d3.scale.ordinal().rangeBands([0, width]),
z = d3.scale.linear().domain([0, 4]).clamp(true),
c = d3.scale.category10().domain(d3.range(10));
var svg = d3.select("#header2").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", -margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("miserables.json", function(miserables) {
var matrix = [],
nodes = miserables.nodes,
links = miserables.links,
n = nodes.length,
sampleCategoricalData =[];
// Compute index per node.
nodes.forEach(function(node, i) {
node.index = i;
node.count = 0;
matrix[i] = d3.range(n).map(function(j) { return {x: j, y: i, z: 0}; });
});
// Convert links to matrix; count character occurrences.
links.forEach(function(link) {
matrix[link.source][link.target].z += 4;
matrix[link.target][link.source].z += 4;
// matrix[link.source][link.source].z += 4;
// matrix[link.target][link.target].z += 4;
nodes[link.source].count++;
nodes[link.target].count++;
sampleCategoricalData[nodes[link.source].group] = nodes[link.source].region;
});
sampleCategoricalData[0]="Different Region";
verticalLegend = d3.svg.legend().labelFormat("none").cellPadding(5).orientation("vertical").units("Region by Color").cellWidth(25).cellHeight(18).inputScale(c,sampleCategoricalData).cellStepping(10);
d3.selectAll("svg")
.append("g").attr("transform", "translate("+(width+130)+",250)").attr("class", "legend").call(verticalLegend);
// Precompute the orders.
var orders = {
name: d3.range(n).sort(function(a, b) { return d3.ascending(nodes[a].name, nodes[b].name); }),
count: d3.range(n).sort(function(a, b) { return nodes[b].count - nodes[a].count; }),
group: d3.range(n).sort(function(a, b) { return nodes[a].group - nodes[b].group; })
};
// The default sort order.
x.domain(orders.name);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var row = svg.selectAll(".row")
.data(matrix)
.enter().append("g")
.attr("class", "row")
.attr("transform", function(d, i) { return "translate(0," + x(i) + ")"; })
.each(row);
row.append("line")
.attr("x2", width);
row.append("text")
.attr("x", -6)
.attr("y", x.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "end")
.text(function(d, i) { return nodes[i].name; });
var column = svg.selectAll(".column")
.data(matrix)
.enter().append("g")
.attr("class", "column")
.attr("transform", function(d, i) { return "translate(" + x(i) + ")rotate(-90)"; });
column.append("line")
.attr("x1", -width);
column.append("text")
.attr("x", 6)
.attr("y", x.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "start")
.text(function(d, i) { return nodes[i].name; });
function row(row) {
var cell = d3.select(this).selectAll(".cell")
.data(row.filter(function(d) { return d.z; }))
.enter().append("rect")
.attr("class", "cell")
.attr("x", function(d) { return x(d.x); })
.attr("width", x.rangeBand())
.attr("height", x.rangeBand())
.style("fill-opacity", function(d) { return z(d.z); })
.style("fill", function(d) { return nodes[d.x].group == nodes[d.y].group ? c(nodes[d.x].group) : c(0); })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
}
function mouseover(p) {
d3.selectAll(".row text").classed("active", function(d, i) { return i == p.y; });
d3.selectAll(".column text").classed("active", function(d, i) { return i == p.x; });
}
function mouseout() {
d3.selectAll("text").classed("active", false);
d3.selectAll("rect").attr("width",x.rangeBand());
d3.selectAll("rect").attr("height",x.rangeBand());
}
d3.select("#order").on("change", function() {
clearTimeout(timeout);
order(this.value);
});
function order(value) {
x.domain(orders[value]);
var t = svg.transition().duration(1500);
t.selectAll(".row")
.delay(function(d, i) { return x(i) * 4; })
.attr("transform", function(d, i) { return "translate(0," + x(i) + ")"; })
.selectAll(".cell")
.delay(function(d) { return x(d.x) * 4; })
.attr("x", function(d) { return x(d.x); });
t.selectAll(".column")
.delay(function(d, i) { return x(i) * 4; })
.attr("transform", function(d, i) { return "translate(" + x(i) + ")rotate(-90)"; });
}
var timeout = setTimeout(function() {
order("group");
d3.select("#order").property("selectedIndex", 2).node().focus();
}, 2000);
});
{
"nodes":[
{"abb":"AL","name":"Alabama","region":"East South Central","group":6},
{"abb":"AR","name":"Arkansas","region":"West South Central","group":7},
{"abb":"AZ","name":"Arizona","region":"Mountain","group":8},
{"abb":"CA","name":"California","region":"Pacific","group":9},
{"abb":"CO","name":"Colorado","region":"Mountain","group":8},
{"abb":"CT","name":"Connecticut","region":"New England","group":1},
{"abb":"DC","name":"DC","region":"South Atlantic","group":5},
{"abb":"DE","name":"Delaware","region":"South Atlantic","group":5},
{"abb":"FL","name":"Florida","region":"South Atlantic","group":5},
{"abb":"GA","name":"Georgia","region":"South Atlantic","group":5},
{"abb":"IA","name":"Iowa","region":"West North Central","group":4},
{"abb":"ID","name":"Idaho","region":"Mountain","group":8},
{"abb":"IL","name":"Illinois","region":"East North Central","group":3},
{"abb":"IN","name":"Indiana","region":"East North Central","group":3},
{"abb":"KS","name":"Kansas","region":"West North Central","group":4},
{"abb":"KY","name":"Kentucky","region":"East South Central","group":6},
{"abb":"LA","name":"Louisiana","region":"West South Central","group":7},
{"abb":"MA","name":"Massachusetts","region":"New England","group":1},
{"abb":"MD","name":"Maryland","region":"South Atlantic","group":5},
{"abb":"ME","name":"Maine","region":"New England","group":1},
{"abb":"MI","name":"Michigan","region":"East North Central","group":3},
{"abb":"MN","name":"Minnesota","region":"West North Central","group":4},
{"abb":"MO","name":"Missouri","region":"West North Central","group":7},
{"abb":"MS","name":"Mississippi","region":"East South Central","group":6},
{"abb":"MT","name":"Montana","region":"Mountain","group":8},
{"abb":"NC","name":"North Carolina","region":"South Atlantic","group":5},
{"abb":"ND","name":"North Dakota","region":"West North Central","group":4},
{"abb":"NE","name":"Nebraska","region":"West North Central","group":4},
{"abb":"NH","name":"New Hampshire","region":"New England","group":1},
{"abb":"NJ","name":"New Jersey","region":"Middle Atlantic","group":2},
{"abb":"NM","name":"New Mexico","region":"Mountain","group":8},
{"abb":"NV","name":"Nevada","region":"Mountain","group":8},
{"abb":"NY","name":"New York","region":"Middle Atlantic","group":2},
{"abb":"OH","name":"Ohio","region":"East North Central","group":3},
{"abb":"OK","name":"Oklahoma","region":"West South Central","group":7},
{"abb":"OR","name":"Oregon","region":"Pacific","group":9},
{"abb":"PA","name":"Pennsylvania","region":"Middle Atlantic","group":2},
{"abb":"RI","name":"Rhode Island","region":"New England","group":1},
{"abb":"SC","name":"South Carolina","region":"South Atlantic","group":5},
{"abb":"SD","name":"South Dakota","region":"West North Central","group":4},
{"abb":"TN","name":"Tennessee","region":"East South Central","group":6},
{"abb":"TX","name":"Texas","region":"West South Central","group":7},
{"abb":"UT","name":"Utah","region":"Mountain","group":8},
{"abb":"VA","name":"Virginia","region":"South Atlantic","group":5},
{"abb":"VT","name":"Vermont","region":"New England","group":1},
{"abb":"WA","name":"Washington","region":"Pacific","group":9},
{"abb":"WI","name":"Wisconsin","region":"East North Central","group":3},
{"abb":"WV","name":"West Virginia","region":"South Atlantic","group":5},
{"abb":"WY","name":"Wyoming","region":"Mountain","group":8}
],
"links":[
{"source":0,"target":8},
{"source":0,"target":9},
{"source":0,"target":23},
{"source":0,"target":40},
{"source":1,"target":16},
{"source":1,"target":22},
{"source":1,"target":23},
{"source":1,"target":34},
{"source":1,"target":40},
{"source":1,"target":41},
{"source":2,"target":3},
{"source":2,"target":30},
{"source":2,"target":31},
{"source":2,"target":42},
{"source":3,"target":31},
{"source":3,"target":35},
{"source":4,"target":14},
{"source":4,"target":27},
{"source":4,"target":30},
{"source":4,"target":34},
{"source":4,"target":42},
{"source":4,"target":48},
{"source":5,"target":17},
{"source":5,"target":32},
{"source":5,"target":37},
{"source":6,"target":18},
{"source":6,"target":43},
{"source":7,"target":18},
{"source":7,"target":29},
{"source":7,"target":36},
{"source":8,"target":9},
{"source":9,"target":25},
{"source":9,"target":38},
{"source":9,"target":40},
{"source":10,"target":12},
{"source":10,"target":21},
{"source":10,"target":22},
{"source":10,"target":27},
{"source":10,"target":39},
{"source":10,"target":46},
{"source":11,"target":24},
{"source":11,"target":31},
{"source":11,"target":35},
{"source":11,"target":42},
{"source":11,"target":45},
{"source":11,"target":48},
{"source":12,"target":13},
{"source":12,"target":15},
{"source":12,"target":22},
{"source":12,"target":46},
{"source":13,"target":15},
{"source":13,"target":20},
{"source":13,"target":33},
{"source":14,"target":22},
{"source":14,"target":27},
{"source":14,"target":34},
{"source":15,"target":22},
{"source":15,"target":33},
{"source":15,"target":40},
{"source":15,"target":43},
{"source":15,"target":47},
{"source":16,"target":23},
{"source":16,"target":41},
{"source":17,"target":28},
{"source":17,"target":32},
{"source":17,"target":37},
{"source":17,"target":44},
{"source":18,"target":36},
{"source":18,"target":43},
{"source":18,"target":47},
{"source":19,"target":28},
{"source":20,"target":33},
{"source":20,"target":46},
{"source":21,"target":26},
{"source":21,"target":39},
{"source":21,"target":46},
{"source":22,"target":27},
{"source":22,"target":34},
{"source":22,"target":40},
{"source":23,"target":40},
{"source":24,"target":26},
{"source":24,"target":39},
{"source":24,"target":48},
{"source":25,"target":38},
{"source":25,"target":40},
{"source":25,"target":43},
{"source":26,"target":39},
{"source":27,"target":39},
{"source":27,"target":48},
{"source":28,"target":44},
{"source":29,"target":32},
{"source":29,"target":36},
{"source":30,"target":34},
{"source":30,"target":41},
{"source":31,"target":35},
{"source":31,"target":42},
{"source":32,"target":36},
{"source":32,"target":44},
{"source":33,"target":36},
{"source":33,"target":47},
{"source":34,"target":41},
{"source":35,"target":45},
{"source":36,"target":47},
{"source":39,"target":48},
{"source":40,"target":43},
{"source":42,"target":48},
{"source":43,"target":47}
]
}
/* Copyright 2013 Michael Bostock. All rights reserved. Do not copy. */
@import url(//fonts.googleapis.com/css?family=PT+Serif|PT+Serif:b|PT+Serif:i|PT+Sans|PT+Sans:b);
html {
min-width: 800px;
}
.ocks-org body {
background: #fcfcfa;
color: #333;
font-family: "PT Serif", serif;
margin: 1em 2em 2em 5em;
width: 750px;
}
.ocks-org header,
.ocks-org footer,
.ocks-org aside,
.ocks-org h1,
.ocks-org h2,
.ocks-org h3,
.ocks-org h4 {
font-family: "PT Sans", sans-serif;
}
.ocks-org h1,
.ocks-org h2,
.ocks-org h3,
.ocks-org h4 {
color: #000;
}
.ocks-org header,
.ocks-org footer {
color: #636363;
}
h1 {
font-size: 64px;
font-weight: 300;
letter-spacing: -2px;
margin: .3em 0 .1em 0;
}
h2 {
margin-top: 2em;
}
h1, h2 {
text-rendering: optimizeLegibility;
}
h2 a[name],
h2 a[id] {
color: #ccc;
right: 100%;
padding: 0 .3em;
position: absolute;
}
header,
footer {
font-size: small;
}
.ocks-org header aside,
.ocks-org footer aside {
float: left;
margin-right: .5em;
}
.ocks-org header aside:after,
.ocks-org footer aside:after {
padding-left: .5em;
content: "/";
}
footer {
margin-top: 8em;
}
h1 ~ aside {
font-size: small;
right: 0;
position: absolute;
width: 180px;
}
.attribution {
font-size: small;
margin-bottom: 2em;
}
body > p, li > p {
line-height: 1.5em;
}
body > p {
width: 720px;
}
body > blockquote {
width: 640px;
}
blockquote q {
display: block;
font-style: oblique;
}
ul {
padding: 0;
}
li {
width: 690px;
margin-left: 30px;
}
a {
color: steelblue;
}
a:not(:hover) {
text-decoration: none;
}
pre, code, textarea {
font-family: "Menlo", monospace;
}
code {
line-height: 1em;
}
textarea {
font-size: 100%;
}
body > pre {
border-left: solid 2px #ccc;
padding-left: 18px;
margin: 2em 0 2em -20px;
}
.html .value,
.javascript .string,
.javascript .regexp {
color: #756bb1;
}
.html .tag,
.css .tag,
.javascript .keyword {
color: #3182bd;
}
.comment {
color: #636363;
}
.html .doctype,
.javascript .number {
color: #31a354;
}
.html .attribute,
.css .attribute,
.javascript .class,
.javascript .special {
color: #e6550d;
}
svg {
font: 10px sans-serif;
overflow-y: scroll;
overflow-x: hidden;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
sup, sub {
line-height: 0;
}
q:before {
content: "“";
}
q:after {
content: "”";
}
blockquote q {
line-height: 1.5em;
display: inline;
}
blockquote q:before,
blockquote q:after {
content: "";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment