【问题标题】:ggplot and grid: Find the relative x and y positions of a point in a ggplot grobggplot 和网格:在 ggplot grob 中查找点的相对 x 和 y 位置
【发布时间】:2017-06-27 14:09:11
【问题描述】:

我正在组合多个 ggplot 图,使用网格视口,这是必要的(我相信),因为我想旋转一个图,这是标准 ggplot 甚至是 gridExtra 包中不可能实现的。

我想在两个图上画一条线,以使相关性更加清晰。但要确切知道线条在哪里,我需要 ggplot 图中某个点的相对位置(grob?)。

我做了以下例子:

require(reshape2)
require(grid)
require(ggplot2)


datamat <- matrix(rnorm(50), ncol=5)
cov_mat <- cov(datamat)
cov_mat[lower.tri(cov_mat)] <- NA

data_df <- melt(datamat)
cov_df <- melt(cov_mat)

plot_1 <- ggplot(data_df, aes(x=as.factor(Var2), y=value)) + geom_boxplot()
plot_2 <- ggplot(cov_df, aes(x=Var1, y=Var2, fill=value)) + 
                    geom_tile() +
                    scale_fill_gradient(na.value="transparent") + 
                    coord_fixed() +
                    theme(
                    legend.position="none",
                    plot.background = element_rect(fill = "transparent",colour = NA),
                    panel.grid=element_blank(),
                    panel.background=element_blank(),
                    panel.border = element_blank(),
                    plot.margin = unit(c(0, 0, 0, 0), "npc"),
                    axis.ticks=element_blank(), 
                    axis.title=element_blank(), 
                    axis.text=element_text(size=unit(0,"npc")),
                    )

cov_heatmap <- ggplotGrob(plot_2)
boxplot <- ggplotGrob(plot_1)

grid.newpage()

pushViewport(viewport(height=unit(sqrt(2* 0.4 ^2), 'npc'),
                      width=unit(sqrt(2* 0.4 ^2), 'npc'),
                      x=unit(0.5, 'npc'),
                      y=unit(0.63, 'npc'),
                      angle=-45,
                      clip="on")
            )
grid.draw(cov_heatmap)
upViewport(0)
pushViewport(viewport(height=unit(0.5, 'npc'),
                      width=unit(1, 'npc'),
                      x=unit(0.5, 'npc'),
                      y=unit(0.25, 'npc'),
                      clip="on")
            )
grid.draw(boxplot)

产生一个情节

如何找到箱线图第一个框的相对 x 和 y 位置?以及三角协方差矩阵的相对 x 和 y 位置。

我知道我必须查看 grob 对象boxplot,但我不知道如何在那里找到相关数据。

编辑:

我被要求提供一个绘图示例,手动添加线条,如下所示:

线条从底部图上的点到顶部图上的块。

【问题讨论】:

  • 这些事情确实很难做到(除非像@baptiste 这样的魔术师从旁边晃过)。您可能会发现绘制已使用 geom_polygon 旋转的顶部面板会更容易,然后将绘图与例如cowplot::plot_grid.
  • 谢谢,我去看看。但当然,如果我有解决问题的方法,我更喜欢它,因为它可能会在未来帮助我和其他人。
  • 两条线之间的线?你能手动画线来展示你想要的地方吗?
  • @naco,请查看我编辑的帖子。

标签: r ggplot2


【解决方案1】:

这是一个老问题,所以答案可能不再相关,但无论如何......

这并不简单,但可以使用grid 编辑工具来完成。人们需要一路收集信息,这使得解决方案变得繁琐。这是一个非常一次性的解决方案。很大程度上取决于两个 ggplots 的细节。但也许这里有足够的人使用。关于要绘制的线的信息不足;我将画两条红线:一条从第一个箱线图的横杆中心到热图左下图块的中心;一个从第一个箱线图的横杆中心到热图中的下一个图块。

几点:

  1. 要在不同的视口中绘制线条。通常,grobs 是在视口中绘制的,但是有几种方法可以在视口中获取线。我将使用grid 函数grid.move.to()grid.line.to()
  2. 可以在 grobs 的结构中找到 grobs 的坐标。那是, 可以提取第一个箱线图,并查看其结构。这 结构将给出晶须段的位置,a 横杆的线段,盒子的多边形。
  3. 同样,可以提取热图,结构会给出 每个矩形左上角的坐标(即, 热图中的每个图块),以及每个图块的宽度和高度 长方形。一些简单的算术将给出坐标 瓷砖的中心。
  4. 但是,矩形的坐标是根据 未旋转的视口。在选择相关矩形时需要小心谨慎。


# Draw the plot
require(reshape2)
require(grid)
require(ggplot2)

