如何用kandinsky抽象画呈现数据集

浏览: 1530

声明:本文最早由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的矩形

#加载grid包
library(grid)
#绘制新的画板
grid.newpage()
#绘制矩形
grid.rect(x = 0.4, y = 0.6, width = 0.5, height = 0.4,
  gp = gpar(col = "red", lwd = 2))

image.png

那么,如何定制一个有倾斜的矩形呢?遗憾的是grid.rect中并没有相应的angle参数. 此时我们可以换一种思路,既然矩形不能倾斜,那么我们就让画板倾斜,使用viewport在空白画板上创建一个倾斜45度子画板,然后再子画板上作图.

vp1 <- viewport(x = 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)

image.png

使用grid.circle函数画圆

grid.circle(x = 0.5, y = 0.5, r = 0.3,
 gp = gpar(lwd = 10, col = "blue", fill = "lightblue"))

image.png

三角形

使用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"))

image.png

弧线

使用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"))

image.png

波浪线

#构造波浪线函数
gCurve <- function (expr, from, to, n = 101,
                   gp = gpar(),
                   default.units = "npc", vp = NULL,
                   name = NULL, draw = TRUE, xname = "x", ...)
{
 sexpr <- substitute(expr)  if (is.name(sexpr)) {
   expr <- call(as.character(sexpr), as.name(xname))
 }  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 <- sexpr
 }
 x <- seq.int(from, to, length.out = n)
 ll <- list(x = x)
 y <- eval(expr, envir = ll, enclos = parent.frame())  if (length(y) != length(x))
   stop("'expr' did not evaluate to an object of length 'n'")
 x <- (x - min(x, na.rm = T))/(max(x, na.rm = T) - min(x, na.rm = T))
 y <- (y - min(y, na.rm = 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'))

image.png

十字图案

#定义函数
gCrissCross <- function(n = 5, gp = gpar(), vp = NULL, ...) {
 x0 <- runif(1, 0, 0.1)
 ccGap <- runif(1, 0.3, 0.7)
 y0 <- runif(1, 0, 0.5)  for (i in 1:n) {
   x0 <- x0 + runif(1, 0.1, 0.2)
   y0 <- y0 + runif(1, -0.05, 0.05)
   y1 <- y0 + ccGap + runif(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()

image.png

随机kandinsky抽象画

我们使用上面绘制的几何元素可以定制一副漂亮kandinsky抽象画

randomKandinsky <- function(n = 10) {  
#打开空白画板
 grid.newpage()  
#对画板随机填充
 grid.rect(gp=gpar(fill=rgb(runif(1),
                            runif(1),
                            runif(1),
                            runif(1))))
 #绘制n个随机几何元素
 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 <- viewport(x = runif(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 <- viewport(x = runif(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 <- viewport(x = runif(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)

image.png

randomKandinsky(1000)

image.png

绘制数据集

绘制数据集的主要思路是按列把数据集标准化(及变为0-1之间的元素), 数值型变量直接标准化,字符型因子型变量先变为数值型再标准化, 缺失值直接赋值给0.5.

#转换函数
zeroOneNormalize <- function(x) {  if (!is.numeric(x)) {    if (is.factor(x)) {
     x <- as.numeric(unclass(x))
   } else {
     x <- as.numeric(unclass(as.factor(x)))
   }
 }  if (length(unique(x)) == 1) {    return(rep(0.5, length(x)))
 } else {
   x <- (x - min(x, na.rm = 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 <- normalizeAndVectorize(df)
 }
 grid.newpage()
 i <<- 0
 grid.rect(gp = gpar(fill = rgb(nex(rv), nex(rv), nex(rv), nex(rv))))
 nRectangles <- floor(nex(rv) * 10) + 3
 nCircles <- floor(nex(rv) * 10) + 3
 nTriangles <- floor(nex(rv) * 10) + 3
 nArchs <- floor(nex(rv) * 10) + 3
 nTiltedRectangles <- floor(nex(rv) * 10) + 3
 nWaves <- floor(nex(rv) * 10) + 3
 nCrissCross <- floor(nex(rv) * 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)
}
#mtcars的kandinsky画
kandinsky(mtcars)

image.png

kandinsky(iris)

image.png

欢迎关注图表绘制之魔方学院QQ群


推荐 0
本文由 EasyCharts 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册