R:删除gridExtra表中的重复行条目 问题:
我使用包创建一个表: 输出: 问题: 我想摆脱重复的行条目,并实现如下所示的跨行条目(此图像是用Photoshop制作的模型): 如何在R中以编程方式实现这一点R:删除gridExtra表中的重复行条目 问题:,r,gridextra,R,Gridextra,我使用包创建一个表: 输出: 问题: 我想摆脱重复的行条目,并实现如下所示的跨行条目(此图像是用Photoshop制作的模型): 如何在R中以编程方式实现这一点 require(grid) require(gridExtra) Loading required package: gridExtra df = data.frame(col1, col2, col3, stringsAsFactors=FALSE) df2 <- df df2[] <- lapply(d
require(grid)
require(gridExtra)
Loading required package: gridExtra
df = data.frame(col1, col2, col3, stringsAsFactors=FALSE)
df2 <- df
df2[] <- lapply(df2, function(col) col <- ifelse( !duplicated(col, fromLast=TRUE), col, ""))
df2
#---------------
col1 col2 col3
1 1
2 2
3 A 3
4 1 4
5 B 5
6 6
7 2 7
8 8
9 9
10 C 3 10
#-------------
grid.arrange(tableGrob(df2, show.rownames=F)) # works
以下是根据数据创建v矩阵的代码:
v <- as.matrix( as.data.frame( lapply(df,function(col)
ifelse(!duplicated(col), as.character(col), NA))) )
v
col1 col2 col3
[1,] 1 1 1
[2,] NA NA 2
[3,] NA NA 3
[4,] 2 NA 4
[5,] NA 2 5
[6,] 3 NA 6
[7,] NA NA 7
[8,] NA 3 8
[9,] NA NA 9
[10,] NA NA 10
g2 <- gtable_colheader(v)
header <- colnames(v)
head <- lapply(header, textGrob, gp=gpar(fontface="bold"))
w <- do.call(unit.c, lapply(header, stringWidth)) + unit(5, "mm")
h <- max(do.call(unit.c, lapply(head, grobHeight))) + unit(5, "mm")
hg <- gtable_matrix("header", widths=w, heights=h,
grobs=matrix(head, nrow=1))
grid.newpage()
grid.draw(gtable:::rbind_gtable(hg, g2, size="first"))
v我会使用gtable,并利用其更灵活的框架
require(gtable)
require(plyr)
## build a rectGrob with parameters
cellRect <- function(fill=NA)
rectGrob(gp=gpar(fill=fill, col=NA))
cellText <- function(label, colour="black",
hjust=c("left", "center", "right"), ...) {
hjust <- match.arg(hjust)
x <- switch(hjust,
"left" = 0,
"center"=0.5,
"right"=1)
textGrob(label, x=x, hjust=x, gp=gpar(col=colour, ...))
}
rowMax_units <- function(m){
do.call(unit.c, apply(m, 1, function(l)
max(do.call(unit.c, lapply(l, grobHeight)))))
}
colMax_units <- function(m){
do.call(unit.c, apply(m, 2, function(l)
max(do.call(unit.c, lapply(l, grobWidth)))))
}
findHeights <- function(l)
do.call(unit.c, lapply(l,grobHeight))
findWidths <- function(l)
do.call(unit.c, lapply(l,grobWidth))
## NAs are used to indicate grobs that span multiple cells
gtable_colheader <- function(header, n = NULL,
padding=unit(rep(5,5),"mm"), ...){
type <- 2L
if(is.null(n)) n <- max(apply(header, type, length))
start <- alply(header, type, function(s) which(!is.na(s), TRUE))
end <- llply(start, function(s) c(s[-1], n+1) - 1 )
fixed <- rep(seq_along(start), sapply(start, length)) # t,b for rows, l,r for cols
label <- header[!is.na(header)]
d <- data.frame(label = label,
start=unlist(start), end=unlist(end), fixed, fixed,
stringsAsFactors=FALSE)
names(d) <- c("label","t","b","l","r")
## make grobs
d$grobs <- lapply(d$label, cellText, hjust="center")
d$widths <- lapply(d$grobs, grobWidth)
d$heights <- lapply(d$grobs, grobHeight)
widths <- dlply(d, names(d)[4], # t if type==1, l if type==2
function(d) width=do.call(unit.c, d$widths))
heights <- dlply(d, names(d)[4],
function(d) heights=do.call(unit.c, d$heights))
## extract widths and heights relevant to the layout
attr(d, "widths") <- do.call(unit.c, lapply(widths, max))
attr(d, "heights") <- heights[[which(sapply(heights, length) == n)]]
## create gtable
g <- gtable()
g <- gtable_add_cols(g, attr(d,"widths") + padding[1])
g <- gtable_add_rows(g, attr(d,"heights")+ padding[2])
## vertical/horizontal separators
sgh <- segmentsGrob(x0 = unit(0, "npc"), y0 = unit(0, "npc"),
x1 = unit(1, "npc"), y1 = unit(0, "npc"),
gp=gpar(lwd=2, col="white"))
sgv <- segmentsGrob(x0 = unit(1, "npc"), y0 = unit(0, "npc"),
x1 = unit(1, "npc"), y1 = unit(1, "npc"),
gp=gpar(lwd=2, col="white"))
d2 <- subset(d, b < n)
g <- with(d2, gtable_add_grob(g, replicate(length(d2$grobs), sgh, simplify=FALSE),
t, l, b, r, z=1, name="seph"))
g <- gtable_add_grob(g, replicate(ncol(g)-1, sgv, simplify=FALSE),
t=1, b=nrow(g),l=seq.int(ncol(g)-1), z=1, name="sepv")
g <- with(d, gtable_add_grob(g, grobs, t, l, b, r, z=0, name="text"))
g <- gtable_add_grob(g, rectGrob(gp=gpar(fill="grey90", col="white")), t=1, l=1,
b=nrow(g), r=ncol(g), z=-Inf, name="rect")
g
}
v <- cbind(c("A", NA, NA, "B", NA, "C", NA, NA, NA, NA),
c(1, NA, NA, NA, 2, NA, NA, 3, NA, NA),
seq(1,10))
g2 <- gtable_colheader(v)
header <- paste0("col #",1:3)
head <- lapply(header, textGrob, gp=gpar(fontface="bold"))
w <- do.call(unit.c, lapply(header, stringWidth)) + unit(5, "mm")
h <- max(do.call(unit.c, lapply(head, grobHeight))) + unit(5, "mm")
hg <- gtable_matrix("header", widths=w, heights=h,
grobs=matrix(head, nrow=1))
grid.newpage()
grid.draw(gtable:::rbind_gtable(hg, g2, size="first"))
require(gtable)
需要(plyr)
##使用参数构建rectGrob
cellRect好奇号:您想在哪个应用程序中使用它?@Ferdinand.kraft:该表是作为knitr代码块的一部分生成的。我认为@Ferdinand.kraft不是这个意思。我认为问题更多的是“你为什么要这样做?”@AnandaMahto:Knitr代码块是LaTeX报告的一部分。该报告包含该表。为了便于阅读,我宁愿跳过重复的行条目。我知道还有其他与LaTeX输出相关的表包,但我更喜欢extraGrid的表特性。希望这能澄清“为什么”?我会使用GTTable。有几个例子被注释掉了。谢谢。您的代码有两个问题。第一,它覆盖col1中的字母,使其显示为数字;第二,跨越后的条目显示在底部。我更喜欢中间(我的问题)或者在上面。哦,见鬼!再次被f-ing因素所咬。只需在数据帧调用中使用stringsAsFactors=FALSE。(或使用<代码> AS。字符(COL)< /代码>),但是,我不知道你所指的是“中间”。对不起,我解释起来有点草率:例如:“C”不出现在第10行的组合单元格的底部,而是出现在中间。查看我的模型图像-它出现在第8行,而不是第10行。您可以提供用于构造该表的代码。我不打算继续这样做,因为它似乎需要一堆你已经做过的“网格”黑客。表格布局相关的答案基于baptiste的代码,而数据相关的代码来自DWN-非常感谢!哇,这在美学上是一个完美的解决方案。最后一个步骤对我来说是开放的:如何将我的数据帧df
转换为您用于回答的对象v
。你能不能修改一下你的答案,让它与我的数据框df配合使用?我想不出一个聪明的办法,所以你可能想问一个单独的问题question@user2030503我会发布代码,但你最好给巴普蒂斯特打勾,否则所有传下来的编码员都会缠着你,在你的大脑中插入额外的按键。是的,与表格布局相关的答案基于baptiste的代码,而与数据相关的代码来自DWN-非常感谢!属性(d,“高度”)属性(d,“高度”)
v <- as.matrix( as.data.frame( lapply(df,function(col)
ifelse(!duplicated(col), as.character(col), NA))) )
v
col1 col2 col3
[1,] 1 1 1
[2,] NA NA 2
[3,] NA NA 3
[4,] 2 NA 4
[5,] NA 2 5
[6,] 3 NA 6
[7,] NA NA 7
[8,] NA 3 8
[9,] NA NA 9
[10,] NA NA 10
g2 <- gtable_colheader(v)
header <- colnames(v)
head <- lapply(header, textGrob, gp=gpar(fontface="bold"))
w <- do.call(unit.c, lapply(header, stringWidth)) + unit(5, "mm")
h <- max(do.call(unit.c, lapply(head, grobHeight))) + unit(5, "mm")
hg <- gtable_matrix("header", widths=w, heights=h,
grobs=matrix(head, nrow=1))
grid.newpage()
grid.draw(gtable:::rbind_gtable(hg, g2, size="first"))
require(gtable)
require(plyr)
## build a rectGrob with parameters
cellRect <- function(fill=NA)
rectGrob(gp=gpar(fill=fill, col=NA))
cellText <- function(label, colour="black",
hjust=c("left", "center", "right"), ...) {
hjust <- match.arg(hjust)
x <- switch(hjust,
"left" = 0,
"center"=0.5,
"right"=1)
textGrob(label, x=x, hjust=x, gp=gpar(col=colour, ...))
}
rowMax_units <- function(m){
do.call(unit.c, apply(m, 1, function(l)
max(do.call(unit.c, lapply(l, grobHeight)))))
}
colMax_units <- function(m){
do.call(unit.c, apply(m, 2, function(l)
max(do.call(unit.c, lapply(l, grobWidth)))))
}
findHeights <- function(l)
do.call(unit.c, lapply(l,grobHeight))
findWidths <- function(l)
do.call(unit.c, lapply(l,grobWidth))
## NAs are used to indicate grobs that span multiple cells
gtable_colheader <- function(header, n = NULL,
padding=unit(rep(5,5),"mm"), ...){
type <- 2L
if(is.null(n)) n <- max(apply(header, type, length))
start <- alply(header, type, function(s) which(!is.na(s), TRUE))
end <- llply(start, function(s) c(s[-1], n+1) - 1 )
fixed <- rep(seq_along(start), sapply(start, length)) # t,b for rows, l,r for cols
label <- header[!is.na(header)]
d <- data.frame(label = label,
start=unlist(start), end=unlist(end), fixed, fixed,
stringsAsFactors=FALSE)
names(d) <- c("label","t","b","l","r")
## make grobs
d$grobs <- lapply(d$label, cellText, hjust="center")
d$widths <- lapply(d$grobs, grobWidth)
d$heights <- lapply(d$grobs, grobHeight)
widths <- dlply(d, names(d)[4], # t if type==1, l if type==2
function(d) width=do.call(unit.c, d$widths))
heights <- dlply(d, names(d)[4],
function(d) heights=do.call(unit.c, d$heights))
## extract widths and heights relevant to the layout
attr(d, "widths") <- do.call(unit.c, lapply(widths, max))
attr(d, "heights") <- heights[[which(sapply(heights, length) == n)]]
## create gtable
g <- gtable()
g <- gtable_add_cols(g, attr(d,"widths") + padding[1])
g <- gtable_add_rows(g, attr(d,"heights")+ padding[2])
## vertical/horizontal separators
sgh <- segmentsGrob(x0 = unit(0, "npc"), y0 = unit(0, "npc"),
x1 = unit(1, "npc"), y1 = unit(0, "npc"),
gp=gpar(lwd=2, col="white"))
sgv <- segmentsGrob(x0 = unit(1, "npc"), y0 = unit(0, "npc"),
x1 = unit(1, "npc"), y1 = unit(1, "npc"),
gp=gpar(lwd=2, col="white"))
d2 <- subset(d, b < n)
g <- with(d2, gtable_add_grob(g, replicate(length(d2$grobs), sgh, simplify=FALSE),
t, l, b, r, z=1, name="seph"))
g <- gtable_add_grob(g, replicate(ncol(g)-1, sgv, simplify=FALSE),
t=1, b=nrow(g),l=seq.int(ncol(g)-1), z=1, name="sepv")
g <- with(d, gtable_add_grob(g, grobs, t, l, b, r, z=0, name="text"))
g <- gtable_add_grob(g, rectGrob(gp=gpar(fill="grey90", col="white")), t=1, l=1,
b=nrow(g), r=ncol(g), z=-Inf, name="rect")
g
}
v <- cbind(c("A", NA, NA, "B", NA, "C", NA, NA, NA, NA),
c(1, NA, NA, NA, 2, NA, NA, 3, NA, NA),
seq(1,10))
g2 <- gtable_colheader(v)
header <- paste0("col #",1:3)
head <- lapply(header, textGrob, gp=gpar(fontface="bold"))
w <- do.call(unit.c, lapply(header, stringWidth)) + unit(5, "mm")
h <- max(do.call(unit.c, lapply(head, grobHeight))) + unit(5, "mm")
hg <- gtable_matrix("header", widths=w, heights=h,
grobs=matrix(head, nrow=1))
grid.newpage()
grid.draw(gtable:::rbind_gtable(hg, g2, size="first"))