From 3b18c35311b524a14bb2024a51aba5afa36e6b2d Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Sun, 14 Jan 2024 22:05:48 +0100 Subject: [PATCH] Fix 226 Add cactustree layout --- NEWS.md | 3 ++ R/RcppExports.R | 4 ++ R/layout_cactustree.R | 65 +++++++++++++++++++++++ R/tbl_graph.R | 3 +- man/layout_tbl_graph_auto.Rd | 1 + man/layout_tbl_graph_backbone.Rd | 1 + man/layout_tbl_graph_cactustree.Rd | 82 ++++++++++++++++++++++++++++++ man/layout_tbl_graph_centrality.Rd | 1 + man/layout_tbl_graph_circlepack.Rd | 1 + man/layout_tbl_graph_dendrogram.Rd | 1 + man/layout_tbl_graph_eigen.Rd | 1 + man/layout_tbl_graph_fabric.Rd | 1 + man/layout_tbl_graph_focus.Rd | 1 + man/layout_tbl_graph_hive.Rd | 1 + man/layout_tbl_graph_igraph.Rd | 1 + man/layout_tbl_graph_linear.Rd | 1 + man/layout_tbl_graph_manual.Rd | 1 + man/layout_tbl_graph_matrix.Rd | 1 + man/layout_tbl_graph_partition.Rd | 1 + man/layout_tbl_graph_pmds.Rd | 1 + man/layout_tbl_graph_stress.Rd | 1 + man/layout_tbl_graph_treemap.Rd | 1 + man/layout_tbl_graph_unrooted.Rd | 1 + src/RcppExports.cpp | 17 +++++++ src/cactusTree.cpp | 64 +++++++++++++++++++++++ src/nodes.h | 8 +++ vignettes/Layouts.Rmd | 26 ++++++++++ 27 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 R/layout_cactustree.R create mode 100644 man/layout_tbl_graph_cactustree.Rd create mode 100644 src/cactusTree.cpp diff --git a/NEWS.md b/NEWS.md index 9c16663b..dea1fa6c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -21,6 +21,9 @@ * The linear layout has gained a `weight` argument allowing you to set how much space each node occupy. Further, the layout now calculates statistics so that it can be used in conjunction with `geom_node_tile()` and `geom_node_arc_bar()` +* New layout added. Cactustree is a hierarchical layout optimised for + hierarchical edge bundling by placing nodes as budding circles on the + periphery of their parent (#226) # ggraph 2.1.0 diff --git a/R/RcppExports.R b/R/RcppExports.R index d8d5cead..90fbde1a 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,6 +1,10 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 +cactusTree <- function(parent, order, weight, scale, overlap, upright) { + .Call('_ggraph_cactusTree', PACKAGE = 'ggraph', parent, order, weight, scale, overlap, upright) +} + #' Pack circles together #' #' This function is a direct interface to the circle packing algorithm used by diff --git a/R/layout_cactustree.R b/R/layout_cactustree.R new file mode 100644 index 00000000..5eeb18c5 --- /dev/null +++ b/R/layout_cactustree.R @@ -0,0 +1,65 @@ +#' Calculate nodes as fractal circle buds +#' +#' The cactustree layout is a hierarchical layout optimised for use with +#' hierarchical edge bundling ([geom_conn_bundle()]). It is a fractal layout +#' that places node children as circles on the periphery of their parent circle, +#' each circle scaled by the total weight of their children. +#' +#' @note +#' cactustree is a layout intended for trees, that is, graphs where nodes +#' only have one parent and zero or more children. If the provided graph does +#' not fit this format an attempt to convert it to such a format will be made. +#' +#' @param graph An `tbl_graph` object +#' +#' @param direction The direction of the tree in the graph. `'out'` (default) +#' means that parents point towards their children, while `'in'` means that +#' children point towards their parent. +#' +#' @param weight An optional node variable to use as weight. If `NULL` all leaf +#' nodes will be assigned a weight of `1`. +#' +#' @param scale_factor A scaling factor for the circles in the layout. The +#' radius will be calculated as `total_weight ^ scale_factor` with `total_weight` +#' being the weight of the node and all it's children. +#' +#' @param overlap How much is the center of child nodes offset from the +#' periphery of their parent as a proportion of their own radius. +#' +#' @param upright Logical. Should the children of the root only be distributed +#' around the top half of the root or all the way around. +#' +#' @param circular Logical. Should the layout be transformed to a circular +#' representation. Ignored. +#' +#' @return A data.frame with the columns `x`, `y`, `r`, `leaf`, `depth`, +#' `circular` as well as any information stored as node variables in the +#' tbl_graph object. +#' +#' @references +#' Dang, T., Forbes, A. (2017). *CactusTree: A Tree Drawing Approach +#' for Hierarchical Edge Bundling*. 2017 IEEE Pacific Visualization Symposium, +#' 210-214. https://doi.org/10.1109/PACIFICVIS.2017.8031596 +#' +#' @family layout_tbl_graph_* +#' +layout_tbl_graph_cactustree <- function(graph, direction = "out", weight = NULL, scale_factor = 0.75, overlap = 0.5, upright = FALSE, circular = FALSE) { + weight <- enquo(weight) + weight <- eval_tidy(weight, .N()) + if (is.null(weight)) { + weight <- as.numeric(degree(graph, mode = direction) == 0) + } + hierarchy <- tree_to_hierarchy(graph, direction, NULL, weight, NULL) + layout <- cactusTree(hierarchy$parent, hierarchy$order, hierarchy$weight, scale_factor, overlap, upright)[-1, ] + nodes <- data_frame0( + x = layout[, 1], + y = layout[, 2], + r = layout[, 3], + circular = FALSE, + leaf = degree(graph, mode = direction) == 0, + depth = node_depth(graph, mode = direction) + ) + nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) + attr(nodes, 'graph') <- add_direction(graph, nodes) + nodes +} diff --git a/R/tbl_graph.R b/R/tbl_graph.R index 98dd2868..91aadeec 100644 --- a/R/tbl_graph.R +++ b/R/tbl_graph.R @@ -84,7 +84,8 @@ prepare_graph <- function(graph, layout, direction = 'out', ...) { 'dendrogram', 'treemap', 'circlepack', - 'partition' + 'partition', + 'cactustree' ) graph_is_treeish <- with_graph(graph, graph_is_tree() || graph_is_forest()) if (is_hierarchy || (layout == 'auto' && graph_is_treeish)) { diff --git a/man/layout_tbl_graph_auto.Rd b/man/layout_tbl_graph_auto.Rd index 8387e950..0e836b08 100644 --- a/man/layout_tbl_graph_auto.Rd +++ b/man/layout_tbl_graph_auto.Rd @@ -32,6 +32,7 @@ than 2000 nodes). \seealso{ Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_backbone.Rd b/man/layout_tbl_graph_backbone.Rd index b1f2f761..8c753aad 100644 --- a/man/layout_tbl_graph_backbone.Rd +++ b/man/layout_tbl_graph_backbone.Rd @@ -36,6 +36,7 @@ Algorithms and Applications: JGAA, 19(2), 595-618. \seealso{ Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_cactustree.Rd b/man/layout_tbl_graph_cactustree.Rd new file mode 100644 index 00000000..1b192e3d --- /dev/null +++ b/man/layout_tbl_graph_cactustree.Rd @@ -0,0 +1,82 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/layout_cactustree.R +\name{layout_tbl_graph_cactustree} +\alias{layout_tbl_graph_cactustree} +\title{Calculate nodes as fractal circle buds} +\usage{ +layout_tbl_graph_cactustree( + graph, + direction = "out", + weight = NULL, + scale_factor = 0.75, + overlap = 0.5, + upright = FALSE, + circular = FALSE +) +} +\arguments{ +\item{graph}{An \code{tbl_graph} object} + +\item{direction}{The direction of the tree in the graph. \code{'out'} (default) +means that parents point towards their children, while \code{'in'} means that +children point towards their parent.} + +\item{weight}{An optional node variable to use as weight. If \code{NULL} all leaf +nodes will be assigned a weight of \code{1}.} + +\item{scale_factor}{A scaling factor for the circles in the layout. The +radius will be calculated as \code{total_weight ^ scale_factor} with \code{total_weight} +being the weight of the node and all it's children.} + +\item{overlap}{How much is the center of child nodes offset from the +periphery of their parent as a proportion of their own radius.} + +\item{upright}{Logical. Should the children of the root only be distributed +around the top half of the root or all the way around.} + +\item{circular}{Logical. Should the layout be transformed to a circular +representation. Ignored.} +} +\value{ +A data.frame with the columns \code{x}, \code{y}, \code{r}, \code{leaf}, \code{depth}, +\code{circular} as well as any information stored as node variables in the +tbl_graph object. +} +\description{ +The cactustree layout is a hierarchical layout optimised for use with +hierarchical edge bundling (\code{\link[=geom_conn_bundle]{geom_conn_bundle()}}). It is a fractal layout +that places node children as circles on the periphery of their parent circle, +each circle scaled by the total weight of their children. +} +\note{ +cactustree is a layout intended for trees, that is, graphs where nodes +only have one parent and zero or more children. If the provided graph does +not fit this format an attempt to convert it to such a format will be made. +} +\references{ +Dang, T., Forbes, A. (2017). \emph{CactusTree: A Tree Drawing Approach +for Hierarchical Edge Bundling}. 2017 IEEE Pacific Visualization Symposium, +210-214. https://doi.org/10.1109/PACIFICVIS.2017.8031596 +} +\seealso{ +Other layout_tbl_graph_*: +\code{\link{layout_tbl_graph_auto}()}, +\code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_centrality}()}, +\code{\link{layout_tbl_graph_circlepack}()}, +\code{\link{layout_tbl_graph_dendrogram}()}, +\code{\link{layout_tbl_graph_eigen}()}, +\code{\link{layout_tbl_graph_fabric}()}, +\code{\link{layout_tbl_graph_focus}()}, +\code{\link{layout_tbl_graph_hive}()}, +\code{\link{layout_tbl_graph_igraph}()}, +\code{\link{layout_tbl_graph_linear}()}, +\code{\link{layout_tbl_graph_manual}()}, +\code{\link{layout_tbl_graph_matrix}()}, +\code{\link{layout_tbl_graph_partition}()}, +\code{\link{layout_tbl_graph_pmds}()}, +\code{\link{layout_tbl_graph_stress}()}, +\code{\link{layout_tbl_graph_treemap}()}, +\code{\link{layout_tbl_graph_unrooted}()} +} +\concept{layout_tbl_graph_*} diff --git a/man/layout_tbl_graph_centrality.Rd b/man/layout_tbl_graph_centrality.Rd index 321d398a..e0ec8443 100644 --- a/man/layout_tbl_graph_centrality.Rd +++ b/man/layout_tbl_graph_centrality.Rd @@ -48,6 +48,7 @@ Graph Algorithms and Applications, 15(1), 157-173. Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, \code{\link{layout_tbl_graph_eigen}()}, diff --git a/man/layout_tbl_graph_circlepack.Rd b/man/layout_tbl_graph_circlepack.Rd index 7bfe3807..292b866d 100644 --- a/man/layout_tbl_graph_circlepack.Rd +++ b/man/layout_tbl_graph_circlepack.Rd @@ -67,6 +67,7 @@ Results and New Trends in Computer Science, 359-370. Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_dendrogram}()}, \code{\link{layout_tbl_graph_eigen}()}, diff --git a/man/layout_tbl_graph_dendrogram.Rd b/man/layout_tbl_graph_dendrogram.Rd index c148bd1b..7f754401 100644 --- a/man/layout_tbl_graph_dendrogram.Rd +++ b/man/layout_tbl_graph_dendrogram.Rd @@ -60,6 +60,7 @@ This function is not intended to be used directly but by setting Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_eigen}()}, diff --git a/man/layout_tbl_graph_eigen.Rd b/man/layout_tbl_graph_eigen.Rd index ec71277f..67f9a599 100644 --- a/man/layout_tbl_graph_eigen.Rd +++ b/man/layout_tbl_graph_eigen.Rd @@ -35,6 +35,7 @@ and extracting the eigenvectors. Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_fabric.Rd b/man/layout_tbl_graph_fabric.Rd index 70ad6f30..457b7c42 100644 --- a/man/layout_tbl_graph_fabric.Rd +++ b/man/layout_tbl_graph_fabric.Rd @@ -55,6 +55,7 @@ BMC Bioinformatics, 13: 275. \doi{10.1186/1471-2105-13-275} Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_focus.Rd b/man/layout_tbl_graph_focus.Rd index b358bba2..2ef91e07 100644 --- a/man/layout_tbl_graph_focus.Rd +++ b/man/layout_tbl_graph_focus.Rd @@ -45,6 +45,7 @@ Graph Algorithms and Applications, 15(1), 157-173. Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_hive.Rd b/man/layout_tbl_graph_hive.Rd index feacb79a..9d74a680 100644 --- a/man/layout_tbl_graph_hive.Rd +++ b/man/layout_tbl_graph_hive.Rd @@ -96,6 +96,7 @@ plots-rational approach to visualizing networks}. Brief Bioinform 13 (5): Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_igraph.Rd b/man/layout_tbl_graph_igraph.Rd index 1a41c06f..bf98feb7 100644 --- a/man/layout_tbl_graph_igraph.Rd +++ b/man/layout_tbl_graph_igraph.Rd @@ -107,6 +107,7 @@ This function is not intended to be used directly but by setting Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_linear.Rd b/man/layout_tbl_graph_linear.Rd index 79bafc80..f458fad9 100644 --- a/man/layout_tbl_graph_linear.Rd +++ b/man/layout_tbl_graph_linear.Rd @@ -49,6 +49,7 @@ between the nodes. Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_manual.Rd b/man/layout_tbl_graph_manual.Rd index 907fc024..a33bc43b 100644 --- a/man/layout_tbl_graph_manual.Rd +++ b/man/layout_tbl_graph_manual.Rd @@ -25,6 +25,7 @@ supplied positions must match the order of the nodes in the tbl_graph Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_matrix.Rd b/man/layout_tbl_graph_matrix.Rd index 089ef8d9..07815ec0 100644 --- a/man/layout_tbl_graph_matrix.Rd +++ b/man/layout_tbl_graph_matrix.Rd @@ -37,6 +37,7 @@ Computer Graphics Forum, 35: 693–716. \doi{10.1111/cgf.12935} Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_partition.Rd b/man/layout_tbl_graph_partition.Rd index 0d9e98a7..1f48cabf 100644 --- a/man/layout_tbl_graph_partition.Rd +++ b/man/layout_tbl_graph_partition.Rd @@ -75,6 +75,7 @@ https://doi.org/10.2307/2685881 Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_pmds.Rd b/man/layout_tbl_graph_pmds.Rd index fe7df263..a1b5cd79 100644 --- a/man/layout_tbl_graph_pmds.Rd +++ b/man/layout_tbl_graph_pmds.Rd @@ -34,6 +34,7 @@ Drawing (pp. 42-53). Springer Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_stress.Rd b/man/layout_tbl_graph_stress.Rd index 52d52f3b..023c82da 100644 --- a/man/layout_tbl_graph_stress.Rd +++ b/man/layout_tbl_graph_stress.Rd @@ -66,6 +66,7 @@ Ortmann, M. and Klimenta, M. and Brandes, U. (2016). \emph{A Sparse Stress Model Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_treemap.Rd b/man/layout_tbl_graph_treemap.Rd index 4175338c..0a77b344 100644 --- a/man/layout_tbl_graph_treemap.Rd +++ b/man/layout_tbl_graph_treemap.Rd @@ -88,6 +88,7 @@ Visualization, 284-291. \doi{10.1109/VISUAL.1991.175815} Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/man/layout_tbl_graph_unrooted.Rd b/man/layout_tbl_graph_unrooted.Rd index 1da7b195..df64d73c 100644 --- a/man/layout_tbl_graph_unrooted.Rd +++ b/man/layout_tbl_graph_unrooted.Rd @@ -61,6 +61,7 @@ Assoc., pp 573-584 Other layout_tbl_graph_*: \code{\link{layout_tbl_graph_auto}()}, \code{\link{layout_tbl_graph_backbone}()}, +\code{\link{layout_tbl_graph_cactustree}()}, \code{\link{layout_tbl_graph_centrality}()}, \code{\link{layout_tbl_graph_circlepack}()}, \code{\link{layout_tbl_graph_dendrogram}()}, diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index fa973d12..5a63a125 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -10,6 +10,22 @@ Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif +// cactusTree +NumericMatrix cactusTree(IntegerVector parent, IntegerVector order, NumericVector weight, double scale, double overlap, bool upright); +RcppExport SEXP _ggraph_cactusTree(SEXP parentSEXP, SEXP orderSEXP, SEXP weightSEXP, SEXP scaleSEXP, SEXP overlapSEXP, SEXP uprightSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); + Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); + Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); + Rcpp::traits::input_parameter< double >::type scale(scaleSEXP); + Rcpp::traits::input_parameter< double >::type overlap(overlapSEXP); + Rcpp::traits::input_parameter< bool >::type upright(uprightSEXP); + rcpp_result_gen = Rcpp::wrap(cactusTree(parent, order, weight, scale, overlap, upright)); + return rcpp_result_gen; +END_RCPP +} // pack NumericMatrix pack(NumericVector areas); RcppExport SEXP _ggraph_pack(SEXP areasSEXP) { @@ -129,6 +145,7 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { + {"_ggraph_cactusTree", (DL_FUNC) &_ggraph_cactusTree, 6}, {"_ggraph_pack", (DL_FUNC) &_ggraph_pack, 1}, {"_ggraph_circlePackLayout", (DL_FUNC) &_ggraph_circlePackLayout, 2}, {"_ggraph_dendrogram_spread", (DL_FUNC) &_ggraph_dendrogram_spread, 7}, diff --git a/src/cactusTree.cpp b/src/cactusTree.cpp new file mode 100644 index 00000000..c5a24f8e --- /dev/null +++ b/src/cactusTree.cpp @@ -0,0 +1,64 @@ +#include +#include "nodes.h" +using namespace Rcpp; + +void cactusTreeCircle(Node* node, double x, double y, double scale, double alpha, double span, double overlap) { + Rectangle r = {x, y, std::pow(node->weight(), scale), 0.0}; + node->bounds = r; + + if (node->leaf()) return; + + std::vector children = node->getChildren(); + + std::sort(children.begin(), children.end(), [](Node* a, Node* b){return a->weight() < b->weight();}); + std::vector ordered_children; + double total_angle = 0.0; + for (unsigned int i = 0; i < children.size(); i++) { + total_angle += std::pow(children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)); + ordered_children.insert(ordered_children.begin() + int(ordered_children.size() / 2), children[i]); + } + //std::reverse(ordered_children.begin(), ordered_children.end()); + //for (unsigned int i = 1; i < children.size(); i+=2) { + // ordered_children.push_back(children[i]); + //} + + alpha -= span / 2; + + for (unsigned int i = 0; i < ordered_children.size(); i++) { + //Rprintf("%f ", ordered_children[i]->weight()); + double local_span = 0.5 * span * std::pow(ordered_children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)) / total_angle; + alpha += local_span; + double child_r = std::pow(ordered_children[i]->weight(), scale); + double dist = node->bounds.width + child_r * overlap; + double x2 = x + dist * std::cos(alpha); + double y2 = y + dist * std::sin(alpha); + cactusTreeCircle(ordered_children[i], x2, y2, scale, alpha, 3.926991, overlap); + alpha += local_span; + } + //Rprintf("\n"); +} + +//[[Rcpp::export]] +NumericMatrix cactusTree(IntegerVector parent, IntegerVector order, NumericVector weight, double scale, double overlap, bool upright) { + NumericMatrix circ(parent.size(), 3); + unsigned int i; + + std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(order), as< std::vector >(weight)); + + Node* startNode = nodes[0]->getRoot(); + startNode->tallyWeights(); + if (startNode->nChildren() == 1) { + startNode = startNode->getChildren()[0]; + } + double start_span = upright ? 3.926991 : 6.283185; + cactusTreeCircle(startNode, 0.0, 0.0, scale, 1.570796, start_span, overlap); + + for (i = 0; i < nodes.size(); ++i) { + circ(i, 0) = nodes[i]->bounds.x; + circ(i, 1) = nodes[i]->bounds.y; + circ(i, 2) = nodes[i]->bounds.width; + delete nodes[i]; + } + + return circ; +} diff --git a/src/nodes.h b/src/nodes.h index 017e05d0..730068ee 100644 --- a/src/nodes.h +++ b/src/nodes.h @@ -117,6 +117,14 @@ class Node { } return leafs; } + void tallyWeights() { + for (unsigned int i = 0; i < children.size(); ++i) { + if (!children[i]->leaf()) { + children[i]->tallyWeights(); + } + Weight += children[i]->Weight; + } + } unsigned int nChildren() { return children.size(); }; diff --git a/vignettes/Layouts.Rmd b/vignettes/Layouts.Rmd index d77c8227..390ed8f7 100644 --- a/vignettes/Layouts.Rmd +++ b/vignettes/Layouts.Rmd @@ -253,6 +253,32 @@ ggraph(graph, 'treemap', weight = size) + geom_node_point(aes(colour = depth)) ``` +Cactustree is a layout type specifically developed for use with hierarchical +edge bundling, but can be used on it's own as well + +```{r} +ggraph(graph, 'cactustree') + + geom_node_circle(aes(fill = depth), size = 0.25) + + coord_fixed() +``` + +```{r} +importFrom <- match(flare$imports$from, flare$vertices$name) +importTo <- match(flare$imports$to, flare$vertices$name) + +ggraph(graph, 'cactustree') + + geom_node_circle(aes(fill = depth), + size = 0.25, + alpha = 0.2 + ) + + geom_conn_bundle(aes(colour = after_stat(index)), + data = get_con(importFrom, importTo), + edge_alpha = 0.25 + ) + + theme(legend.position = "none") + + coord_fixed() +``` + The most recognized tree plot is probably dendrograms though. If nothing else is stated the height of each node is calculated based on the distance to its farthest sibling (the tree layout, on the other hand, puts all nodes at a