-
-
Save biovisualize/4247094 to your computer and use it in GitHub Desktop.
Circular network in Tributary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tributary.Table = function module() { | |
var dispatch = d3.dispatch("edit"); | |
function exports(_selection) { | |
_selection.each(function (_dataset) { | |
//________________________________________________ | |
// Data | |
//________________________________________________ | |
var data = _dataset[0]; | |
var columnNames = _dataset[1]; | |
//________________________________________________ | |
// Table | |
//________________________________________________ | |
var table = d3.select(this).selectAll("table").data([0]); | |
table.enter().append('table') | |
.append('tr') | |
.attr('class', 'header-row') | |
.selectAll('th') | |
.data(columnNames) | |
.enter().append('th') | |
.attr('class', 'header no-select') | |
.text(function(d, i){return d;}); | |
var rows = table.selectAll('tr.row') | |
.data(data); | |
rows.enter().append('tr') | |
.attr('class', 'row'); | |
var cells = rows.selectAll('td.cell') | |
.data(function(d, i){return d;}) | |
cells.enter().append('td') | |
.attr({class: 'cell', contenteditable: true}); | |
cells.text(function(d, i){return d;}) | |
.on("keyup", function(d, i){ | |
var newData = []; | |
d3.select('.table').selectAll('tr.row').selectAll('td') | |
.each(function(d, i, pI){ | |
var text = d3.select(this).text(); | |
if (typeof newData[pI] == 'undefined') newData[pI] = []; | |
newData[pI].push(text) | |
}); | |
dispatch.edit(newData); | |
}); | |
}); | |
} | |
d3.rebind(exports, dispatch, "on"); | |
return exports; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tributary.CircularNetwork = function module() { | |
var opts = { | |
width: 200, | |
height: 200, | |
margins: {top:30, right:30, bottom:30, left:30}, | |
fillColorList: [ | |
"#3182bd", "#6baed6", "#9ecae1", "#c6dbef", | |
"#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", | |
"#31a354", "#74c476", "#a1d99b", "#c7e9c0", | |
"#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", | |
"#636363", "#969696", "#bdbdbd", "#d9d9d9" | |
], | |
enableTooltips: true, | |
enableBringToFront: true, | |
labelOffset: 5 | |
}; | |
function exports(_selection) { | |
_selection.each(function (_dataset) { | |
//________________________________________________ | |
// Data | |
//________________________________________________ | |
var dataset = d3.transpose(_dataset); | |
var start = dataset[0]; | |
var end = dataset[1]; | |
var weight = (dataset[2] == undefined) | |
? start.map(function(d, i){return 1;}) | |
: dataset[2].map(function(d){return parseInt(d);}); | |
//________________________________________________ | |
// Data transform | |
//________________________________________________ | |
var transformedData = d3.transpose([start, end, weight]); | |
// list of unique values to use as index | |
var unique = []; | |
transformedData.forEach(function(d, i){ | |
if(unique.indexOf(d[0]) == -1) unique.push(d[0]); | |
if(unique.indexOf(d[1]) == -1) unique.push(d[1]); | |
}); | |
// init square matrix | |
var matrix = d3.range(unique.length).map(function(){ | |
return d3.range(unique.length).map(function(){return 0;}); | |
}); | |
// compute matrix | |
transformedData.forEach(function(d, i){ | |
var row = unique.indexOf(d[1]); | |
var col = unique.indexOf(d[0]); | |
matrix[col][row] = d[2]; | |
}); | |
//________________________________________________ | |
// DOM selection | |
//________________________________________________ | |
var chartW = Math.max(opts.width - opts.margins.left - opts.margins.right, 0.1); | |
var chartH = Math.max(opts.height - opts.margins.top - opts.margins.bottom, 0.1); | |
var svg = d3.select(this).selectAll("svg").data([0]); | |
svg.enter().append("svg").attr({width: opts.width, height: opts.height}) | |
.append("g").attr({class: "vis-group", | |
transform: "translate(" + (opts.margins.left + chartW/2) + "," + (opts.margins.top + chartH/2) + ")"}); | |
var chartSVG = d3.select("g.vis-group"); | |
//________________________________________________ | |
// Circular network | |
//________________________________________________ | |
var fill = function(i) { | |
return opts.fillColorList[i % opts.fillColorList.length]; | |
} | |
var chord = d3.layout.chord().padding(.05).matrix(matrix); | |
var r1 = Math.min(chartW, chartH) / 2; | |
var r0 = r1 * 0.9; | |
// draw arcs | |
var groupSVG = chartSVG.selectAll("path.arc") | |
.data(chord.groups); | |
groupSVG.enter().append("path") | |
.attr("class", "arc") | |
groupSVG.attr("d", d3.svg.arc() | |
.innerRadius(r0) | |
.outerRadius(r1)) | |
.style("fill", function(d){ return fill(d.index);}); | |
groupSVG.exit().remove(); | |
// draw chords | |
var chordSVG = chartSVG.selectAll("path.link") | |
.data(chord.chords); | |
chordSVG.enter() | |
.append("path") | |
.attr("class", "link") | |
.call(highlight); | |
chordSVG.attr("d", d3.svg.chord().radius(r0)) | |
.style("fill",function (d) {return fill(d.target.index);}); | |
chordSVG.exit().remove(); | |
if(opts.enableBringToFront) chordSVG.call(bringToFront); | |
function highlight(_selection){ | |
_selection | |
.on("mouseover.highlight", function(d, i) { | |
d3.select(this).classed({highlighted: true}); | |
}) | |
.on("mouseout.highlight", function(d, i){ | |
d3.select(this).classed({highlighted: false}); | |
}); | |
} | |
function bringToFront(_selection){ | |
_selection.on("mouseover.toFront", function() { | |
var dragTarget = event.target; | |
dragTarget.parentNode.appendChild( dragTarget ); | |
}); | |
} | |
//________________________________________________ | |
// Labels | |
//________________________________________________ | |
var labelSVG = chartSVG.selectAll("text.label") | |
.data(chord.groups); | |
labelSVG.enter().append("text") | |
.attr("class", "label"); | |
labelSVG.each(function(d){ d.angle = (d.startAngle + d.endAngle) / 2; }) | |
.attr("text-anchor", function(d){ return d.angle > Math.PI ? "end" : null; }) | |
.attr("transform", function(d){ | |
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")" | |
+ "translate(" + (r1 + opts.labelOffset) + ")" | |
+ (d.angle > Math.PI ? "rotate(180)" : ""); | |
}) | |
.text(function(d, i){ return unique[i];}); | |
labelSVG.exit().remove(); | |
//________________________________________________ | |
// Tooltips | |
//________________________________________________ | |
if(opts.enableTooltips){ | |
var groupTooltip = tooltip() | |
.accessor(function(d, i){ | |
return "<strong>start</strong>: " + unique[i]; }); | |
var chordTooltip = tooltip() | |
.accessor(function(d, i){ | |
var tipText = "<strong>start</strong>: " + unique[d.source.index] + "<br/> " | |
+ "<strong>weight</strong>: " + d.source.value + "<br/> " | |
+ "to<br/>" | |
+ "<strong>end</strong>: " + unique[d.target.index] + "<br/>" | |
+ "<strong>weight</strong>: " + d.target.value; | |
return tipText; | |
}); | |
groupSVG.call(groupTooltip); | |
chordSVG.call(chordTooltip); | |
} | |
}); | |
} | |
exports.opts = opts; | |
createAccessors(exports); | |
return exports; | |
}; | |
var tooltip = function module(){ | |
var opts = { | |
accessor: function(d, i){return d;} | |
}; | |
function exports(selection){ | |
var tooltipDiv; | |
var body = d3.select("body"); | |
selection.on("mouseover.tooltip", function(d, i){ | |
d3.select("body").selectAll("div.tooltip").remove(); | |
tooltipDiv = body.append("div").attr("class", "tooltip"); | |
var absoluteMousePos = d3.mouse(body.node()); | |
tooltipDiv.style("left", (absoluteMousePos[0] + 10)+"px") | |
.style("top", (absoluteMousePos[1] - 15)+"px") | |
.style("position", "absolute") | |
.style("z-index", 1001); | |
var tooltipText = opts.accessor(d, i) || ""; | |
tooltipDiv.html(tooltipText); | |
}) | |
.on("mousemove.tooltip", function(d, i) { | |
var absoluteMousePos = d3.mouse(body.node()); | |
tooltipDiv.style("left", (absoluteMousePos[0] + 10)+"px") | |
.style("top", (absoluteMousePos[1] - 15)+"px"); | |
}) | |
.on("mouseout.tooltip", function(d, i){ | |
tooltipDiv.remove(); | |
}); | |
}; | |
exports.opts = opts; | |
createAccessors(exports); | |
return exports; | |
}; | |
function createAccessors(visExport) { | |
for (var n in visExport.opts) { | |
if (!visExport.opts.hasOwnProperty(n)) continue; | |
visExport[n] = (function(n) { | |
return function(v) { | |
return arguments.length ? (visExport.opts[n] = v, this) : visExport.opts[n]; | |
} | |
})(n); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Another Inlet","endpoint":"","display":"html","public":true,"require":[],"fileconfigs":{"circular_network.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"basic-editable-table.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"index.html":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"index.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"tab":"edit","display_percent":0.5495736906211939,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"hidepanel":false} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var display = d3.select('#display'); | |
var tableContainer = display.append('div').attr('class', 'table'); | |
var resetButton = display.append('div').attr('class', 'reset-button no-select'); | |
var chartContainer = display.append('div').attr('class', 'container'); | |
// Data | |
var data = [ | |
['page0', 'page1', 200], | |
['page1', 'page0', 50], | |
['page2', 'page0', 100], | |
['page0', 'page2', 100] | |
]; | |
var columnNames = ['Start', 'End', 'Weight'] | |
// Charts | |
var table = tributary.Table() | |
.on('edit', function(d){ update(d) }); | |
var circularNetwork = tributary.CircularNetwork() | |
.width(500) | |
.height(500) | |
.margins({top:50, right:50, bottom:50, left:50}) | |
.enableTooltips(true) | |
.labelOffset(5); | |
// Bind charts to DOM | |
function update(_data){ | |
chartContainer | |
.datum(_data) | |
.call(circularNetwork); | |
} | |
function updateTable(_data){ | |
tableContainer | |
.datum(_data) | |
.call(table); | |
} | |
update(data); | |
updateTable([data, columnNames]) | |
// Update charts on reset | |
resetButton | |
.on("mouseup", function(d, i){ | |
update(data); | |
updateTable([data, columnNames]) | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.reset-button{ | |
width: 50px; | |
height: 25px; | |
border: 1px solid black; | |
background-color: white; | |
cursor: pointer; | |
text-align: center; | |
position: absolute; | |
top: 260px; | |
} | |
.reset-button:hover{ | |
background-color: #eee; | |
} | |
.reset-button:active{ | |
background-color: #ccc; | |
} | |
.no-select{ | |
-webkit-touch-callout: none; | |
-webkit-user-select: none; | |
-khtml-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
table{ | |
border-collapse: collapse; | |
} | |
.table{ | |
position: absolute; | |
top: 100px; | |
} | |
.container{ | |
position: absolute; | |
top: 0; | |
left: 250px; | |
} | |
td, th{ | |
border: 1px solid black; | |
background-color: white; | |
width: 70px; | |
padding: 5px; | |
text-align: left; | |
} | |
th.header{ | |
cursor: default; | |
} | |
.tooltip{ | |
background-color: aliceblue; | |
pointer-events: none; | |
margin-left: 10px; | |
padding: 10px; | |
opacity: 0.8; | |
} | |
svg text.label{ | |
fill: black; | |
font: 10px Verdana; | |
} | |
svg path.arc{ | |
stroke: grey; | |
} | |
svg path.link{ | |
stroke: grey; | |
opacity: 0.9; | |
} | |
.highlighted{ | |
opacity: 1 !important; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment