r - 如何控制ggplot2中多个图的宽度?

标签 r map ggplot2

map 资料:InputSpatialData

产量数据:InputYieldData

结果_使用视口(viewport)():Plot

编辑:使用@rawr 建议的“multiplot”函数的结果(见下面的评论)。我确实喜欢新结果,尤其是 map 更大。尽管如此,箱线图似乎仍然与 map 图不一致。是否有更系统的方法来控制居中和放置?
Plot1

我的问题:有没有办法控制箱线图的大小以使其大小接近并以上方的 map 图为中心?

全码:

    ## Loading packages
    library(rgdal)
    library(plyr)
    library(maps)
    library(maptools)
    library(mapdata)
    library(ggplot2)
    library(RColorBrewer)
    library(foreign)  
    library(sp)
    library(ggsubplot)
    library(reshape)
    library(gridExtra)

    ## get.centroids: function to extract polygon ID and centroid from shapefile
    get.centroids = function(x){
    poly = wmap@polygons[[x]]
    ID   = poly@ID
    centroid = as.numeric(poly@labpt)
    return(c(id=ID, long=centroid[1], lat=centroid[2]))
    }

    ## read input files (shapefile and .csv file)
    wmap <- readOGR(dsn=".", layer="ne_110m_admin_0_countries")
    wyield <- read.csv(file = "F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/GTAP-CGE/GTAP_Sims&Rests/NewFiles/RMaps_GTAP/AllWorldCountries_CCShocksGTAP.csv", header=TRUE, sep=",", na.string="NA", dec=".", strip.white=TRUE)
    wyield$ID_1 <- substr(wyield$ID_1,3,10) # Eliminate the ID_1 column

    ## re-order the shapefile
    wyield <- cbind(id=rownames(wmap@data),wyield)

    ## Build table of labels for annotation (legend).
    labs <- do.call(rbind,lapply(1:17,get.centroids)) # Call the polygon ID and centroid from shapefile
    labs <- merge(labs,wyield[,c("id","ID_1","name_long")],by="id") # merging the "labs" data with the spatial data
    labs[,2:3] <- sapply(labs[,2:3],function(x){as.numeric(as.character(x))})
    labs$sort <- as.numeric(as.character(labs$ID_1))
    labs <- cbind(labs, name_code = paste(as.character(labs[,4]), as.character(labs[,5])))
    labs <- labs[order(labs$sort),]

    ## Dataframe for boxplot plot
    boxplot.df <- wyield[c("ID_1","name_long","A1B","A1BLow","A1F","A1T","A2","B1","B1Low","B2")]
    boxplot.df[1] <- sapply(boxplot.df[1], as.numeric)
    boxplot.df <- boxplot.df[order(boxplot.df$ID_1),]
    boxplot.df <- cbind(boxplot.df, name_code = paste(as.character(boxplot.df[,1]), as.character(boxplot.df[,2])))
    boxplot.df <- melt(boxplot.df, id=c("ID_1","name_long","name_code"))
    boxplot.df <- transform(boxplot.df,name_code=factor(name_code,levels=unique(name_code)))

    ## Define new theme for map
    ## I have found this function on the website
    theme_map <- function (base_size = 14, base_family = "serif") {
    # Select a predefined theme for tweaking features
    theme_bw(base_size = base_size, base_family = base_family) %+replace% 
    theme(
    axis.line=element_blank(),
    axis.text.x=element_text(size=rel(1.2), color="grey"),
    axis.text.y=element_text(size=rel(1.2), color="grey"),
    axis.ticks=element_blank(),
    axis.ticks.length=unit(0.3, "lines"),
    axis.ticks.margin=unit(0.5, "lines"),
    axis.title.x=element_text(size=rel(1.2), color="grey"),
    axis.title.y=element_text(size=rel(1.2), color="grey"),
    legend.background=element_rect(fill="white", colour=NA),
    legend.key=element_rect(colour="white"),
    legend.key.size=unit(1.3, "lines"),
    legend.position="right",
    legend.text=element_text(size=rel(1.3)),
    legend.title=element_text(size=rel(1.4), face="bold", hjust=0),
    panel.border=element_blank(),
    panel.grid.minor=element_blank(),
    plot.title=element_text(size=rel(1.8), face="bold", hjust=0.5, vjust=2),
    plot.margin=unit(c(0.5,0.5,0.5,0.5), "lines")
    )}

    ## Transform shapefile to dataframe and merge with yield data
    wmap_df <- fortify(wmap)
    wmap_df <- merge(wmap_df,wyield, by="id") # merge the spatial data and the yield data

    ## Plot map
    mapy <- ggplot(wmap_df, aes(long,lat, group=group)) 
    mapy <- mapy + geom_polygon(aes(fill=AVG))
    mapy <- mapy + geom_path(data=wmap_df, aes(long,lat, group=group, fill=A1BLow), color="white", size=0.4) 
    mapy <- mapy + labs(title="Average yield impacts (in %) across SRES scenarios ") + scale_fill_gradient2(name = "%Change in yield",low = "red3",mid = "snow2",high = "darkgreen") 
    mapy <- mapy + coord_equal() + theme_map()
    mapy <- mapy + geom_text(data=labs, aes(x=long, y=lat, label=ID_1, group=ID_1), size=6, family="serif") 
    mapy

    ## Plot boxplot
    boxploty <- ggplot(data=boxplot.df, aes(factor(name_code),value)) + 
    geom_boxplot(stat="boxplot", 
           position="dodge", 
           fill="grey",
           outlier.colour = "blue", 
           outlier.shape = 16, 
           outlier.size = 4) +
    labs(title="Distribution of yield impacts (in %) by GTAP region", y="Yield (% Change)") + theme_bw() + coord_flip() +
    stat_summary(fun.y = "mean", geom = "point", shape=21, size= 4, color= "red") +
    theme(plot.title = element_text(size = 26,
                              hjust = 0.5,
                              vjust = 1,
                              face = 'bold',
                              family="serif")) +
    theme(axis.text.x = element_text(colour = 'black',
                               size = 18,
                               hjust = 0.5, 
                               vjust = 1,
                               family="serif"),
    axis.title.x = element_text(size = 14, 
                               hjust = 0.5,
                               vjust = 0, 
                               face = 'bold',
                               family="serif")) +  
    theme(axis.text.y = element_text(colour = 'black', 
                               size = 18, 
                               hjust = 0, 
                               vjust = 0.5,
                               family="serif"), 
    axis.title.y = element_blank())
    boxploty

    ## I found this code on the website, and tried to tweak it to achieve my desired
    result, but failed
    # Plot objects using widths and height and respect to fix aspect ratios
    grid.newpage()
    pushViewport( viewport( layout = grid.layout( 2 , 1 , widths = unit( c( 1 ) , "npc" ) ,
                                                  heights = unit( c( 0.45 ) , "npc" ) , 
                                                  respect = matrix(rep(2,1),2) ) ) ) 
    print( mapy, vp = viewport( layout.pos.row = 1, layout.pos.col = 1 ) )
    print( boxploty, vp = viewport( layout.pos.row = 2, layout.pos.col = 1 ) )
    upViewport(0)
    vp3 <- viewport( width = unit(0.5,"npc") , x = 0.9 , y = 0.5)
    pushViewport(vp3)
    #grid.draw( legend )
    popViewport()

