如何在R中为网络图添加文本?​​

时间:2015-10-15 15:15:06

标签: r plot

我正在使用包networkDynamic来可视化两个不断发展的网络,我想在每个网络附近添加一个简单的图例(几个文字)。我找不到这样做的方法。

networkDynamic包中,函数render.animation使用plot.network(来自包network)来渲染每个帧,然后将不同的帧编译成动画。

plot.network参数可以传递给render.animation,所以问题似乎归结为将文本添加到使用plot.network生成的图中但似乎没有办法在指定坐标处添加文本。

使用普通plot我会使用text函数,但有没有办法将此函数包含在plot.network参数中?

2 个答案:

答案 0 :(得分:0)

render.animationndtv包中的函数。您必须根据render.animation2创建自定义render.animation功能。在以下函数中,我向render.animation函数添加了一行。我在每次mtext次通话后添加plot.network(从最后看约20行)。您可以将其更改为text而不是mtext

render.animation2 <- function (net, render.par = list(tween.frames = 10, show.time = TRUE,
    show.stats = NULL, extraPlotCmds = NULL, initial.coords = 0),
    plot.par = list(bg = "white"), ani.options = list(interval = 0.1),
    render.cache = c("plot.list", "none"), verbose = TRUE, ...)
{
    if (!is.network(net)) {
        stop("render.animation requires the first argument to be a network object")
    }
    if (is.null(render.par)) {
        stop("render.animation is missing the 'render.par' argument (a list of rendering parameters).")
    }
    if (is.null(render.par$tween.frames)) {
        render.par$tween.frames <- 10
    }
    if (is.null(render.par$show.time)) {
        render.par$show.time <- TRUE
    }
    if (is.null(render.par$initial.coords)) {
        render.par$initial.coords <- matrix(0, ncol = 2, nrow = network.size(net))
    }
    if (!all(c("animation.x.active", "animation.y.active") %in%
        list.vertex.attributes(net))) {
        net <- compute.animation(net, verbose = verbose)
    }
    externalDevice <- FALSE
    doRStudioHack <- TRUE
    if (!is.null(render.par$do_RStudio_plot_hack)) {
        doRStudioHack <- render.par$do_RStudio_plot_hack
    }
    if (!is.function(options()$device)) {
        if (names(dev.cur()) == "RStudioGD" & doRStudioHack) {
            message("RStudio's graphics device is not well supported by ndtv, attempting to open another type of plot window")
            if (.Platform$OS.type == "windows") {
                windows()
            }
            else if (length(grep(R.version$platform, pattern = "apple")) >
                0) {
                quartz()
            }
            else {
                x11()
            }
            externalDevice <- TRUE
        }
    }
    if (par("bg") == "transparent" & is.null(plot.par$bg)) {
        plot.par$bg <- "white"
    }
    origPar <- par(plot.par)
    oopts <- ani.options(ani.options)
    slice.par <- get.network.attribute(net, "slice.par")
    if (is.null(slice.par)) {
        stop("render.animation can not locate the 'slice.par' list of parameters in the input network object")
    }
    render.cache <- match.arg(render.cache)
    plot_params <- list(...)
    if (is.null(plot_params$label)) {
        plot_params$label <- function(slice) {
            network.vertex.names(slice)
        }
    }
    if (is.null(plot_params$xlab) & render.par$show.time) {
        plot_params$xlab <- function(onset, terminus) {
            ifelse(onset == terminus, paste("t=", onset, sep = ""),
                paste("t=", onset, "-", terminus, sep = ""))
        }
    }
    if (!is.null(render.par$show.stats) && render.par$show.stats !=
        FALSE) {
        if (render.par$show.time) {
            plot_params$xlab <- eval(parse(text = paste("function(slice,onset,terminus){stats<-summary.statistics.network(slice",
                render.par$show.stats, ")\n return(paste('t=',onset,'-',terminus,' ',paste(rbind(names(stats),stats),collapse=':'),sep='')) }",
                sep = "")))
        }
        else {
            plot_params$xlab <- eval(parse(text = paste("function(slice){stats<-summary.statistics.network(slice",
                render.par$show.stats, ")\n return(paste(rbind(names(stats),stats),collapse=':')) }",
                sep = "")))
        }
    }
    if (is.null(plot_params$jitter)) {
        plot_params$jitter <- FALSE
    }
    interp.fun <- coord.interp.smoothstep
    starts <- seq(from = slice.par$start, to = slice.par$end,
        by = slice.par$interval)
    ends <- seq(from = slice.par$start + slice.par$aggregate.dur,
        to = slice.par$end + slice.par$aggregate.dur, by = slice.par$interval)
    xmin <- aggregate.vertex.attribute.active(net, "animation.x",
        min)
    xmax <- aggregate.vertex.attribute.active(net, "animation.x",
        max)
    ymin <- aggregate.vertex.attribute.active(net, "animation.y",
        min)
    ymax <- aggregate.vertex.attribute.active(net, "animation.y",
        max)
    if (is.null(plot_params$xlim)) {
        if (xmin == xmax) {
            xmax <- xmin + 1
            xmin <- xmin - 1
        }
        plot_params$xlim <- c(xmin, xmax)
    }
    if (is.null(plot_params$ylim)) {
        if (ymin == ymax) {
            ymax <- ymin + 1
            ymin <- ymin - 1
        }
        plot_params$ylim <- c(ymin, ymax)
    }
    if (is.numeric(render.par$initial.coords)) {
        coords <- matrix(render.par$initial.coords, ncol = 2,
            nrow = network.size(net))
    }
    slice <- network.collapse(net, starts[1], ends[1], rule = slice.par$rule,
        rm.time.info = FALSE)
    activev <- is.active(net, starts[1], ends[1], v = seq_len(network.size(net)),
        rule = if (slice.par$rule != "all") {
            "any"
        })
    if (length(slice) > 0 & network.size(slice) > 0) {
        coords[activev, 1] <- get.vertex.attribute(slice, "animation.x")
        coords[activev, 2] <- get.vertex.attribute(slice, "animation.y")
    }
    coords2 <- coords
    if (render.cache == "plot.list") {
        ani.record(reset = TRUE)
    }
    for (s in 1:length(starts)) {
        if (verbose) {
            print(paste("rendering", render.par$tween.frames,
                "frames for slice", s - 1))
        }
        slice <- network.collapse(net, starts[s], ends[s], rule = slice.par$rule,
            rm.time.info = FALSE)
        activev <- is.active(net, starts[s], ends[s], v = seq_len(network.size(net)),
            rule = if (slice.par$rule != "all") {
                "any"
            })
        if (length(slice) > 0 & network.size(slice) > 0) {
            evald_params <- .evaluate_plot_params(plot_params = plot_params,
                net = net, slice = slice, s = s, onset = starts[s],
                terminus = ends[s])
            for (t in 1:render.par$tween.frames) {
                coords2[activev, 1] <- get.vertex.attribute(slice,
                  "animation.x")
                coords2[activev, 2] <- get.vertex.attribute(slice,
                  "animation.y")
                tweenCoords <- interp.fun(coords, coords2, t,
                  render.par$tween.frames)
                plot_args <- list(x = slice, coord = tweenCoords[activev,
                  , drop = FALSE])
                plot_args <- c(plot_args, evald_params)
                do.call(plot.network, plot_args)
                mtext("my text\n on two lines", side = 3) #my.legend
                if (!is.null(render.par$extraPlotCmds)) {
                  eval(render.par$extraPlotCmds)
                }
                if (render.cache == "plot.list") {
                  ani.record()
                }
            }
            coords <- coords2
        }
        else {
            evald_params <- .evaluate_plot_params(plot_params = plot_params,
                net = net, slice = slice, s = s, onset = starts[s],
                terminus = ends[s])
            if (render.par$show.time) {
                xlab <- evald_params$xlab
            }
            else {
                xlab <- NULL
            }
            singlenet <- network.initialize(1)
            for (t in 1:render.par$tween.frames) {
                plot.network(singlenet, vertex.cex = 0, xlab = xlab)
                if (!is.null(render.par$extraPlotCmds)) {
                  eval(render.par$extraPlotCmds)
                }
                if (render.cache == "plot.list") {
                  ani.record()
                }
            }
        }
    }
    par(origPar)
    if (externalDevice) {
        dev.off()
    }
}

