You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并vcd包绘制的马赛克图并保留标签?

问题:合并vcd::mosaic生成的马赛克图报错

我尝试合并一系列通过vcd::mosaic生成的马赛克图,由于无法使用par(mfrow())将图形排布为2×2布局,于是在生成马赛克图并通过labeling_cells添加频率标签后,使用grid.grab()处理,但合并图形时出现错误。

原代码

mos<- function(bcoh, sex1, name, union2,m){ 
data2<-dataset_full_paper2_101 %>%
dplyr::filter(birthc==bcoh & sex=-sex1 & union==union2)

genga<-xtabs (~edu34+edu34_pa, data=data2)
t2<-round(prop.table(genga),2)

t3<-data.frame(t2)
t3$edu34<-as.numeric(t3$edu34)
t3$edu34_pa<- as.numeric(t3$edu34_pa)

genga2<-structable(~edu34+edu34_pa, data=t3) 
dimnames (genga2)<-list (edu34=c(1,2,3),edu34_pa=c(1,2,3))
txt<-as.table(matrix(paste0(t2), 3,3))
dimnames (txt)=dimnames (genga2)
colors=c("#d1e8e2", "#d1e8e2","#d1e8e2","#a9d6ca", "#a9d6ca", "#a9d6ca","#7cc7c0", "#7cc7c0", "#7cc7c0")

mosaic(x=genga2, pop-F, direction='v', gp-gpar (fill=colors), colorize=T, shade=T,
labeling_args=list(set_varnames=c(edu34="Education",
edu34_pa="Partner's education")),set_labels=c(list(edu34=c("Low", "Interm","High"), edu34_pa=c("Low", "Interm", "High")))
labeling_cells(text=txt, margin=0,clip=T)(genga2) 
m=grid.grab()
}

mos (0,2, "Married women born in 1932-1950",2,m1) 
mos (1,2, "Married women born in 1951-1970",2,m2) 
grid. arrange(m1,m2)

错误信息

mos (0,2, "Married women born in 1932-1950",2,m1) 警告信息:

1: In grabDL (warn, wrap, wrap.grobs, ...) :
viewport被覆盖(抓取结果可能不准确)
2: In grabDL (warn, wrap, wrap.grobs, ...) :
viewport被覆盖(抓取结果可能不准确)

mos (1,2, "Married women born in 1951-1970",2,m2) 警告信息:
1: In grabDL (warn, wrap, wrap.grobs, ...) : 
viewport被覆盖(抓取结果可能不准确)
2: In grabDL (warn, wrap, wrap.grobs, ...) :
viewport被覆盖(抓取结果可能不准确)

grid. arrange(m1,m2)
Error in gList(...) : only 'grobs' allowed in "gList"

解决方案

1. 修复核心语法错误

原代码存在多处语法错误,直接导致逻辑失效:

  • sex=-sex1 改为 sex==sex1(R中判断相等需用双等号)
  • pop-F 改为 pop=FALSE,gp-gpar (fill=colors) 改为 gp=gpar(fill=colors)(赋值需用单等号)
  • 移除无用的name参数,调整函数参数逻辑

2. 修正函数返回逻辑

原函数试图修改外部变量m1、m2,但R函数默认传值,不会直接修改外部对象。改为让函数返回grid.grab()的结果,再赋值给m1、m2

3. 解决viewport警告

给grid.grab()添加wrap=TRUE参数,将抓取的图形封装在独立viewport中,避免覆盖问题

修正后的完整代码

library(vcd)
library(dplyr)
library(grid)
library(gridExtra)

mos <- function(bcoh, sex1, union2){ 
  data2 <- dataset_full_paper2_101 %>%
    dplyr::filter(birthc == bcoh & sex == sex1 & union == union2)
  
  genga <- xtabs(~edu34 + edu34_pa, data = data2)
  t2 <- round(prop.table(genga), 2)
  
  t3 <- data.frame(t2)
  t3$edu34 <- as.numeric(t3$edu34)
  t3$edu34_pa <- as.numeric(t3$edu34_pa)
  
  genga2 <- structable(~edu34 + edu34_pa, data = t3) 
  dimnames(genga2) <- list(edu34 = c(1,2,3), edu34_pa = c(1,2,3))
  txt <- as.table(matrix(paste0(t2), 3,3))
  dimnames(txt) <- dimnames(genga2)
  colors <- c("#d1e8e2", "#d1e8e2","#d1e8e2","#a9d6ca", "#a9d6ca", "#a9d6ca","#7cc7c0", "#7cc7c0", "#7cc7c0")
  
  # 生成马赛克图并配置标签
  mosaic(x = genga2, pop = FALSE, direction = 'v', gp = gpar(fill = colors), 
         colorize = TRUE, shade = TRUE,
         labeling_args = list(set_varnames = c(edu34 = "Education",
                                               edu34_pa = "Partner's education")),
         set_labels = list(edu34 = c("Low", "Interm","High"), 
                          edu34_pa = c("Low", "Interm", "High")))
  # 添加频率标签
  labeling_cells(text = txt, margin = 0, clip = TRUE)(genga2) 
  
  # 抓取并返回grob对象,解决viewport警告
  return(grid.grab(wrap = TRUE))
}

# 调用函数获取grob对象
m1 <- mos(0, 2, 2) 
m2 <- mos(1, 2, 2) 

# 2列布局合并图形
grid.arrange(m1, m2, ncol = 2)

错误原因解析

  • Error in gList(...):原函数未正确返回grob对象,m1、m2实际为NULL,不是合法的图形对象,导致grid.arrange报错
  • viewport被覆盖警告:未给grid.grab()添加wrap=TRUE,抓取的图形共享viewport导致冲突,添加参数后可封装为独立图形单元

内容的提问来源于stack exchange,提问作者Lydia Palumbo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:45:02