8

有没有办法在网格窗口中获取绘图区域的宽度?例如,如果plot.margin更改或 y 轴标签的字体大小增加,它会增大或缩小。是隐藏在某处str(p)吗?

任何尺寸测量都可以。我需要能够测量不同场景下绘图区域宽度的相对变化,例如 y 轴标签的字体大小的变化。

在此处输入图像描述

df = data.frame(x = (1:3),One=c(12, 8, 13),Two=c(13, 7, 11),Three=c(11, 9, 11))
df.melt = melt(df, id.vars="x")

p = ggplot(df.melt, aes(x=x, y=value, color=variable)) + 
  geom_line() +
  coord_cartesian(xlim=c(min(df.melt$x),max(df.melt$x))) +
  theme(legend.position="none", plot.margin = unit(c(1, 4, 1, 1), "cm")) 
p

更新 - 澄清:请帮我计算a/b

在此处输入图像描述

p = ggplot(df.melt, aes(x=x, y=value, color=variable)) + 
  geom_line() + coord_cartesian(xlim=c(min(df.melt$x),max(df.melt$x))) +
  theme(legend.position="none")

p1 = p + theme(plot.margin=unit(c(1,1,1,1),"cm"), axis.text.y=element_text(size=10))
p2 = p + theme(plot.margin=unit(c(1,1,1,2),"cm"), axis.text.y=element_text(size=30))
grid.arrange(p1, p2, ncol=2)
4

3 回答 3

15

ggplot2 中的绘图使用网格图形。使用网格图形包生成的图形场景由 grobs 和视口组成。

您可以使用gridDebug包来检查 grobs。

  1. showGrob 显示用于绘制场景的 grobs 的位置和名称

          showGrob()
    
  2. 获取 grob 的 gpath

      sceneListing <- grid.ls(viewports=T, print=FALSE)
      do.call("cbind", sceneListing)
    
       name                                gPath                                                      
    [1,] "ROOT"                              ""                                                         
    [2,] "GRID.gTableParent.45019"           ""                                                         
    [3,] "background.1-5-6-1"                "GRID.gTableParent.45019"                                  
    [4,] "spacer.4-3-4-3"                    "GRID.gTableParent.45019"                                  
    [5,] "panel.3-4-3-4"                     "GRID.gTableParent.45019"                                  
    [6,] "grill.gTree.44997"                 "GRID.gTableParent.45019::panel.3-4-3-4"                   
    
  3. 取回 gorb

    h <- grid.get(gPath="GRID.gTableParent.45019")
    
  4. 获取 h 属性(例如)

    h$layoutvp$width
    

应用:

grid.get('x',grep=TRUE,global=T)
(polyline[panel.grid.minor.x.polyline.21899], polyline[panel.grid.major.x.polyline.21903], gTableChild[axis-l.3-3-3-3], gTableChild[axis-b.4-4-4-4], gTableChild[xlab.5-4-5-4]) 
>  grid.get('x',grep=TRUE,global=T)[[3]]
gTableChild[axis-l.3-3-3-3] 
>  xx <- grid.get('x',grep=TRUE,global=T)[[3]]
> grobWidth(xx)
[1] sum(1grobwidth, 0.15cm+0.1cm)
于 2012-12-13T21:03:28.837 回答
9

这引起了我足够的兴趣,以便更深入地研究它。我希望该grid.ls功能能够提供信息以导航到正确的视口以获取信息,但是对于您的示例,有一堆步骤被替换为“...”,我看不出如何更改它提供易于使用的东西。但是,使用grid.ls或其他工具,您可以看到不同视口的名称。对于您的示例,感兴趣的视口都命名为“panel.3-4-3-4”,下面是一些将导航到第一个的代码,找到以英寸为单位的宽度,导航到第二个并找到那个的宽度以英寸来算。

