plot.GRiwrm.R 11.10 KiB
#' Plot of a diagram representing the network structure of a GRiwrm object
#'
#' @details
#' `header` parameter allows to add any mermaid code injected before the `graph`
#' instruction. It is notably useful for injecting directives that impact the
#' format of the graph. See [mermaid documentation on directives](https://mermaid.js.org/config/directives.html) for
#' more details and also the
#' [complete list of available directives](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/schemas/config.schema.yaml#L1878).
#'
#' @param x \[GRiwrm object\] data to display. See [CreateGRiwrm] for details
#' @param display [logical] if `TRUE` plots the diagram, returns the mermaid code otherwise
#' @param orientation [character] orientation of the graph. Possible values are
#'        "LR" (left-right), "RL" (right-left), "TB" (top-bottom), or "BT" (bottom-top).
#' @param with_donors [logical] for drawing boxes around ungauged nodes and their donors
#' @param box_colors [list] containing the color used for the different types of nodes
#' @param defaultClassDef [character] default style apply to all boxes
#' @param header mermaid script to add before the generated script (see Details)
#' @param footer mermaid script to add after the generated script
#' @param ... further parameters passed to [mermaid]
#' @return Mermaid code of the diagram if display is `FALSE`, otherwise the function returns the diagram itself.
#' @export plot.GRiwrm
#' @export
#' @seealso [CreateGRiwrm()]
#' @example man-examples/CreateGRiwrm.R
plot.GRiwrm <- function(x,
                        display = TRUE,
                        orientation = "LR",
                        with_donors = TRUE,
                        box_colors = c(UpstreamUngauged = "#eef",
                                       UpstreamGauged = "#aaf",
                                       IntermediateUngauged = "#efe",
                                       IntermediateGauged = "#afa",
                                       Reservoir = "#9de",
                                       DirectInjection = "#faa"),
                        defaultClassDef = "stroke:#333",
                        header = "%%{init: {'theme': 'neutral'} }%%",
                        footer = NULL,
                        ...) {
  stopifnot(inherits(x, "GRiwrm"),
            is.logical(display),
            length(display) == 1,
            is.character(orientation),
            length(orientation) == 1,
            is.character(box_colors),
            length(setdiff(names(box_colors), c("UpstreamUngauged", "UpstreamGauged",
                                                "IntermediateUngauged",   "IntermediateGauged",
                                                "DirectInjection", "Reservoir"))) == 0)
  x <- sortGRiwrm4plot(x)
  nodes <- unlist(sapply(unique(x$donor), plotGriwrmCluster, x = x, with_donors = with_donors))
  g2 <- x[!is.na(x$down),]
  if (nrow(g2) > 0) {
    links <- paste(
      sprintf("id_%1$s", g2$id),
      "-->|",
      round(g2$length, digits = 0),
      "km|",
      sprintf("id_%1$s", g2$down)
  } else {
    links <- ""
  x$nodeclass <- sapply(x$id, getNodeClass, griwrm = x)
  node_class <- lapply(unique(x$nodeclass), function(nc) {
    x$id[x$nodeclass == nc]
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
names(node_class) <- unique(x$nodeclass) node_class <- lapply(node_class, function(id) if (length(id) > 0) paste0("id_", id)) node_class <- paste("class", sapply(node_class, paste, collapse = ","), names(node_class)) css <- c( paste("classDef default", defaultClassDef), paste("classDef", names(box_colors), paste0("fill:", box_colors)), paste("classDef", paste0(names(box_colors[1:5]), "Diversion"), sprintf("fill:%s, stroke:%s, stroke-width:3px", box_colors[1:5], box_colors["DirectInjection"])) ) if (length(getDiversionRows(g2)) > 0) { css <- c(css, paste("linkStyle", getDiversionRows(g2) - 1, sprintf("stroke:%s, stroke-width:2px,stroke-dasharray: 5 5;", box_colors["DirectInjection"]))) } diagram <- paste(c(header, paste("graph", orientation), nodes, links, node_class, css, footer), collapse = "\n\n") class(diagram) <- c("mermaid", class(diagram)) if (display) { plot(diagram, ...) } else { return(diagram) } } #' Order GRiwrm network grouping it by donor #' #' This sort algorithm respects the original order of nodes but reorder nodes #' by donor groups by conserving the sort of first nodes by donor groups. #' #' @param g #' #' @return *GRiwrm* #' @noRd #' sortGRiwrm4plot <- function(g) { class_g <- class(g) g <- g %>% group_by(.data$donor) r <- attr(g, "groups")$.rows r_min <- sapply(r, min) r <- unlist(r[order(r_min)]) x <- g[r, ] class(x) <- class_g return(x) } #' Mermaid script for one donor cluster #' #' @param d donor id #' @param x GRiwrm #' #' @return mermaid script #' @noRd #' plotGriwrmCluster <- function(d, x, with_donors) { x <- x[getDiversionRows(x, TRUE), ] cluster_nodes <- sprintf("id_%1$s[%1$s]", x$id[is.na(d) | !is.na(x$donor) & x$donor == d]) if (length(cluster_nodes) > 1 && with_donors && !is.na(d)) { s <- c(sprintf("subgraph donor_%1$s [%1$s]", d), cluster_nodes, "end") } else { s <- cluster_nodes } return(s) } getNodeClass <- function(id, griwrm) {