grid包是一个底层的绘图系统,能够灵活地控制图形输出的外观和布局,但是grid包不提供创建完整图形的高级绘图系统,例如,ggplot2和lattice,而是提供绘制开发这些高级绘图的基础接口,例如:定制lattice的输出,产生高水平图或非统计图,为输出添加复杂注释。在绘图时,有时候会遇到这样一种情景,客户想把多个代表不同KPI的图形分布到同一个画布(Page)上,而且每一个图形都是单独绘制的。对于这种需求,可以使用grid包来实现,grid包能把图形逐个地添加到画布中,并按照业务的需求,把图形摆放到合适的位置上去。在布局完成之后,把图形绘制出来。

一,grid包概述

grid包不仅可以输出图形,还可以产生可编辑的图形组件,这些图形组件可以被复用和重组,并能把图形输出到指定的位置上。在使用grid包之前,需要安装和载入grid包:

install.packages("grid")
library(grid)

1,绘图原语

常用的绘图原语的明明格式是grid.**,用于输出图形:

grid.rect(...)
grid.lines(...)
grid.polygon(...)
grid.circle(...)
grid.text(...)

用户可以通过参数修改绘图函数输出的图形:

grid.rect(x = unit(0, “native"), y = unit(1.5, “npc"), height = unit(0.5, "inches"), width = unit(0.8, “lines”),
gp=gpar(col="red", lwd=2, fill="yellow", lty="dotted"))

2,Grob对象

每一个绘图原语都对应一个Grob,grob的命名格式是**Grob,Grob对象是一个可编辑的图形组件,该组件保留图形的所有属性,但不会立即输出图形:

rectGrob(...)
linesGrob(...)
polygonGrob(...)
circleGrob(...)
textGrob(..)

要输出Grob表示的图形,可以使用grid.draw()函数绘制图形:

rect <- rectGrob(...)
grid.draw(rect)

二,核心对象viewport

绘制图形需要画布,是R的绘图设备,在grid包中,画布被定义为page,通过函数newpage()创建一个新的画布:

grid.newpage()

viewport是grid包的核心对象,简单来说,它就是画布中的一个矩形的绘图区域,直译为视口,通过viewport()函数新建一个viewport对象:

viewport(x = unit(0.5, "npc"), y = unit(0.5, "npc"),
width = unit(1, "npc"), height = unit(1, "npc"),
default.units = "npc", just = "centre",
gp = gpar(), clip = "inherit",
xscale = c(0, 1), yscale = c(0, 1),
angle = 0,
layout = NULL,
layout.pos.row = NULL, layout.pos.col = NULL,
name = NULL)

参数注释:

  • x:视口的几何中心点相对页面左下角原点的x坐标轴,默认单位是npc
  • y:视口的几何中心点相对页面左下角原点的y坐标轴,默认单位是npc
  • width:视口的宽度(x轴方向)
  • height:视口的高度(y轴方向)
  • default.units:默认单位为npc (Normalised Parent Coordinates),含义是规范化化的父区域坐标
  • just:x和y所指的位置,默认为矩形中心位置
  • gp:gpar对象,用于设置图形参数;
  • clip:裁剪区域,有效值是“on”,“inherit”或“off”,指示剪裁到视口范围内,从父视口继承剪裁区域,或者完全关闭剪裁。 为了后向兼容性,逻辑值TRUE对应于“on”,而FALSE对应于“inherit”
  • xscale,yscale:两个数值元素的向量,用于表示坐标轴的最小值和最大值。
  • angle:把视口逆时针旋转的角度
  • layout:布局(grid.layout)对象,用于把视口划分为多个子区域
  • layout.pos.row,layout.pos.col:子区域在父布局中的行位置和列位置
  • name:此视口的名字,用于搜索和定位

viewport是绘图的基础,创建一个viewport:

vp <- viewport(x = 0.5, y = 0.5, width = 0.5, height = 0.25, angle=45)

通过函数grid.show.viewport()查看创建的视口:

grid.show.viewport(viewport(x=0.6, y=0.6, width=unit(1, "inches"), height=unit(1, "inches"), angle=30))

height和width是矩形的长和宽,x和y是视口中心点(也就是,矩形的几何中心点)距离x坐标抽和y坐标轴的距离:

三,基于viewport绘制图形

使用grid包绘图时,首先要创建一个空的画布:

grid.newpage()

在画布中创建viewport对象:

vp <- viewport(x = 0.5, y = 0.5, width = 0.5, height = 0.25, angle=45)

此时,画布中是空的,需要把viewport推到画布中:

pushViewport(vp)