grid.ls(view=TRUE,grob=FALSE)
current.vpTree()
seekViewport('panel.3-4-3-4')
a <- convertWidth(unit(1,'npc'), 'inch', TRUE)
popViewport(1)
seekViewport('panel.3-4-3-4')
b <- convertWidth(unit(1,'npc'), 'inch', TRUE)
a/b

如果不弹出第一个面板,我想不出一个简单的方法来进入第二个面板。这有效并提供了您需要的信息,不幸的是,因为它从列表中弹出第一个面板,您无法返回它并查找其他信息或修改它。但这确实提供了您要求的信息,可以在未来的情节中使用。

也许其他人知道如何导航到第二个面板而不弹出第一个面板,或者让每个面板的完整 vpPath 直接导航。

于 2012-12-15T18:09:13.770 回答
5

这个答案主要是回复@java_xof的评论。回复太长并且包含代码,因此不适合评论。但是,它也可能有助于解决原始问题(或至少给出一个起点)。

这是一个函数和一些使用它的代码(它需要 tcltk 和 tkrplot 包):

library(ggplot2)
library(tkrplot)
TkPlotLocations <- function(FUN) {
    require(tkrplot)

    cl <- substitute(FUN)
    replot <- function() eval(cl)

    tt <- tktoplevel()
    img <- tkrplot(tt, replot, vscale=1.5, hscale=1.5)
    tkpack(img)

    tkpack(xfr <- tkframe(tt), side='left')
    tkpack(yfr <- tkframe(tt), side='left')

    xndc <- tclVar()
    yndc <- tclVar()
    xin <- tclVar()
    yin <- tclVar()

    tkgrid(tklabel(xfr, text='x ndc'), tklabel(xfr, textvariable=xndc))
    tkgrid(tklabel(yfr, text='y ndc'), tklabel(yfr, textvariable=yndc))
    tkgrid(tklabel(xfr, text='x inch'), tklabel(xfr, textvariable=xin))
    tkgrid(tklabel(yfr, text='y inch'), tklabel(yfr, textvariable=yin))

    iw <- as.numeric(tcl("image","width", tkcget(img, "-image")))
    ih <- as.numeric(tcl("image","height",tkcget(img, "-image")))

    cc <- function(x,y) {
        x <- (as.real(x)-1)/iw
        y <- 1-(as.real(y)-1)/ih
        c(x,y)
    }

    mm <- function(x, y) {
        xy <- cc(x,y)
        tclvalue(xndc) <- xy[1]
        tclvalue(yndc) <- xy[2]
        tclvalue(xin) <- grconvertX(xy[1], from='ndc', to='inches')
        tclvalue(yin) <- grconvertY(xy[2], from='ndc', to='inches')
    }

    tkbind( img, "<Motion>", mm)

    invisible()
}


x <- runif(25)
y <- rnorm(25, x, 0.25)
plot(x,y)
par()$pin
par()$plt
TkPlotLocations(plot(x,y))
qplot(x,y)
par()$pin
par()$plt
TkPlotLocations(print(qplot(x,y)))
qplot(x,y) + xlab('Multi\nline\nx\nlabel')
par()$pin
par()$plt
TkPlotLocations(print(qplot(x,y) + xlab('Multi\nline\nx\nlabel')))

定义上述函数,然后运行以下行将生成 3 个相同随机数据的图。您可以看到 3 个图的par()$pinpar()$plt(和其他参数)的结果完全相同,即使图中的绘图区域不同。

还会弹出 3 个新窗口,在这些窗口中,您可以将鼠标指针移到图形上,在窗口底部,您将看到指针的当前位置,以标准化设备坐标和英寸为单位(均来自设备区域的左下角)。您可以将鼠标指针悬停在图形(或任何其他部分)的角上以查看值并在 3 个图形之间进行比较。

这可能足以回答至少部分原始问题(只是不是以编程方式,这会更有用)。也可以修改该功能以打印出其他测量值。如果其他人有兴趣,我可能会扩展它并将其包含在将来的包中。

于 2012-12-14T18:19:39.840 回答