最佳答案

这和你的想法很接近吗?



代码:

library(rgdal)
library(ggplot2)
library(RColorBrewer)
library(reshape)
library(gridExtra)

setwd("<directory with all your files...>")

get.centroids = function(x){   # extract centroids from polygon with given ID
  poly = wmap@polygons[[x]]
  ID   = poly@ID
  centroid = as.numeric(poly@labpt)
  return(c(id=ID, c.long=centroid[1], c.lat=centroid[2]))
}

wmap   <- readOGR(dsn=".", layer="ne_110m_admin_0_countries")
wyield <- read.csv(file = "AllWorldCountries_CCShocksGTAP.csv", header=TRUE)
wyield <- transform(wyield, ID_1 = substr(ID_1,3,10))  #strip leading "TR"

# wmap@data and wyield have common, unique field: name
wdata  <- data.frame(id=rownames(wmap@data),name=wmap@data$name)
wdata  <- merge(wdata,wyield, by="name")
labs   <- do.call(rbind,lapply(1:17,get.centroids)) # extract polygon IDs and centroids from shapefile
wdata  <- merge(wdata,labs,by="id")
wdata[c("c.lat","c.long")] <- sapply(wdata[c("c.lat","c.long")],function(x) as.numeric(as.character(x)))

wmap.df <- fortify(wmap)                # data frame for world map
wmap.df <- merge(wmap.df,wdata,by="id") # merge data to fill polygons

