声明:本文最早由Giora Simchoni发表在自己的博客中,由周世荣翻译.
kandinsky 是一个著名的俄罗斯抽象派艺术家,以大胆使用多彩的几何形状而出名. 他的作品中常用的几何形状有矩形、圆、三角形、弧、波浪线和十字图案. 这些几何图案除后两个外,R中的grid包都提供了相应的函数。下面我们一一介绍如何绘制这些几何图案。
矩形
首先使用grd.new()函数绘制一张空白画板,这张画板的XY轴的范围0-1,从左下角(x=0,y=0)到右上角(x=1,y=1). 然后使用grid.rect函数绘制矩形, 其中x=0.4,y=0.6表示矩形中心在画板上的坐标,width 和 height 表示矩形的宽和高, gp参数通过gpar函数来自定义矩形属性, 例如本例中定制了一个红边宽度为2的矩形
library(grid)
grid.newpage()
grid.rect(x = 0.4, y = 0.6, width = 0.5, height = 0.4,
gp = gpar(col = "red", lwd = 2))
那么,如何定制一个有倾斜的矩形呢?遗憾的是grid.rect中并没有相应的angle参数. 此时我们可以换一种思路,既然矩形不能倾斜,那么我们就让画板倾斜,使用viewport在空白画板上创建一个倾斜45度子画板,然后再子画板上作图.
vp1 0.5, y = 0.6, width = 0.8, height = 0.7, angle = 45)
grid.rect(x = 0.4, y = 0.6, width = 0.5, height = 0.4,
gp = gpar(col = "red", lwd = 2, fill = "yellow"), vp = vp1)
圆
使用grid.circle函数画圆
grid.circle(x = 0.5, y = 0.5, r = 0.3,
gp = gpar(lwd = 10, col = "blue", fill = "lightblue"))
三角形
使用grid.polygon函数画三角形
grid.polygon(x = c(0.1, 0.7, 0.8), y = c(0.2, 0.5, 0.8),
gp = gpar(col = NA, fill = "pink"))
弧线
使用grid.curve函数画弧线,其中curvature表示曲率,ncp构成弧线的点的个数,越大弧线越平滑.
grid.curve(x1 = 0.1, y1 = 0.7, x2 = 0.6, y2 = 0.2,
curvature = 0.15, square = FALSE, ncp = 30,
gp = gpar(lwd = 10, col = "navyblue"))
波浪线
gCurve function (expr, from, to, n = 101,
gp = gpar(),
default.units = "npc", vp = NULL,
name = NULL, draw = TRUE, xname = "x", ...)
{
sexpr if (is.name(sexpr)) {
expr else { if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in%
all.vars(sexpr)))
stop(gettextf("'expr' must be a function, or a call or an expression
containing '%s'", xname), domain = NA)
expr if (length(y) != length(x))
stop("'expr' did not evaluate to an object of length 'n'")
x T))/(max(x, na.rm = T) - min(x, na.rm = T))
y T))/(max(y, na.rm = T) - min(y, na.rm = T))
grid.lines(x = x, y = y, default.units = default.units, gp = gp, vp = vp, ...)
invisible(list(x = x, y = y))
}
#绘制波浪线
gCurve(sin(x)/x, from = 0.1, to = 20, gp = gpar(lty = 3,lwd=2,col='red'))
十字图案
gCrissCross function(n = 5, gp = gpar(), vp = NULL, ...) {
x0 1, 0, 0.1)
ccGap 1, 0.3, 0.7)
y0 1, 0, 0.5) for (i in 1:n) {
x0 1, 0.1, 0.2)
y0 1, -0.05, 0.05)
y1 1, -0.05, 0.05)
grid.segments(x0, y0, x0 + ccGap, y1, vp = vp, gp = gp, ...)
grid.segments(x0, y1, x0 + ccGap, y0, vp = vp, gp = gp, ...)
}
}
gCrissCross()
随机kandinsky抽象画
我们使用上面绘制的几何元素可以定制一副漂亮kandinsky抽象画
randomKandinsky function(n = 10) {
grid.newpage()
grid.rect(gp=gpar(fill=rgb(runif(1),
runif(1),
runif(1),
runif(1))))
for (i in 1:n) {
grid.rect(x = runif(1), y = runif(1), width = runif(1), height =runif(1),
gp = gpar(col = NA,
fill=rgb(runif(1),
runif(1),
runif(1),
runif(1))))
grid.circle(x = runif(1), y = runif(1), r = runif(1),
gp = gpar(
lwd = runif(1, 0, 100),
col = rgb(runif(1),
runif(1),
runif(1),
runif(1)),
fill=rgb(runif(1),
runif(1),
runif(1),
runif(1))))
grid.polygon(x = runif(3), y = runif(3),
gp = gpar(col = NA,
fill=rgb(runif(1),
runif(1),
runif(1),
runif(1))))
grid.curve(runif(1), runif(1), runif(1), runif(1),
curvature = runif(1, -1, 1), square = FALSE,
ncp =sample(100,1),gp = gpar(lwd = runif(1, 0, 10),
col = rgb(runif(1),
runif(1),
runif(1), 1)))
vp1 1), y = runif(1), width = runif(1), height = runif(1), angle = runif(1) * 360)
grid.rect(x = runif(1), y = runif(1), width = runif(1), height = runif(1),vp = vp1,
gp = gpar(col = NA,
fill=rgb(runif(1),
runif(1),
runif(1),
runif(1))))
vp2 1), y = runif(1), width = runif(1), height = runif(1), angle = runif(1) * 360)
gCurve(sin(x)/(x), sample(5, 1), sample(10:50, 1), vp = vp2,
gp = gpar(lwd = runif(1, 0, 10),
col = rgb(runif(1),
runif(1),
runif(1), 1)))
}
vp3 1), y = runif(1), width = runif(1), height = runif(1), clip = "off")
gCrissCross(vp = vp3,
gp = gpar(lwd = runif(1, 0, 10),
col = rgb(runif(1),
runif(1),
runif(1), 1)))
}
randomKandinsky(10)
randomKandinsky(1000)
绘制数据集
绘制数据集的主要思路是按列把数据集标准化(及变为0-1之间的元素), 数值型变量直接标准化,字符型因子型变量先变为数值型再标准化, 缺失值直接赋值给0.5.
zeroOneNormalize function(x) { if (!is.numeric(x)) { if (is.factor(x)) {
x else {
x if (length(unique(x)) == 1) { return(rep(0.5, length(x)))
} else {
x TRUE)) /
(max(x, na.rm = TRUE) - min(x, na.rm = TRUE))
x[is.na(x)] 0.5
return(x)
}
}kandinsky function(df = NULL, rv = runif(1000)) { library(grid) library(purrr) if (!is.null(df)) {
rv 0
grid.rect(gp = gpar(fill = rgb(nex(rv), nex(rv), nex(rv), nex(rv))))
nRectangles 10) + 3
nCircles 10) + 3
nTriangles 10) + 3
nArchs 10) + 3
nTiltedRectangles 10) + 3
nWaves 10) + 3
nCrissCross 3) + 1
walk(1:nRectangles, drawRectangle, rv)
walk(1:nCircles, drawCircle, rv)
walk(1:nTriangles, drawTriangle, rv)
walk(1:nArchs, drawArch, rv)
walk(1:nTiltedRectangles, drawTiltedRectangle, rv)
walk(1:nWaves, drawWave, rv)
walk(1:nCrissCross, drawCrissCross, rv)
}
kandinsky(mtcars)
kandinsky(iris)
欢迎关注图表绘制之魔方学院QQ群