中心对齐底部图例视口或相对于带有网格包的绘图区域

Center align bottom legend viewport or grob relative to plot area with grid package

我正在尝试对齐图表底部的图例,分别以该图表为中心。但我无法对齐它。 下面的图片显示了当前的渲染图,您可以清楚地看到图例未对齐(红线作为指导)。

library(grid)
draw <- function() {
    masterLayout <- grid.layout(
        nrow    = 4,
        ncol    = 1,
        heights = unit(c(0.1, 0.7, 0.1, 0.1), rep("null", 4)))

    vp1 <- viewport(layout.pos.row=1, layout.pos.col = 1, name="title")
    vp2 <- viewport(layout.pos.row=2, layout.pos.col = 1, name="plot")
    vp3 <- viewport(layout.pos.row=3, layout.pos.col = 1, name="legend")
    vp4 <- viewport(layout.pos.row=4, layout.pos.col = 1, name="caption")

    pushViewport(
        vpTree(viewport(layout = masterLayout, name = "master"),
                        vpList(vp1, vp2, vp3, vp4)))

    ## Draw main plot
    seekViewport("plot")
    pushViewport(viewport(width=unit(.8, "npc")))
    grid.rect(gp=gpar("fill"="red")) # dummy chart
    popViewport(2)

    ## Draw legend
    seekViewport("legend")

    colors <- list(first="red", second="green", third="blue")
    data.names <- names(colors)

    legend.cols <- length(data.names)
    pushViewport(viewport(
        width  = unit(0.8, "npc"),
        layout = grid.layout(ncol=legend.cols * 2,
                             nrow=1,
                             widths=unit(2.5, "cm"),
                             heights=unit(0.25, "npc"))))

    idx <- 0
    for(name in data.names)  {
        idx <- idx + 1
        pushViewport(viewport(layout.pos.row=1, layout.pos.col=idx))
        grid.circle(x=0, r=0.35, gp=gpar(fill=colors[[name]], col=NA))
        popViewport()

        idx <- idx + 1
        pushViewport(viewport(layout.pos.row=1, layout.pos.col=idx))
        grid.text(x=unit(-0.8, "npc"), "text", just="left")
        popViewport()
    }

    popViewport(2)
}
draw()

我不明白你为什么对单个视口做这么多。这使它变得非常复杂。我本以为为图例设置一个视口然后控制文本和圆圈相对于它的 x 坐标要容易得多。像这样的东西;我不确定这是否正是您想要的,但感觉如果您需要调整它应该很容易控制:

library(grid)
draw <- function() {
    masterLayout <- grid.layout(
        nrow    = 4,
        ncol    = 1,
        heights = unit(c(0.1, 0.7, 0.1, 0.1), rep("null", 4)))

    vp1 <- viewport(layout.pos.row=1, layout.pos.col = 1, name="title")
    vp2 <- viewport(layout.pos.row=2, layout.pos.col = 1, name="plot")
    vp3 <- viewport(layout.pos.row=3, layout.pos.col = 1, name="legend")
    vp4 <- viewport(layout.pos.row=4, layout.pos.col = 1, name="caption")

    pushViewport(
        vpTree(viewport(layout = masterLayout, name = "master"),
                        vpList(vp1, vp2, vp3, vp4)))

    ## Draw main plot
    seekViewport("plot")
    pushViewport(viewport(width=unit(.8, "npc")))
    grid.rect(gp=gpar("fill"="red")) # dummy chart
    popViewport(2)

    ## Draw legend
    seekViewport("legend")

    colors <- list(first="red", second="green", third="blue")
    lab_centers <- seq(from = 0.2, to = 0.8, length = length(colors))
    disp <- 0.03 # how far to left of centre circle is, and to right text is, in each label

    for(i in 1:length(colors)){
      grid.circle(x = lab_centers[i] - disp, r = 0.1, gp=gpar(fill = colors[[i]], col=NA))
      grid.text("text", x = lab_centers[i] + disp)

    }


    popViewport(2)
}
draw()
grid.lines(c(0.5, 0.5), c(0, 1))

如果您的图例标签长度不同,您可能需要将它们左对齐并调整我使用 disp 参数的方式,但不应该太难。