palette <- brewer.pal(11,"Spectral")    # ColorBrewewr.org spectral palette, 11 colors
ggmap   <- ggplot(wmap.df, aes(x=long, y=lat, group=group))
ggmap   <- ggmap + geom_polygon(aes(fill=AVG))
ggmap   <- ggmap + geom_path(colour="grey50", size=.1)
ggmap   <- ggmap + geom_text(aes(x=c.long, y=c.lat, label=ID_1),size=3)
ggmap   <- ggmap + scale_fill_gradientn(name="% Change",colours=rev(palette))
ggmap   <- ggmap + theme(plot.title=element_text(face="bold"),legend.position="left")
ggmap   <- ggmap + coord_fixed()
ggmap   <- ggmap + labs(x="",y="",title="Average Yield Impacts across SRES Scenarios (% Change)")
ggmap   <- ggmap + theme(plot.margin=unit(c(0,0.03,0,0.05),units="npc"))
ggmap

box.df       <- wdata[order(as.numeric(wdata$ID_1)),]    # order by ID_1
box.df$label <- with(box.df, paste0(name_long," [",ID_1,"]")) # create labels for boxplot
box.df       <- melt(box.df,id.vars="label",measure.vars=c("A1B","A1BLow","A1F","A1T","A2","B1","B1Low","B2"))
box.df$label <- factor(box.df$label,levels=unique(box.df$label)) # need this so orderin is maintained in ggplot

ggbox   <- ggplot(box.df,aes(x=label, y=value))
ggbox   <- ggbox + geom_boxplot(fill="grey", outlier.colour = "blue", outlier.shape = 16, outlier.size = 4)
ggbox   <- ggbox + stat_summary(fun.y=mean, geom="point", shape=21, size= 4, color= "red")
ggbox   <- ggbox + coord_flip()
ggbox   <- ggbox + labs(x="", y="% Change", title="Distribution of Yield Impacts by GTAP region")
ggbox   <- ggbox + theme(plot.title=element_text(face="bold"), axis.text=element_text(color="black"))
ggbox   <- ggbox + theme(plot.margin=unit(c(0,0.03,0,0.0),units="npc"))
ggbox

grid.newpage()
pushViewport(viewport(layout=grid.layout(2,1,heights=c(0.40,0.60))))
print(ggmap, vp=viewport(layout.pos.row=1,layout.pos.col=1))
print(ggbox, vp=viewport(layout.pos.row=2,layout.pos.col=1))

解释:
最后 4 行代码完成了布局布局的大部分工作。我创建了一个视口(viewport)布局,其中 2 个视口(viewport)排列为 1 列中的 2 行。上视口(viewport)是网格高度的 40%,下视口(viewport)是高度的 60%。然后,在 ggplot调用我为 map 和箱线图创建了绘图宽度的 3% 的右边距,并为 map 创建了左边距,以便 map 和箱线图在左侧对齐。有相当多的调整可以让所有东西都对齐,但这些是可以使用的参数。你也应该知道,因为我们使用 coord_fixed()在 map 中,如果您更改绘图的整体大小(例如,通过调整绘图窗口的大小), map 的宽度将会改变。

最后,您创建等值线图的代码有点冒险......
## re-order the shapefile
wyield <- cbind(id=rownames(wmap@data),wyield)

这不会重新排序 shapefile。您在这里所做的只是在 wmap@data 前面添加行名到您的wyield数据。如果 wyield 中的行与 wmap 中的多边形的顺序相同,则此方法有效——这是一个非常危险的假设。如果不是,那么您将获得一张 map ,但着色将不正确,除非您非常仔细地研究输出,否则很可能会错过。所以上面的代码创建了多边形 ID 和区域名称之间的关联,合并了 wyield数据基于 name , 然后将其合并到 wmp.df基于多边形 id .
wdata  <- data.frame(id=rownames(wmap@data),name=wmap@data$name)
wdata  <- merge(wdata,wyield, by="name")
...
wmap.df <- fortify(wmap)                # data frame for world map
wmap.df <- merge(wmap.df,wdata,by="id") # merge data to fill polygons

关于r - 如何控制ggplot2中多个图的宽度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20817094/

相关文章:

r - 如何在 R 中的函数内部使用 colnames() 而不将数字输出转换为字符?

c++ - 如何正确清理 vector/ map ?

Rmarkdown Latex 对齐图形和 kbl 表(输出 PDF)

r - 渲染 RMarkdown 文档时修改全局环境

r - 基准分析和显示分析AND基准的结果?

R:为绘图标题、轴标签或图例创建拉丁文/希腊文表达式的向量

c++ - C++ 中 STL::MAP 的内部实现

java - 如何将对象向上转换为 java.util.Map?

r - 用ggplot中的函数定义的两条线之间的阴影区域

r - R 中箱形图到误差图的转换