将新功能render.animation2分配给ndtv命名空间非常重要。如果不这样做,它将崩溃,因为render.animation引用的函数只能在它自己的命名空间中找到。

environment(render.animation2) <- asNamespace('ndtv')
environment(render.animation)  #<environment: namespace:ndtv>
environment(render.animation2) #<environment: namespace:ndtv>

使用,render.animation2,您将在动画的每张幻灯片上打印您的图例。

require(ndtv)
triangle <- network.initialize(3) # create a toy network
add.edge(triangle,1,2)
# add an edge between vertices 1 and 2
add.edge(triangle,2,3)
# add a more edges
activate.edges(triangle,at=1) # turn on all edges at time 1 only
activate.edges(triangle,onset=2, terminus=3,
e=get.edgeIDs(triangle,v=1,alter=2))
add.edges.active(triangle,onset=4, length=2,tail=3,head=1)
render.animation2(triangle) #custom function
ani.replay()

以下是动画中最后一张幻灯片的样子: enter image description here

答案 1 :(得分:-1)

如果您只需要添加几行文本,则可以传递标准绘图参数main(对于主标题)或xlab(对于x轴标题)。你可以用换行符&#34; \ n&#34;

分隔行
library(ndtv)
data(short.stergm.sim)
render.animation(short.stergm.sim,main='hello\nworld')

也可以使用legend参数text绘制其他图形元素(例如extraPlotCmdsrender.animation或地图)。例如,如果你想绘制&#34; hello world&#34;使用text在coordiantes 0,0的蓝色中,您可以将其包裹在expression中并通过render.par

传递给它
render.animation(short.stergm.sim,
                 render.par=list(extraPlotCmds=expression(
                                   text(0,0,'hello\nworld',col='blue')
                                ))
                 )

额外的绘图命令将在渲染网络时在每个帧上进行评估