可别再说base plot不能图形语法!
经常有人说ggplot2
牛逼,图形语法,base plot不行,这两货根本就不在一个level,怎么能这么比呢?我在《👉树变图,图变树?》一文中已经做了解释。base plot应该和grid比,而ggplot2
是构建在grid之上的,这主要是因为有大神hadley wickham。很多东西所谓行与不行,多半是因为还没有大神来插手,比如说python机器学习牛逼,其实就一张皮,算法都是C++,难道perl, R就不配拥有一套马甲?原因还是因为没有大神染指。想当年ruby火起来的时候,就是因为有ruby on rails。所以啊,A语言行,B语言不行,说到底多半不是行不行的问题,而是缺乏唐长老来缝虎皮裙子。
当初在推特上被AT了,《👉ggfree:试图让你摆脱ggplot2》,我看完之后,一顿吐槽,吐槽之后,我又想,语言是苍白的,所谓you can you up, no can no bb。
于是我就撸起袖子,搞了几天,写了一个叫plotbb的包,正好是ggplot反过来,bb和gg也像是反过来似的。取名brammar of braphics的基于base plot的图形语法。
自2019年12月写了一些功能,疫情来了之后,就一直没空再写,毕竟很忙,再者要真写出来一整套图形语法,可不简单,ggplot2可是hadley wickham大神的博士论文,而且又经历了这么多年的完善。但先能用,以后的再说。
美学映射
基本上所有的东西都是以bb_
打头,这样不会和ggplot2撞名,也方便大家把plotbb
包的功能用tab
键给列出来。
图形语法怎么能没有美学映射,这也是我吐槽ggfree
包的重点之一。废话不说,直接看代码:
library(plotbb)
p <- bbplot(mtcars, bb_aes(mpg, disp, col=factor(cyl)))
p + bb_grid(col='grey50', lty='dashed') + bb_point(pch=19)
和你的ggplot2
代码是不是几乎一毛一样,出图如下:
几何图层
上面的图,我可以加不同的图层,也可以叠加不同的图层:
p2 <- p + bb_point() + bb_lm(bb_aes(group=cyl), lwd=2)
p3 <- p2 + bb_lm(col="red", lwd=3, lty='dotted')
p4 <- p + bb_text(bb_aes(label=cyl), cex=2)
par(mfrow=c(1,3))
p2; p3; p4
画个热图试试
用base plot,除了用现成的函数,你是不是不会画热图?现在我就要来教你画了,而且是辣么的简单,映射xy轴,然后一个bb_tile
的图层搞定。
df <- data.frame(x = rep(1:10, 12),
y = rep(1:12, each = 10),
values = rnorm(120, mean = 10, sd = 5),
type = sample(LETTERS[1:5], 120, replace=TRUE),
stringsAsFactors = FALSE)
par(mfrow=c(2,2))
bbplot(df, bb_aes(x,y, col=values)) + bb_tile() +
bb_title("heatmap for continuous numerical values")
bbplot(df, bb_aes(x,y, col=values)) + bb_tile() + bb_scale_col_palette("YlOrRd") +
bb_title("applying a color palette")
bbplot(df, bb_aes(x,y, col=type)) + bb_tile() +
bb_title("heatmap for discrete categorical values")
bbplot(df, bb_aes(x,y, col=values)) + bb_tile() + bb_text(col='black') +
bb_title("heatmap with text labels") + bb_theme_expand()
此处画了几个,连续型、离散型,还有变换颜色标尺,和加文本图层。
设置label
title, xlab, ylab, subtitle一应具全。
p2 + bb_labs(title = "hello", sub = "just for demo",
xlab="this is xlab", ylab = "this is ylab") +
bb_title("hello world") # last one rules
主题
怎么可以没有主题,对吧?在画热图的时候,大家已经主题初印象了。
g <- p2 +
bb_theme(col.main="red", cex.main=2,
mar = c(4, 4, 3, 1)) +
bb_title("applying graphics::par")
par(mfrow=c(1,2))
print(g)
p2 + bb_title("theme has no side effect")
看到没有,应用了主题画g
,然后这个主题对p2
没有影响。这就是牛逼的地方,因为base plot要设置主题啊,得经过par()
,一搞就是全局的。但我就是可以搞成没有side effect的。
平时用base plot画,会不会觉得图的margin太大?我反正就有这感觉,所以啊,我给你写了一个放大画图区域的主题。
par(mfrow=c(1,2))
p3 + bb_theme_expand()
print(p3)
对比一下,是不是左图舒服多了?
再来一个仿ggplot2
的灰色背景主题吧。
p + bb_grid(col='grey50', lty='dashed') +
bb_point(pch=19) +
bb_theme_expand() +
bb_theme_grey()
此处我主题再加主题的用法,没加主题之前,一切是你的环境设置,加了主题1,就会用主题1指定的东西去改变默认的。再加主题2就又叠加了设置。比如说主题1设置了A和B,主题2设置了B和C,那么主题1+主题2就设置了A,B和C,而且B是主题2设置的,因为它在后面加的。
最后再来一个深蓝的主题:
p + bb_point(pch=19, cex=2) +
bb_theme_expand() +
bb_theme_deepblue()
你也会写主题
我一不小心,就写了一个最容易写的主题系统,小白菜鸟都会写主题了。
我们来看深蓝的主题是怎么定义的:
bb_theme_deepblue <- function(...) {
bb_theme(
bg = "#002E49",
fg = "#CCCCCC",
col.axis = "#BEBEBE",
col.lab = "#FFFFFF"
) <= bb_theme(...)
}
一开始是bb_theme()
定义了你默认的东西,然后是bb_theme(...)
允许用户再传递额外的设置,或者覆盖掉默认设置,比如你能深蓝主题传个bg
的参数,设置背景颜色不是深蓝,它也OK。你给它传别的参数,比如mar
设置margin,同样也OK。你只要仿照这个写法,把第一个bb_theme()
中的东西,改成你想要的一些默认设置,你就定义了一个新的主题。至于后面那个<= bb_theme(...)
,你照抄就可以了。没错,我这里自己定义了一个<=
的操作符,它不再是比大小,不是小于等于的意思了。
和现有代码衔接
做为一套图形语法,还有很多东西没有实现,所以啊,要让plotbb
在一开始就可以被大家所使用,它就必须能够衔接现有的代码。这里包括了几个方面:
代码出图,我是有的,我就想用用主题,可行? 我有代码去画图(包括各种包的各种函数),然后我想用图形语法加个图层,行不? 我用图形语法出图,想再加点什么,当前还不支持,能否用我熟悉的老代码去加上去?
做为一个成年人,我啥都想要,然后对于上面的问题,答案全部是行行行。
首先假如我有以下代码:
plot(mtcars$mpg, mtcars$disp)
abline(lm(disp ~ mpg, data=mtcars), col='red')
这时候能我把它封装成函数:
f <- function() {
plot(mtcars$mpg, mtcars$disp)
abline(lm(disp ~ mpg, data=mtcars), col='red')
}
plotbb
包呢,提供了一个函数as.bbplot()
就可以把函数里的代码,转成了一个bbplot
对象,然后就可以愉快地用图形语法去加图层,和应用主题了。
library(dplyr)
d <- group_by(mtcars, cyl) %>%
summarize(xm=mean(mpg), ym=mean(disp))
pp <- as.bbplot(f) +
bb_theme_expand() +
bb_theme_grey() +
bb_lm(bb_aes(mpg, disp, group=cyl, col=factor(cyl)), data=mtcars, lwd=2, lty='dashed') +
bb_point(bb_aes(xm, ym, col=factor(cyl)), data=d, pch=19, cex=2) +
bb_title("hello plotbb") +
bb_grid(col='grey30', lty='dashed') ## grid lines were plotted as background by default
这时候啊,假设我还想干点什么,我能不能用base plot的代码来搞?可以可以都可以!
pp + (~points(30, 400, pch=19, col="red", cex=3)) +
~text(30, 420, label="hae fun :)", col="blue", cex=1.2)
只需要在你的代码前加一个波浪线,plotbb
就会去处理它,变成图层给你加上去。
就是最后这一些兼容的功能,让这个包在当前还是BB(baby)状态的时候,已经可以用了,就像在梦里一样,想干什么干什么!
往期精彩