viewport是绘图的区域,也就是说,基于viewport绘制图形,在视口规定的范围内作图,例如,向视口中绘制矩形。

grid.rect()

四,viewport树

grid包为每一个画布维护了一个由viewport构成的树,树的根节点是由系统创建的,名字是ROOT的viewport,每一个节点都是一个viewport。活跃viewport是树的当前位置,在树中是唯一的,用户只能向活跃viewport中绘图,所有的操作都是基于活跃viewport。viewport()函数用于创建viewport,而一个viewport只有被push到viewport树中,才能在其区域中绘图。

通过5个函数实现对viewport树的遍历和更新:

  • pushViewport()函数:向活跃viewport中添加一个viewport,作为树中的活跃viewport,原活跃viewport变成父viewport,这意味着,当一个viewport被push到树中时,该viewport变成活跃viewport,是原活跃viewport的子viewport。
  • popViewport()函数:把活跃viewport从树中删除,其父viewport变成活跃viewport。
  • upViewport()函数:导航到活跃viewport的父viewport,当前viewport变成活跃viewport,原viewport不会被删除;
  • downViewport()函数:导航到活跃viewport的父viewport,当前viewport变成活跃viewport,原viewport不会被删除;
  • searchViewport()函数:根据viewport的名字,导航到任意viewport,当前viewport变成活跃viewport,原viewport不会被删除。

注意:当向树中push一个viewport时,如果树中存在一个级别(level)相同,名字相同的viewport,那么push操作会把该viewport替换掉。

There is only ever one current viewport, which is the current position within the viewport tree. All drawing and viewport operations are relative to the current viewport. When a viewport is pushed it becomes the current viewport. When a viewport is popped, the parent viewport becomes the current viewport. Use upViewport to navigate to the parent of the current viewport, without removing the current viewport from the viewport tree. Use downViewport to navigate to a viewport further down the viewport tree and seekViewport to navigate to a viewport anywhere else in the tree.

查看当前的viewport树结构:

current.vpTree()

例如,下面我们连续push三个viewport到一个图形中。

grid.newpage()
colvec <- c('red', 'green', 'blue')
xvec <- c(0.3, 0.4, 0.5)
for (i in 1 : 3) {
vp <- viewport(x = xvec[i], y = 0.5, width = 0.4, height = 0.4,
gp = gpar(col = colvec[i]))
pushViewport(vp)
grid.rect()
}

绘制的图形依次嵌套,这说明,每push一次,原活跃viewport都变成父节点,把当前的veiwport作为子viewport:

五,布局

grid包中定义了布局对象,布局是矩形的子分区,也就是说,布局(layout)把一个矩形区域细分为更小的分区。

grid.layout(nrow = 1, ncol = 1,
widths = unit(rep_len(1, ncol), "null"), heights = unit(rep_len(1, nrow), "null"),
default.units = "null", respect = FALSE, just="centre")

参数注释:

  • nrow,ncol:布局分为多少个行和列,每一个行和列构成的单元叫做分区(subdivision)
  • widths,heights:每一个分区的宽和高
  • default.units:默认单位
  • respect:逻辑值,如果为true,指定行高度和列宽度都遵守。
  • just:指定对齐方式,有效的值是:"left", "right", "centre", "center", "bottom", 和 "top".

1,创建布局

把top.vp视口分割为3X3的分区,使用函数grid.show.layout()查看布局,创建的布局如下图所示:

layout <- grid.layout(nrow=3, ncol=3,
widths=unit(c(5, 1, 2), c("lines", "null", "lines")),
heights=unit(c(5, 1, 4), c("lines", "null", "lines"))) top.vp <-viewport(layout=layout, name="top") grid.show.layout(layout)

创建一系列的viewport,占用布局的各个分区,由于没有push任何viewport,因此画布中没有绘制任何图形。在为每个视口命名时,使用统一的格式:margin+数值,如下代码所示:

margin1 <- viewport(layout.pos.col = 2, layout.pos.row = 3, name = "margin1") #(3,2)
margin2 <- viewport(layout.pos.col = 1, layout.pos.row = 2, name = "margin2") #(2,1)
margin3 <- viewport(layout.pos.col = 2, layout.pos.row = 1, name = "margin3") #(1,2)
margin4 <- viewport(layout.pos.col = 3, layout.pos.row = 2, name = "margin4") #(2,3)
plot <- viewport(layout.pos.col = 2, layout.pos.row = 2, name = "plot") #(2,2)

R用数字来表示位置,数值代表的含义是:1=Buttom,2=Left,3=Top,4=Right,视口被布局分割的分区如下图所示:

2,创建viewport树

使用vpList()把视口排列成一个树形结构,并把top.vp作为视图的父节点,把所有其他视口作为子节点,使用vpTree()创建一个viewport树:

 splot <- vpTree(top.vp, vpList(margin1, margin2, margin3, margin4, plot))

把整个viewport树push到活跃视口中,这样,在绘图区域中,我们可以在不同的散点视口中绘制图形。

 pushViewport(splot)

在把整个树push到活跃视口之后,就可以在不同的区域内绘制图形,使用seekViewport()函数按照视口名称切换到指定的视口,并把当前视口激活。

seekViewport("plot")
grid.xaxis()
grid.yaxis()
grid.rect()
grid.points(x, y)

完整的代码如下:

library(grid)

layout <- grid.layout(nrow=3, ncol=3,
widths=unit(c(5, 1, 2), c("lines", "null", "lines")),
heights=unit(c(5, 1, 4), c("lines", "null", "lines")))
#grid.show.layout(layout) top.vp <-viewport(layout=layout,name="top")
#grid.show.viewport(top.vp) x <- runif(10)
y <- runif(10)
xscale <- extendrange(x)
yscale <- extendrange(y) margin1 <- viewport(layout.pos.col = 2, layout.pos.row = 3, name = "margin1")
margin2 <- viewport(layout.pos.col = 1, layout.pos.row = 2, name = "margin2")
margin3 <- viewport(layout.pos.col = 2, layout.pos.row = 1, name = "margin3")
margin4 <- viewport(layout.pos.col = 3, layout.pos.row = 2, name = "margin4")
plot <- viewport(layout.pos.col = 2, layout.pos.row = 2, name = "plot",xscale = xscale, yscale = yscale) splot <- vpTree(top.vp, vpList(margin1, margin2, margin3, margin4, plot))
#grid.show.viewport(splot) pushViewport(splot) seekViewport("plot")
grid.xaxis()
grid.yaxis()
grid.rect()
grid.points(x, y,pch=20) seekViewport("margin1")
grid.text("Random X", y = unit(1, "lines")) seekViewport("margin2")
grid.text("Random Y", x = unit(1, "lines"), rot = 90)

3,把图形逐个打印到视口中

利用布局在同一个画布中绘制多个图形的另外一种方法是使用print()函数,代码摘抄于《R统计绘图(2):grid布局》。

step1,创建多个图形

library(grid)
library(ggplot2)
# prepare ggplot charts
p.hist.len <- ggplot(iris) + geom_histogram(aes(x=Sepal.Length))
p.hist.wid <- ggplot(iris) + geom_histogram(aes(x=Sepal.Width)) + coord_flip()
p.scatter <- ggplot(iris) + geom_point(aes(x=Sepal.Length, y=Sepal.Width))

step2,创建布局,分割视口,并push当前视口

grid.newpage()
pushViewport(viewport(layout = grid.layout(3, 3)))

step3,把图形输出到布局的不同区域中

print(p.scatter, vp=viewport(layout.pos.row=2:3, layout.pos.col=1:2))
print(p.hist.len, vp=viewport(layout.pos.row=1, layout.pos.col=1:2))
print(p.hist.wid, vp=viewport(layout.pos.row=2:3, layout.pos.col=3))

六,unit对象和gpar对象

在grid包中,unit对象用于表示:长度和单位,gpar对象用于设置:图形参数

1,unit对象

用unit对象表示长度的大小和单位:

unit(x, units, data=NULL)

参数注释:

  • x:数值向量
  • units:单位向量

2,gpar对象

用gapr对象表示图形参数:

  • col: Colour for lines and borders.
  • fill: Colour for filling rectangles, polygons, ...
  • alpha: Alpha channel for transparency
  • lty: Line type
  • lwd: Line width
  • lex: Multiplier applied to line width
  • lineend: Line end style (round, butt, square)
  • linejoin: Line join style (round, mitre, bevel)
  • linemitre: Line mitre limit (number greater than 1)
  • fontsize: The size of text (in points)
  • cex: Multiplier applied to fontsize
  • fontfamily: The font family
  • fontface: The font face (bold, italic, ...)
  • lineheight: The height of a line as a multiple of the size of text
  • font: Font face (alias for fontface; for backward compatibility)

参考文档:

Working with grid Viewports

R统计绘图(2):grid布局

R语言grid包使用笔记——viewport

The Grid Graphics Package

