--- 大师,大师,618买的什么书呀,好奇呢。
··· 一本R语言绘图的书,可花了呢。
"Beautiful Visualization with R" provides a comprehensive introduction to the many types of visualisation that you can create with R. As well as foundational visualisations like bar charts, scatterplots, and histogram, this book will teach you about more complex tools like 3d plots, ternary plots, polar coordinate plots and more! Read this book to learn how to create visually compelling plots that help you understand your data. ——Hadley Wickham RStudio 首席科学家,莱斯大学统计系助理教授,ggplot2等软件包开发者
公元2019年5月底得知出版消息,旋即下单,约莫6月5日拆封,开阅。太贵,开卷有益。于端午假期草过一遍,略有所得,以飨读者。
本书基本上分为三个部分:R语言编程与绘图基础、可视化实战和论文中学术图表的升级技能(tips),其中第二部分是大量的案例,按照绘图类型不同来区分。窃以为这样的安排挺好的,我们学习可视化技能基本上是靠案例来学习的。其实R语言本身也倡导这种case-study的方式,君不见R里面充满了而各种example。
首先,我们为什么要可视化?因为我们想把数据变现:一图胜千言。而且一张图上能表征的信息越多越好,当然是在人类的理解范围内。一张图基本的元素就是点线面以及大小形状颜色,一张好的图就是合理地组合这些元素,做的比较好的当然是ggplot2的图形语法了。本书也是基于ggplot2语法来的,很多图是由ggplot2及其扩展包实现的。读者朋友用R做可视化一定看过《ggplot2:数据分析与图形艺术》一书咯,这是一本圣经级别的书,偏理论一点,例子尽可能的简单。
相比之下,这本书就更加偏向应用了,例子给的详尽也尽量做到了精美。所以叫他指南也是有一定的道理的。这里举几个例子。
#EasyCharts团队出品,
#如需使用与深入学习,请联系微信:EasyCharts
#---------------------------------------图5-1-2核密度估计峰峦图--------------------------------------
library(ggplot2)
library(ggridges)
library(RColorBrewer)
ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = `Month`, fill = ..density..)) +
geom_density_ridges_gradient(scale = 3, rel_min_height = 0.00,size = 0.3) +
scale_fill_gradientn(colours = colorRampPalette(rev(brewer.pal(11,'Spectral')))(32))
###------------------------------自定义编写代码实现:图5-1-2核密度估计峰峦图-------------------------------
library(reshape2)
colormap <- colorRampPalette(rev(brewer.pal(11,'Spectral')))(32)
dt<-lincoln_weather[,c("Month","Mean Temperature [F]")]
splitdata<-split(dt,dt$Month)
xmax<-max(dt$`Mean Temperature [F]`)*1.1
xmin<-min(dt$`Mean Temperature [F]`)*1.1
N<-length(splitdata)
labels_y<-names(splitdata)
mydata<-data.frame(x=numeric(),y=numeric(),variable=numeric()) #创建空的Data.Frame
for (i in 1:N){
tempy<-density(splitdata[[i]][2]$`Mean Temperature [F]`,bw = 3.37,from=xmin, to=xmax)
newdata<-data.frame(x=tempy$x,y=tempy$y)
newdata$variable<-i
mydata<-rbind(mydata,newdata)
}
Step<-max(mydata$y)*0.6
mydata$offest<--as.numeric(mydata$variable)*Step
mydata$V1_density_offest<-mydata$y+mydata$offest
p<-ggplot()
for (i in 1:N){
p<-p+ geom_linerange(data=mydata[mydata$variable==i,],aes(x=x,ymin=offest,ymax=V1_density_offest,group=variable,color=y),size =1, alpha =1) +
geom_line(data=mydata[mydata$variable==i,],aes(x=x, y=V1_density_offest),color="black",size=0.5)
}
p+scale_color_gradientn(colours=colormap,name="Density")+
scale_y_continuous(breaks=seq(-Step,-Step*N,-Step),labels=labels_y)+
xlab("Mean Temperature [F]")+
ylab("Month")+
theme_classic()+
theme(
panel.background=element_rect(fill="white",colour=NA),
panel.grid.major.x = element_line(colour = "grey80",size=.25),
panel.grid.major.y = element_line(colour = "grey60",size=.25),
axis.line = element_blank(),
text=element_text(size=15,colour = "black"),
plot.title=element_text(size=15,hjust=.5),
legend.position="right"
)
#EasyCharts团队出品,
#如有问题修正与深入学习,可联系微信:EasyCharts
library(ggplot2)
library(grid)
library(RColorBrewer)
library(dplyr)
install.packages("SuppDists")
library(SuppDists) #提供rJohnson()函数
# somewhat hackish solution to:
# https://twitter.com/EamonCaddigan/status/646759751242620928
# based mostly on copy/pasting from ggplot2 geom_violin source:
# https://github.com/hadley/ggplot2/blob/master/R/geom-violin.r
"%||%" <- function(a, b) {
if (!is.null(a)) a else b
}
color<-brewer.pal(7,"Set2")[c(1,2,4,5)]
geom_flat_violin <- function(mapping = NULL, data = NULL, stat = "ydensity",
position = "dodge", trim = TRUE, scale = "area",
show.legend = NA, inherit.aes = TRUE, ...) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomFlatViolin,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
trim = trim,
scale = scale,
...
)
)
}
GeomFlatViolin <-
ggproto("GeomFlatViolin", Geom,
setup_data = function(data, params) {
data$width <- data$width %||%
params$width %||% (resolution(data$x, FALSE) * 0.9)
# ymin, ymax, xmin, and xmax define the bounding rectangle for each group
data %>%
group_by(group) %>%
mutate(ymin = min(y),
ymax = max(y),
xmin = x,
xmax = x + width / 2)
},
draw_group = function(data, panel_scales, coord) {
# Find the points for the line to go all the way around
data <- transform(data, xminv = x,
xmaxv = x + violinwidth * (xmax - x)) #利用transform函数为数据框mydata增加数据
newdata <- rbind(plyr::arrange(transform(data, x = xmaxv), -y),plyr::arrange(transform(data, x = xminv), y))
newdata_Polygon <- rbind(newdata, newdata[1,])
newdata_Polygon$colour<-NA
newdata_Path <- plyr::arrange(transform(data, x = xmaxv), -y)
ggplot2:::ggname("geom_flat_violin", grobTree(
GeomPolygon$draw_panel(newdata_Polygon, panel_scales, coord),
GeomPath$draw_panel(newdata_Path, panel_scales, coord))
)
},
draw_key = draw_key_polygon,
default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5,
alpha = NA, linetype = "solid"),
required_aes = c("x", "y")
)
# "%||%" <- getFromNamespace("%||%", "ggplot2")
# "%>%" <- getFromNamespace("%>%", "magrittr")
set.seed(141079)
# Generate sample data -------------------------------------------------------
#findParams函数参考:https://github.com/hadley/boxplots-paper
findParams <- function(mu, sigma, skew, kurt) {
value <- .C("JohnsonMomentFitR", as.double(mu), as.double(sigma),
as.double(skew), as.double(kurt - 3), gamma = double(1),
delta = double(1), xi = double(1), lambda = double(1),
type = integer(1), PACKAGE = "SuppDists")
list(gamma = value$gamma, delta = value$delta,
xi = value$xi, lambda = value$lambda,
type = c("SN", "SL", "SU", "SB")[value$type])
}
# 均值为3,标准差为1的正态分布
n <- rnorm(100,3,1)
# Johnson分布的偏斜度2.2和峰度13
s <- rJohnson(100, findParams(3, 1, 2., 13.1))
# Johnson分布的偏斜度0和峰度20)
k <- rJohnson(100, findParams(3, 1, 2.2, 20))
# 两个峰的均值μ1,μ2分别为1.89和3.79,σ1 = σ2 =0.31
mm <- rnorm(100, rep(c(2, 4), each = 50) * sqrt(0.9), sqrt(0.1))
mydata <- data.frame(
Class = factor(rep(c("n", "s", "k", "mm"), each = 100),
c("n", "s", "k", "mm")),
Value = c(n, s, k, mm)+3
)
#-------------------------------------------------------------
colnames(mydata)<-c("Class", "Value")
d <- group_by(mydata, Class) %>%
summarize(mean = mean(Value),
sd = sd(Value))
plot1<-ggplot(mydata, aes(Class, Value, fill=Class)) +
geom_flat_violin(position=position_nudge(x=.2)) +
geom_jitter(aes(color=Class), width=.1) +
geom_pointrange(aes(y=mean, ymin=mean-sd, ymax=mean+sd),
data=d, size=1, position=position_nudge(x=.2)) +
coord_flip() +
theme_bw() +
theme( axis.text = element_text(size=13),
axis.title = element_text(size=15),
legend.position="none")
plot2<-ggplot(mydata, aes(x=Class, y=Value)) +
geom_flat_violin(aes(fill=Class),position=position_nudge(x=.25),color="black") +
geom_jitter(aes(color=Class), width=0.1) +
geom_boxplot(width=.1,position=position_nudge(x=0.25),fill="white",size=0.5) +
coord_flip() +
theme_bw() +
theme( axis.text = element_text(size=13),
axis.title = element_text(size=15),
legend.position="none")
library(gridExtra)
grid.arrange(plot1,plot2,ncol = 2, nrow = 1)
作为一本以案例为主的指南书,非常适于我们可视化初学者,因为我们很多时候不知道原来数据还可以这样展示。所以对于资历一般的我们,看到才可能想到,想到才可能做到,做到才可能得到,得到才可能失去,失去才可能知道适不适合自己。
任何一张图都离不开具体的实际问题,有时候理解实际问题要比绘图难的多,数据是连续的还是离散的,离散的用点,连续的用线,把自己的数据分到以下类别中能更好地帮助我们选择相应的绘图类型。
结合案例可以思考哪些类型的数据我是可以用这个图来展示的,要做这张图需要什么样的数据类型呢?可视化的大部分工作是在整理数据,可以感觉到本书的作者也是个tidyverse语法的爱好者。当然这不是一本数据处理的书,不是《R语言数据科学》所以我们主要关心的还是每张图的细节修饰,也许在大量的实践之后,你会觉得作者做的远远不够,也采用了很多默认的参数,但是操千曲而后笑声,观千剑而后识器。通过执行作者的代码。也可以学到不少R编程的知识,当然了如果你已经是大牛了也许就没有兴趣看这本书了。
虽然本书的代码和数据都是公布在github的要运行不必买书的。碰到我是一个喜欢积累的人也喜欢做一些摘抄,有时候遇到惊艳的绘图代码也会记在ggplot2的那本书上,但是由于他偏理论,很多类型的图表没有涉及,以至于有的句子不知道摘抄在哪。有了这本书好了,R语言绘图代码有地方放了。包括但不限于R语言可视化,可以把自己处理数据学术绘图的心得体会写在相应的章节,以后遇到类似的问题就可以参考解决。这不失是一个比较笨的方法,学习要有学生思维嘛。
我还是比较怀念当时拿着铅笔在纸上写代码的年纪呢!
有两点书中没有涉及一个是空间数据,比如地图,另一个关系型数据可视化主题网络图(Network)没有涉及,使我觉得这本书是不完整的,至少不是那么完整。然后是多维数据可视化中heatmap做的有些草草了,就是把pheatmap的example拿过来演示一下,没有之美之说。柱形图、散点图、热图这三种图在学术文章中是最常见的,其中热图可以用来描述类别比较(分组)、数据关系(相关性)、数量关系(丰度),所以他的席位不应该排这么少。
在阅读的过程中我产生一种想法就是:科研绘图亦应该有分级制度:学术文章级别以及学术报告级别。这两个在主题设置、颜色配置要求是不一样的。本书关于学术图表主题设置的讨论我觉得也是有益的。
代码在这||Beautiful-Visualization-with-R
韩愈《答李翊书》:“始者非三代两汉之书不敢观.非圣人之志不敢存,处若忘,行若遗,俨乎其若恩,茫乎其若迷,当其取予心而注于手也,惟陈言之务去,戛戛乎其难哉!”
《樊绍述墓志铭》:“必出于己,不蹈袭前人一言一句,又何其难也。”