2019第23周:評(píng)《R語(yǔ)言數(shù)據(jù)可視化之美:專業(yè)圖表繪制指南》

--- 大師畸写,大師呀非,618買的什么書(shū)呀,好奇呢。
··· 一本R語(yǔ)言繪圖的書(shū),可花了呢。

"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 首席科學(xué)家,萊斯大學(xué)統(tǒng)計(jì)系助理教授,ggplot2等軟件包開(kāi)發(fā)者

公元2019年5月底得知出版消息籽孙,旋即下單,約莫6月5日拆封火俄,開(kāi)閱犯建。太貴,開(kāi)卷有益瓜客。于端午假期草過(guò)一遍适瓦,略有所得,以饗讀者谱仪。

本書(shū)基本上分為三個(gè)部分:R語(yǔ)言編程與繪圖基礎(chǔ)玻熙、可視化實(shí)戰(zhàn)和論文中學(xué)術(shù)圖表的升級(jí)技能(tips),其中第二部分是大量的案例疯攒,按照繪圖類型不同來(lái)區(qū)分嗦随。竊以為這樣的安排挺好的,我們學(xué)習(xí)可視化技能基本上是靠案例來(lái)學(xué)習(xí)的敬尺。其實(shí)R語(yǔ)言本身也倡導(dǎo)這種case-study的方式枚尼,君不見(jiàn)R里面充滿了而各種example。

首先砂吞,我們?yōu)槭裁匆梢暬鸹校恳驗(yàn)槲覀兿氚褦?shù)據(jù)變現(xiàn):一圖勝千言。而且一張圖上能表征的信息越多越好蜻直,當(dāng)然是在人類的理解范圍內(nèi)盯质。一張圖基本的元素就是點(diǎn)線面以及大小形狀顏色,一張好的圖就是合理地組合這些元素袭蝗,做的比較好的當(dāng)然是ggplot2的圖形語(yǔ)法了唤殴。本書(shū)也是基于ggplot2語(yǔ)法來(lái)的,很多圖是由ggplot2及其擴(kuò)展包實(shí)現(xiàn)的到腥。讀者朋友用R做可視化一定看過(guò)《ggplot2:數(shù)據(jù)分析與圖形藝術(shù)》一書(shū)咯,這是一本圣經(jīng)級(jí)別的書(shū)蔚袍,偏理論一點(diǎn)乡范,例子盡可能的簡(jiǎn)單配名。

相比之下,這本書(shū)就更加偏向應(yīng)用了晋辆,例子給的詳盡也盡量做到了精美渠脉。所以叫他指南也是有一定的道理的。這里舉幾個(gè)例子瓶佳。

#EasyCharts團(tuán)隊(duì)出品芋膘,
#如需使用與深入學(xué)習(xí),請(qǐng)聯(lián)系微信:EasyCharts

#---------------------------------------圖5-1-2核密度估計(jì)峰巒圖--------------------------------------
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))

###------------------------------自定義編寫(xiě)代碼實(shí)現(xiàn):圖5-1-2核密度估計(jì)峰巒圖-------------------------------
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()) #創(chuàng)建空的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團(tuán)隊(duì)出品霸饲,
#如有問(wèn)題修正與深入學(xué)習(xí)为朋,可聯(lián)系微信:EasyCharts

library(ggplot2)
library(grid)
library(RColorBrewer)
library(dplyr)
install.packages("SuppDists")
library(SuppDists) #提供rJohnson()函數(shù)

# 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函數(shù)為數(shù)據(jù)框mydata增加數(shù)據(jù)
            
            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函數(shù)參考: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,標(biāo)準(zhǔn)差為1的正態(tài)分布
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))
# 兩個(gè)峰的均值μ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)
云雨圖

作為一本以案例為主的指南書(shū),非常適于我們可視化初學(xué)者傻工,因?yàn)槲覀兒芏鄷r(shí)候不知道原來(lái)數(shù)據(jù)還可以這樣展示霞溪。所以對(duì)于資歷一般的我們,看到才可能想到中捆,想到才可能做到鸯匹,做到才可能得到,得到才可能失去泄伪,失去才可能知道適不適合自己忽你。

任何一張圖都離不開(kāi)具體的實(shí)際問(wèn)題,有時(shí)候理解實(shí)際問(wèn)題要比繪圖難的多臂容,數(shù)據(jù)是連續(xù)的還是離散的科雳,離散的用點(diǎn),連續(xù)的用線脓杉,把自己的數(shù)據(jù)分到以下類別中能更好地幫助我們選擇相應(yīng)的繪圖類型糟秘。

結(jié)合案例可以思考哪些類型的數(shù)據(jù)我是可以用這個(gè)圖來(lái)展示的,要做這張圖需要什么樣的數(shù)據(jù)類型呢球散?可視化的大部分工作是在整理數(shù)據(jù)尿赚,可以感覺(jué)到本書(shū)的作者也是個(gè)tidyverse語(yǔ)法的愛(ài)好者。當(dāng)然這不是一本數(shù)據(jù)處理的書(shū)蕉堰,不是《R語(yǔ)言數(shù)據(jù)科學(xué)》所以我們主要關(guān)心的還是每張圖的細(xì)節(jié)修飾凌净,也許在大量的實(shí)踐之后,你會(huì)覺(jué)得作者做的遠(yuǎn)遠(yuǎn)不夠屋讶,也采用了很多默認(rèn)的參數(shù)冰寻,但是操千曲而后笑聲,觀千劍而后識(shí)器。通過(guò)執(zhí)行作者的代碼皿渗。也可以學(xué)到不少R編程的知識(shí)斩芭,當(dāng)然了如果你已經(jīng)是大牛了也許就沒(méi)有興趣看這本書(shū)了轻腺。