set.seed(4321) 
datamat <- matrix(rnorm(50), ncol=5)
cov_mat <- cov(datamat)
cov_mat[lower.tri(cov_mat)] <- NA

data_df <- melt(datamat)
cov_df <- melt(cov_mat)

plot_1 <- ggplot(data_df, aes(x=as.factor(Var2), y=value)) + geom_boxplot()
plot_2 <- ggplot(cov_df, aes(x=Var1, y=Var2, fill=value)) + 
                    geom_tile() +
                    scale_fill_gradient(na.value="transparent") + 
                    coord_fixed() +
                    theme(
                    legend.position="none",
                    plot.background = element_rect(fill = "transparent",colour = NA),
                    panel.grid=element_blank(),
                    panel.background=element_blank(),
                    panel.border = element_blank(),
                    plot.margin = unit(c(0, 0, 0, 0), "npc"),
                    axis.ticks=element_blank(), 
                    axis.title=element_blank(), 
                    axis.text=element_text(size=unit(0,"npc")))

cov_heatmap <- ggplotGrob(plot_2)
boxplot <- ggplotGrob(plot_1)

grid.newpage()

pushViewport(viewport(height=unit(sqrt(2* 0.4 ^2), 'npc'),
                      width=unit(sqrt(2* 0.4 ^2), 'npc'),
                      x=unit(0.5, 'npc'),
                      y=unit(0.63, 'npc'),
                      angle=-45,
                      clip="on",
                      name = "heatmap"))
grid.draw(cov_heatmap)
upViewport(0)
pushViewport(viewport(height=unit(0.5, 'npc'),
                      width=unit(1, 'npc'),
                      x=unit(0.5, 'npc'),
                      y=unit(0.25, 'npc'),
                      clip="on",
                      name = "boxplot"))
grid.draw(boxplot)
upViewport(0)


# So that grid can see all the grobs
grid.force()

# Get the names of the grobs
grid.ls()

相关位在与面板有关的部分中。热图 grob 的名称是:

geom_rect.rect.2

组成第一个箱线图的 grobs 的名称是(数字可以不同):

geom_boxplot.gTree.40
GRID.segments.34
geom_crossbar.gTree.39
geom_polygon.polygon.37
GRID.segments.38

获取热图中矩形的坐标。

names = grid.ls()$name
HMmatch = grep("geom_rect", names, value = TRUE)
hm = grid.get(HMmatch)

str(hm)
hm$x
hm$y
hm$width # heights are equal to the widths
hm$gp$fill

(注意just 设置为"left", "top")热图是一个 5 X 5 的矩形网格,但只有上半部分是彩色的,因此在图中可见。被选中的两个矩形的坐标分别是:(0.045, 0.227) 和(0.227, 0.409),每个矩形的宽和高都是0.182

获取第一个箱线图中相关点的坐标。

BPmatch = grep("geom_boxplot.gTree", names, value = TRUE)[-1]
box1 = grid.gget(BPmatch[1])
str(box1)

胡须的 x 坐标是 0.115,横杆的 y 坐标是 0.507

现在,在两个视口之间画线。线条在面板视口中“绘制”,但热图面板视口的名称与箱线图面板视口的名称相同。为了克服这个困难,我寻找箱线图视口,然后向下推到它的面板视口;同样,我寻找热图视口,然后向下推到它的面板视口。

## First Line (and points)
seekViewport("boxplot") 
downViewport("panel.7-5-7-5")
grid.move.to(x = .115, y = .503, default.units = "native")
grid.points(x = .115, y = .503, default.units = "native", 
      size = unit(5, "mm"), pch = 16, gp=gpar(col = "red"))


seekViewport("heatmap") 
downViewport("panel.7-5-7-5")
grid.line.to(x = 0.045 + .5*.182, y = 0.227 - .5*.182, default.units = "native", gp = gpar(col = "red", lwd = 2))
grid.points(x = 0.045 + .5*.182, y = 0.227 - .5*.182, default.units = "native", 
      size = unit(5, "mm"), pch = 16, gp=gpar(col = "red"))


## Second line (and points)
seekViewport("boxplot") 
downViewport("panel.7-5-7-5")
grid.move.to(x = .115, y = .503, default.units = "native")


seekViewport("heatmap") 
downViewport("panel.7-5-7-5")
grid.line.to(x = 0.227 + .5*.182, y = 0.409 - .5*.182, default.units = "native", gp = gpar(col = "red", lwd = 2))
grid.points(x = 0.227 + .5*.182, y = 0.409 - .5*.182, default.units = "native", 
      size = unit(5, "mm"), pch = 16, gp=gpar(col = "red"))

享受吧。

【讨论】:

  • 美丽的答案。谢谢!
猜你喜欢
  • 2018-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
相关资源
最近更新 更多