Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hive plot to networkD3 #110

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
91 changes: 91 additions & 0 deletions R/hiveNetwork.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#' Create a D3 JavaScript hive plot representation of a network.
#'
#' @TODO
#' 1. Think about bindings from data.frame to: axis and group
#' 2. Limit to ? axis?
#'
#' @export
hiveNetwork <- function(nodes,
links,
source = NULL,
target = NULL,
linksize = NULL,
linkcolour = NULL,
nodeID = NULL,
x = NULL,
y = NULL,
nodesize = NULL,
nodecolour = NULL,
height = NULL,
width = NULL)
{

# some checks ----
if (!is.data.frame(links))
stop("Links must be a data frame class object.")

if (!is.data.frame(nodes))
stop("Nodes must be a data frame class object.")

# helper - rescale attributes to play nice with axis
.rescale <- function(x) (x - min(x))/(max(x) - min(x))

# axis binding
if (is.null(nodes$x)) {
indeces <- 1:nrow(nodes) - 1
indeces <- cbind( indeces %in% links$source & !indeces %in% links$target,
indeces %in% links$source & indeces %in% links$target,
!indeces %in% links$source & indeces %in% links$target)
nodes$x <- apply(indeces, 1, which)
}

# radius binding
nodes$y <- .rescale(nodes$y)

# node size binding
if (is.null(nodes$nodesize)) {
nodes$nodesize <- 5
}

# node size binding
if (is.null(nodes$nodecolour)) {
nodes$nodecolour <- nodes$x
}

# link size binding
if (is.null(links$linksize)) {
links$linksize <- 0.5
}

# link colour binding
if (is.null(links$linkcolour)) {
links$linkcolour <- links$source
}

# create options ----
options = list()

# create widget
htmlwidgets::createWidget(
name = "hiveNetwork",
x = list(links = links, nodes = nodes, options = options),
width = width,
height = height,
htmlwidgets::sizingPolicy(padding = 10, browser.fill = TRUE),
package = "networkD3"
)
}

#' @rdname networkD3-shiny
#' @export
hiveNetworkOutput <- function(outputId, width = "100%", height = "500px") {
shinyWidgetOutput(outputId, "hiveNetwork", width, height,
package = "networkD3")
}

#' @rdname networkD3-shiny
#' @export
renderHiveNetwork <- function(expr, env = parent.frame(), quoted = FALSE) {
if (!quoted) { expr <- substitute(expr) } # force quoted
shinyRenderWidget(expr, forceNetworkOutput, env, quoted = TRUE)
}
130 changes: 130 additions & 0 deletions inst/htmlwidgets/hiveNetwork.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
HTMLWidgets.widget({

name: "hiveNetwork",

type: "output",

initialize: function(el, width, height) {

var svg = d3.select(el).append("svg")
.attr("viewBox", "0 0 " + width + " " + height)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

return svg;
},

resize: function(el, width, height, instance) {
// handle with viewBox
},

renderValue: function(el, x, svg) {

// Convert radians to degrees
function degrees(radians) {
return radians / Math.PI * 180 - 90;
}

// get the width and height
var width = el.offsetWidth;
var height = el.offsetHeight;
var innerRadius = 40;
var outerRadius = Math.min(width, height)/2 - 20;

var angle = d3.scale.ordinal().domain(d3.range(4)).rangePoints([0, 2 * Math.PI]),
radius = d3.scale.linear().range([innerRadius, outerRadius]),
color = d3.scale.category10().domain(d3.range(20));

// alias options
// var options = x.options;

// convert links and nodes data frames to d3 friendly format
var nodes = HTMLWidgets.dataframeToD3(x.nodes);
var tmp = HTMLWidgets.dataframeToD3(x.links);

// create links associative array from nodes
var links = Array(tmp.length);
for (var i = 0; i < tmp.length; i++) {
links[i] = { "source" : nodes[tmp[i].source],
"target" : nodes[tmp[i].target],
"Linksize" : tmp[i].Linksize,
"Linkcolour" : tmp[i].Linkcolour
};
}

// map elements
svg.selectAll(".axis")
.data(d3.range(3))
.enter().append("line")
.attr("class", "axis")
.attr("transform", function(d) { return "rotate(" + degrees(angle(d)) + ")"; })
.attr("x1", radius.range()[0])
.attr("x2", radius.range()[1])
.style("stroke", '#000')
.style('stroke-width', '2px');

svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", d3.hive.link()
.angle(function(d) { return angle(d.x); })
.radius(function(d) { return radius(d.y); }))
.style("stroke", function(d) { return color(d.source.x); })
// .style("stroke", "#000")
.style('stroke-width', '0.5px')
.style("fill", "none");

svg.selectAll(".node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + degrees(angle(d.x)) + ")"; })
.attr("cx", function(d) { return radius(d.y); })
.style("fill", function(d) { return color(d.x); })
.attr("r", function(d) { return d.nodesize; })
.style("stroke", '#000')
.on("mouseenter", function(d) {
d3.select(this)
.transition()
.duration(50)
.style("stroke-width", 3)
.attr("r", 15);

d3.selectAll(".link")
.data(links)
.style("stroke-width", function (dl) {
if(dl.source == d){
return 5;
} else if(dl.target == d){
return 5;
} else {
return 0.5;
}
});
/*
.style("stroke", function (dl) {
if(dl.source == d){
return color(d.x);
} else if(dl.target == d){
return color(d.x);
} else {
return "#000";
}
});
*/
})
.on("mouseleave", function(d){
d3.select(this)
.transition()
.duration(50)
.style("stroke-width", 1.5)
.attr("r", function(d) { return d.nodesize; });

d3.selectAll(".link")
.style("stroke-width", 0.5);
// .style("stroke", "#000")
});
},
});
9 changes: 9 additions & 0 deletions inst/htmlwidgets/hiveNetwork.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dependencies:
- name: d3
version: 3.5.2
src: "htmlwidgets/lib/d3-3.5.2"
script: d3.min.js
- name: hive
version: 1.0
src: "htmlwidgets/lib"
script: d3.hive.min.js
1 change: 1 addition & 0 deletions inst/htmlwidgets/lib/d3.hive.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.