R实战:grid包的更多相关文章

  1. R语言grid包just参数如何just图形位置

    思路   grid的画图函数都含有just,但是just参数的是怎么调节图形位置的总是让人非常费解,于是便写了代码来一探究竟.   思路非常简单:放一个2*2的布局viewport,每个布局里面放一个 ...

  2. R实战 第七篇:网格(grid)

    grid包是R底层的图形系统,可以绘制几乎所有的图形.除了绘制图形之外,grid包还能对图形进行布局.在绘图时,有时候会遇到这样一种情景,客户想把多个代表不同KPI的图形分布到同一个画布(Page)上 ...

  3. R实战 第三篇:数据处理(基础)

    数据结构用于存储数据,不同的数据结构对应不同的操作方法,对应不同的分析目的,应选择合适的数据结构.在处理数据时,为了便于检查数据对象,可以通过函数attributes(x)来查看数据对象的属性,str ...

  4. R语言 ggplot2包

    R语言  ggplot2包的学习   分析数据要做的第一件事情,就是观察它.对于每个变量,哪些值是最常见的?值域是大是小?是否有异常观测? ggplot2图形之基本语法: ggplot2的核心理念是将 ...

  5. 《R实战》读书笔记一

    你仅仅要想处理数据,<R实战>这本书就能够助你一臂之力. <R实战>的目标是让你认识R,而且可以对数据进行操作.可视化和理解.该书包含4部分16个章节8个附录. 第一部分:入门 ...

  6. R语言-神经网络包RSNNS

    code{white-space: pre;} pre:not([class]) { background-color: white; }if (window.hljs && docu ...

  7. R语言-Knitr包的详细使用说明

    R语言-Knitr包的详细使用说明 by 扬眉剑 来自数盟[总舵] 群:321311420 1.相关资料 1:自动化报告-谢益辉 https://github.com/yihui/r-ninja/bl ...

  8. R语言dplyr包初探

    昨天学了一下R语言dplyr包,处理数据框还是很好用的.记录一下免得我忘记了... 先写一篇入门的,以后有空再写一篇详细的用法. #dplyr learning library(dplyr) #fil ...

  9. R+NLP︱text2vec包——四类文本挖掘相似性指标 RWMD、cosine、Jaccard 、Euclidean (三,相似距离)

    要学的东西太多,无笔记不能学~~ 欢迎关注公众号,一起分享学习笔记,记录每一颗"贝壳"~ --------------------------- 在之前的开篇提到了text2vec ...

随机推荐

  1. Linux 系统其他重要文件

    其他重要目录 /usr /usr/local 通过源码安装,没有特别指定,就在这个文件下用户自编译软件存放地方 /usr/src 源代码程序 + 内核源代码程序存放目录 /var /var/log/m ...

  2. JVM源码分析之堆外内存完全解读

    JVM源码分析之堆外内存完全解读   寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...

  3. CSS3动画理解与应用

    CSS3动画理解与应用 Transform:对元素进行变形:Transition:对元素某个属性或多个属性的变化,进行控制(时间等),类似flash的补间动画.但只有两个关键贞.开始,结束.Anima ...

  4. vim高级操作命令

    1.首先在命令模式下,输入“:set nu”显示行号:通过行号确定你要删除的行:命令输入“:32,65d”,回车键,32-65行就被删除了,很快捷吧如果无意中删除错了,可以使用‘u’键恢复(命令模式下 ...

  5. P4197 Peaks

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度\(h_i\).有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点 ...

  6. [HNOI2002]营业额统计(splay基础)

    嘟嘟嘟 这几天开始搞平衡树了,\(splay\)理解起来感觉还行,然而代码看了半天才勉强看懂. 我这篇博客应该不算什么入门讲解,因为我觉得我讲不明白,所以只能算自己的学习笔记吧. 这道题就是有\(n\ ...

  7. Linux环境变量配置文件/etc/profile、/etc/bashrc、~/.bashrc的区别以及一些隐藏文件的作用

    ①/etc/profile: 该文件登录操作系统时,为每个用户设置环境信息,当用户第一次登录时,该文件被执行.也就是说这个文件对每个shell都有效,用于获取系统的环境信息. ②/etc/bashrc ...

  8. jQuery全选反选插件

    (function($){ $.fn.check = function(options){ var options = $.extend({ element : "input[name='n ...

  9. JFinal 部署在 Tomcat 下推荐方法(转载)

    经常有人在群里问 tomcat 下项目部署的问题,现写个简单的博文,希望能帮助到有需要的人. 首先明确一下 JFinal 项目是标准的 java web 项目,其部署方式与普通 java web 项目 ...

  10. jenkins slave 挂载

    http://blog.sina.com.cn/s/blog_13cc013b50102wiau.html