雖然本書(shū)的代碼和數(shù)據(jù)都是公布在github的要運(yùn)行不必買書(shū)的。碰到我是一個(gè)喜歡積累的人也喜歡做一些摘抄划乖,有時(shí)候遇到驚艷的繪圖代碼也會(huì)記在ggplot2的那本書(shū)上贬养,但是由于他偏理論,很多類型的圖表沒(méi)有涉及琴庵,以至于有的句子不知道摘抄在哪误算。有了這本書(shū)好了,R語(yǔ)言繪圖代碼有地方放了迷殿。包括但不限于R語(yǔ)言可視化儿礼,可以把自己處理數(shù)據(jù)學(xué)術(shù)繪圖的心得體會(huì)寫(xiě)在相應(yīng)的章節(jié),以后遇到類似的問(wèn)題就可以參考解決贪庙。這不失是一個(gè)比較笨的方法蜘犁,學(xué)習(xí)要有學(xué)生思維嘛。

我還是比較懷念當(dāng)時(shí)拿著鉛筆在紙上寫(xiě)代碼的年紀(jì)呢止邮!

有兩點(diǎn)書(shū)中沒(méi)有涉及一個(gè)是空間數(shù)據(jù)这橙,比如地圖,另一個(gè)關(guān)系型數(shù)據(jù)可視化主題網(wǎng)絡(luò)圖(Network)沒(méi)有涉及导披,使我覺(jué)得這本書(shū)是不完整的屈扎,至少不是那么完整。然后是多維數(shù)據(jù)可視化中heatmap做的有些草草了,就是把pheatmap的example拿過(guò)來(lái)演示一下,沒(méi)有之美之說(shuō)子巾。柱形圖甲雅、散點(diǎn)圖杠园、熱圖這三種圖在學(xué)術(shù)文章中是最常見(jiàn)的,其中熱圖可以用來(lái)描述類別比較(分組)、數(shù)據(jù)關(guān)系(相關(guān)性)、數(shù)量關(guān)系(豐度)忍疾,所以他的席位不應(yīng)該排這么少。

在閱讀的過(guò)程中我產(chǎn)生一種想法就是:科研繪圖亦應(yīng)該有分級(jí)制度:學(xué)術(shù)文章級(jí)別以及學(xué)術(shù)報(bào)告級(jí)別谨朝。這兩個(gè)在主題設(shè)置卤妒、顏色配置要求是不一樣的。本書(shū)關(guān)于學(xué)術(shù)圖表主題設(shè)置的討論我覺(jué)得也是有益的字币。

代碼在這||Beautiful-Visualization-with-R

韓愈《答李翊書(shū)》:“始者非三代兩漢之書(shū)不敢觀.非圣人之志不敢存则披,處若忘,行若遺洗出,儼乎其若恩士复,茫乎其若迷,當(dāng)其取予心而注于手也共苛,惟陳言之務(wù)去判没,戛戛乎其難哉蜓萄!”

《樊紹述墓志銘》:“必出于己隅茎,不蹈襲前人一言一句澄峰,又何其難也”傧”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俏竞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子堂竟,更是在濱河造成了極大的恐慌魂毁,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件出嘹,死亡現(xiàn)場(chǎng)離奇詭異席楚,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)税稼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門烦秩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人郎仆,你說(shuō)我怎么就攤上這事只祠。” “怎么了扰肌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵抛寝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我曙旭,道長(zhǎng)盗舰,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任桂躏,我火速辦了婚禮钻趋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沼头。我一直安慰自己爷绘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布进倍。 她就那樣靜靜地躺著土至,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猾昆。 梳的紋絲不亂的頭發(fā)上陶因,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音垂蜗,去河邊找鬼楷扬。 笑死解幽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的烘苹。 我是一名探鬼主播躲株,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼镣衡!你這毒婦竟也來(lái)了霜定?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤廊鸥,失蹤者是張志新(化名)和其女友劉穎望浩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惰说,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磨德,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吆视。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片典挑。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖揩环,靈堂內(nèi)的尸體忽然破棺而出搔弄,到底是詐尸還是另有隱情,我是刑警寧澤丰滑,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布顾犹,位于F島的核電站,受9級(jí)特大地震影響褒墨,放射性物質(zhì)發(fā)生泄漏炫刷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一郁妈、第九天 我趴在偏房一處隱蔽的房頂上張望浑玛。 院中可真熱鬧,春花似錦噩咪、人聲如沸顾彰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涨享。三九已至,卻和暖如春仆百,著一層夾襖步出監(jiān)牢的瞬間厕隧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吁讨,地道東北人髓迎。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像建丧,于是被迫代替她去往敵國(guó)和親排龄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容