ggplot2基本要素
這里將從這些基本要素對ggplot2進行介紹。 數(shù)據(jù)和映射下面以一份鉆石的數(shù)據(jù)為例,這份數(shù)據(jù)非常大,隨機取一個子集來畫圖。 require(ggplot2)data(diamonds)set.seed(42)small <- diamonds[sample(nrow(diamonds),="">->1000), ]head(small) ## carat cut color clarity depth table price x y z## 49345 0.71 Very Good H SI1 62.5 60 2096 5.68 5.75 3.57## 50545 0.79 Premium H SI1 61.8 59 2275 5.97 5.91 3.67## 15434 1.03 Ideal F SI1 62.4 57 6178 6.48 6.44 4.03## 44792 0.50 Ideal E VS2 62.2 54 1624 5.08 5.11 3.17## 34614 0.27 Ideal E VS1 61.6 56 470 4.14 4.17 2.56## 27998 0.30 Premium E VS2 61.7 58 658 4.32 4.34 2.67 畫圖實際上是把數(shù)據(jù)中的變量映射到圖形屬性上。以克拉數(shù)為X軸變量,價格為Y軸變量。 p <- ggplot(data="small," mapping="aes(x" =="" carat,="" y="">-> 上面這行代碼把數(shù)據(jù)映射XY坐標軸上,需要告訴ggplot2,這些數(shù)據(jù)要映射成什么樣的幾何對象,下面以散點為例: p + geom_point() 幾何對象將在下面的小節(jié)介紹,這一節(jié),關(guān)注的是數(shù)據(jù)和圖形屬性之間的映射。 如果想將切工(cut)映射到形狀屬性。只需要: p <- ggplot(data="small," mapping="aes(x=carat," y="price," shape="">-> 再比如我想將鉆石的顏色(color)映射顏色屬性: p <- ggplot(data="small," mapping="aes(x=carat," y="price," shape="cut," colour="">-> 幾何對象(Geometric)在上面的例子中,各種屬性映射由ggplot函數(shù)執(zhí)行,只需要加一個圖層,使用
不同的幾何對象,要求的屬性會有些不同,這些屬性也可以在幾何對象映射時提供,比如上一圖,也可以用以下語法來畫: p <- ggplot(small)p+geom_point(aes(x="carat," y="price," shape="cut," colour="">-> ggplot2支持圖層,我通常把不同的圖層中共用的映射提供給ggplot函數(shù),而某一幾何對象才需要的映射參數(shù)提供給geom_xxx函數(shù)。 這一小節(jié)我們來看一下各種常用的幾何對象。 直方圖 直方圖最容易,提供一個x變量,畫出數(shù)據(jù)的分布。 ggplot(small)+geom_histogram(aes(x=price)) 同樣可以根據(jù)另外的變量給它填充顏色,比如按不同的切工: ggplot(small)+geom_histogram(aes(x=price, fill=cut)) 也可以將其分開,side-by-side地畫直方圖。 ggplot(small)+geom_histogram(aes(x=price, fill=cut), position='dodge') 還可以使用position=”fill”,按照相對比例來畫。 ggplot(small)+geom_histogram(aes(x=price, fill=cut), position='fill') 柱狀圖 ggplot(small)+geom_bar(aes(x=clarity)) 柱狀圖兩個要素,一個是分類變量,一個是數(shù)目,也就是柱子的高度。數(shù)目在這里不用提供,因為ggplot2會通過x變量計算各個分類的數(shù)目。 當然你想提供也是可以的,通過stat參數(shù),可以讓geom_bar按指定高度畫圖,比如以下代碼: ggplot()+geom_bar(aes(x=c(LETTERS[1:3]),y=1:3), stat='identity') 柱狀圖和直方圖是很像的,直方圖把連續(xù)型的數(shù)據(jù)按照一個個等長的分區(qū)(bin)來切分,然后計數(shù),畫柱狀圖。而柱狀圖是分類數(shù)據(jù),按類別計數(shù)。我們可以用前面直方圖的參數(shù)來畫side-by-side的柱狀圖,填充顏色或者按比例畫圖,它們是高度一致的。 柱狀圖是用來表示計數(shù)數(shù)據(jù)的,但在生物界卻被經(jīng)常拿來表示均值,加上誤差來表示數(shù)據(jù)分布,這可以通常圖層來實現(xiàn),我將在圖層一節(jié)中給出實例。 密度函數(shù)圖 ggplot(small)+geom_density(aes(x=price, colour=cut)) ggplot(small)+geom_density(aes(x=price,fill=clarity)) colour參數(shù)指定的是曲線的顏色,而fill是往曲線下面填充顏色。 箱式圖 ggplot(small)+geom_boxplot(aes(x=cut, y=price,fill=color)) geom_boxplot將數(shù)據(jù)映射到箱式圖上,上面的代碼,我們應(yīng)該很熟悉了,按切工(cut)分類,對價格(price)變量畫箱式圖,再分開按照color變量填充顏色。 ggplot2提供了很多的geom_xxx函數(shù),可以滿足我們對各種圖形繪制的需求。 geom_abline geom_area geom_bar geom_bin2dgeom_blank geom_boxplot geom_contour geom_crossbargeom_density geom_density2d geom_dotplot geom_errorbargeom_errorbarh geom_freqpoly geom_hex geom_histogramgeom_hline geom_jitter geom_line geom_linerangegeom_map geom_path geom_point geom_pointrangegeom_polygon geom_quantile geom_raster geom_rectgeom_ribbon geom_rug geom_segment geom_smoothgeom_step geom_text geom_tile geom_violingeom_vline 標尺(Scale)前面我們已經(jīng)看到了,畫圖就是在做映射,不管是映射到不同的幾何對象上,還是映射各種圖形屬性。這一小節(jié)介紹標尺,在對圖形屬性進行映射之后,使用標尺可以控制這些屬性的顯示方式,比如坐標刻度,可能通過標尺,將坐標進行對數(shù)變換;比如顏色屬性,也可以通過標尺,進行改變。 ggplot(small)+geom_point(aes(x=carat, y=price, shape=cut, colour=color))+scale_y_log10()+scale_colour_manual(values=rainbow(7)) 以數(shù)據(jù)(Data)和映射(Mapping)一節(jié)中所畫散點圖為例,將Y軸坐標進行l(wèi)og10變換,再自己定義顏色為彩虹色。 統(tǒng)計變換(Statistics)統(tǒng)計變換對原始數(shù)據(jù)進行某種計算,然后在圖上表示出來,例如對散點圖上加一條回歸線。 ggplot(small, aes(x=carat, y=price))+geom_point()+scale_y_log10()+stat_smooth() 這里就不按顏色、切工來分了,不然ggplot會按不同的分類變量分別做回歸,圖就很亂,如果我們需要這樣做,我們可以使用分面,這個將在后面介紹。 這里,aes所提供的參數(shù),就通過ggplot提供,而不是提供給geom_point,因為ggplot里的參數(shù),相當于全局變量,geom_point()和stat_smooth()都知道x,y的映射,如果只提供給geom_point(),則相當于是局部變量,geom_point知道這種映射,而stat_smooth不知道,當然你再給stat_smooth也提供x,y的映射,不過共用的映射,還是提供給ggplot好。 stat_abline stat_contour stat_identity stat_summarystat_bin stat_density stat_qq stat_summary2dstat_bin2d stat_density2d stat_quantile stat_summary_hexstat_bindot stat_ecdf stat_smooth stat_uniquestat_binhex stat_function stat_spoke stat_vlinestat_boxplot stat_hline stat_sum stat_ydensity 統(tǒng)計變換是非常重要的功能,我們可以自己寫函數(shù),基于原始數(shù)據(jù)做某種計算,并在圖上表現(xiàn)出來,也可以通過它改變geom_xxx函數(shù)畫圖的默認統(tǒng)計參數(shù)。 坐標系統(tǒng)(Coordinante)坐標系統(tǒng)控制坐標軸,可以進行變換,例如XY軸翻轉(zhuǎn),笛卡爾坐標和極坐標轉(zhuǎn)換,以滿足我們的各種需求。 坐標軸翻轉(zhuǎn)由coord_flip()實現(xiàn) ggplot(small)+geom_bar(aes(x=cut, fill=cut))+coord_flip() 而轉(zhuǎn)換成極坐標可以由coord_polar()實現(xiàn): ggplot(small)+geom_bar(aes(x=factor(1), fill=cut))+coord_polar(theta='y') 這也是為什么之前介紹常用圖形畫法時沒有提及餅圖的原因,餅圖實際上就是柱狀圖,只不過是使用極坐標而已,柱狀圖的高度,對應(yīng)于餅圖的弧度,餅圖并不推薦,因為人類的眼睛比較弧度的能力比不上比較高度(柱狀圖) 還可以畫靶心圖: ggplot(small)+geom_bar(aes(x=factor(1), fill=cut))+coord_polar() 以及風玫瑰圖(windrose) ggplot(small)+geom_bar(aes(x=clarity, fill=cut))+coord_polar() 圖層(Layer)photoshop流行的原因在于PS 有了圖層的概念,使用ggplot畫起圖來,就更加得心應(yīng)手。 做為圖層的一個很好的例子是蝙蝠俠logo,batman require(ggplot2)f1 <->->function(x) { y1 <->->3*sqrt(1-(x/7)^2) y2 <->->3*sqrt(1-(x/7)^2) y <- c(y1,y2)="" ="" d="">-><- data.frame(x="x,y=y)" ="" d="">-><- d[d$y=""> -3*sqrt(33)/7,] return(d)}x1 <->->3, 7, 0.001), seq(-7, -3, 0.001))d1 <- f1(x1)p1="">-><- ggplot(d1,aes(x,y))="" +="" geom_point(color="">->'red') +xlab('') + ylab('') + theme_bw()x2 <->->4,4, 0.001)y2 <->->2)-(3*sqrt(33)-7)*x2^2/112-3 + sqrt(1-(abs(abs(x2)-2)-1)^2)d2 <- data.frame(x2="x2," y2="y2)p2">-><- p1="" +="" geom_point(data="d2," aes(x="x2,y=y2)," color="">->'yellow')x3 <->->0.75,1,0.001), seq(-1,-0.75,0.001))y3 <->->9-8*abs(x3)d3 <- data.frame(x3="x3," y3="y3)p3">-><- p2+geom_point(data="d3," aes(x="x3,y=y3)," color="">->'green')x4 <->->0.5,0.75,0.001), seq(-0.75,-0.5,0.001))y4 <->->3*abs(x4)+0.75d4 <- data.frame(x4="x4,y4=y4)p4">-><- p3+geom_point(data="d4," aes(x="x4,y=y4)," color="">->'steelblue')x5 <->->0.5,0.5,0.001)y5 <->->2.25,length(x5))d5 <- data.frame(x5="x5,y5=y5)p5">-><- p4+geom_point(data="d5," aes(x="x5,y=y5))x6">-><->->3,-1,0.001), seq(1,3,0.001))y6 <->->6 * sqrt(10)/7 + (1.5 - 0.5 * abs(x6)) * sqrt(abs(abs(x6)-1)/(abs(x6)-1)) - 6 * sqrt(10) * sqrt(4-(abs(x6)-1)^2)/14d6 <- data.frame(x6="x6,y6=y6)p6">-><- p5+geom_point(data="d6,aes(x=x6,y=y6)," colour="">->'blue')multiplot <->->function (..., plotlist = NULL, cols = 1, layout = NULL) { plots <->->...), plotlist) numPlots = length(plots) if (is.null(layout)) { layout <->->1, cols * ceiling(numPlots/cols)), ncol = cols, nrow = ceiling(numPlots/cols)) } if (numPlots == 1) { print(plots[[1]]) } else { grid.newpage() pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout)))) for (i in 1:numPlots) { matchidx <- as.data.frame(which(layout="=" i,="" arr.ind="">->TRUE)) print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row, layout.pos.col = matchidx$col)) } }}multiplot(p1,p2,p3,p4,p5,p6, cols=2)-> 分面(Facet)在《ggplot2: 數(shù)據(jù)分析與圖形藝術(shù)》一書的翻譯中,一開始譯者把facet翻譯成切片,我在校稿的時候發(fā)現(xiàn)了,給他們寫信,推薦翻譯成分面,如果是slice這個詞,翻譯成切片倒是很精準,BSD的硬盤分區(qū)就叫slice,但facet從詞源上看就是小臉的意思,翻譯成分面才到位。給他們寫信的時候,我還專門查了CNKI翻譯助手,發(fā)現(xiàn)這詞在信息學(xué)中,翻成分面早已是固定的。我感覺這是我對這本書翻譯的最大貢獻,校稿過程中發(fā)現(xiàn)的少量小問題遠比不上這個關(guān)鍵詞意思的把握上。 分面可以讓我們按照某種給定的條件,對數(shù)據(jù)進行分組,然后分別畫圖。 ggplot(small, aes(x=carat, y=price))+geom_point(aes(colour=cut))+scale_y_log10() +facet_wrap(~cut)+stat_smooth() 主題(Theme)通過ggplot畫圖之后,我們可能還需要對圖進行定制,像title, xlab, p <- ggplot(small)+geom_boxplot(aes(x="cut," y="price,fill=color))p" +="">->'Price vs Cut')+xlab('Cut')+ylab('Price') 但是這個遠遠滿足不了需求,我們需要改變字體,字體大小,坐標軸,背景等各種元素,這需要通過theme()函數(shù)來完成。 ggplot2提供一些已經(jīng)寫好的主題,比如 別外ggthemes包提供了一些主題可供使用,包括: theme_economist theme_economist_whitetheme_wsj theme_exceltheme_few theme_foundationtheme_igray theme_solarizedtheme_stata theme_tufte require(ggthemes)p + theme_wsj() 在2013年發(fā)表的文章Putative cobalt- and nickel-binding proteins and motifs in Streptococcus pneumoniae中的圖3就是使用 至于如何改變這些元素,我覺得我之前畫囧字的博文可以做為例子: f <- function(x)="" 1/(x^2-1)x="">-><- seq(-3,3,="" by="0.001)y">-><- f(x)d="">-><- data.frame(x="x,y=y)p">-><- ggplot()p="">-><- p+geom_rect(fill='white' ,color='black' ,size="3,aes(NULL," null,xmin="-3," xmax="3,ymin=-3,ymax=3," alpha="0.1))p">-><- p="" +="" geom_line(data="d," aes(x,y),="" size="3)+ylim(-3,3)theme_null">-><- function()="" {="" ="" theme_bw()="" %+replace%="" ="" theme(axis.text.x="element_blank()," ="" axis.text.y="element_blank()," ="" legend.position='none' ,="" ="" panel.grid.minor="element_blank()," ="" panel.grid.major="element_blank()," ="" panel.background="element_blank()," ="" axis.ticks="element_blank()," ="" panel.border="">-> 詳細的說明,可以參考?theme的幫助文檔。 二維密度圖在這個文檔里,為了作圖方便,我們使用diamonds數(shù)據(jù)集的一個子集,如果使用全集,數(shù)據(jù)量太大,畫出來散點就糊了,這種情況可以使用二維密度力來呈現(xiàn)。 ggplot(diamonds, aes(carat, price))+ stat_density2d(aes(fill = ..level..), geom='polygon')+ scale_fill_continuous(high='darkred',low='darkgreen') ggplot2實例蝴蝶圖: theta <->->0,24*pi, len=2000)radius <- exp(cos(theta))="" -="">->2*cos(4*theta) + sin(theta/12)^5dd <- data.frame(x="radius*sin(theta)," y="radius*cos(theta))ggplot(dd," aes(x,="">->'')+ylab('') 這個圖,我想展示的是對細節(jié)的修改上,在畫囧字的時候,把畫布上的元素都給清除了,我把它定義為theme_null主題,在這里,直接應(yīng)用,我們可以形成自己的畫圖風格,并寫出自己的主題函數(shù)固定下來。 最后以生物界中常用的柱狀圖+誤差圖為實例,展示ggplot2非常靈活的圖層。以我2011年發(fā)表的文章Phosphoproteome profile of human lung cancer cell line A549中的westernblot數(shù)據(jù)為例。這個實例展示了圖層,標尺,主題,注釋和各種細節(jié)微調(diào)多種元素。 Normal <- c(0.83,="" 0.79,="" 0.99,="" 0.69)cancer="">-><- c(0.56,="" 0.56,="" 0.64,="" 0.52)m="">-><- c(mean(normal),="" mean(cancer))s="">-><- c(sd(normal),="" sd(cancer))d="">-><- data.frame(v="c('Normal'," 'cancer'),="" mean="m," sd="s)d$V">-><- factor(d$v,="" levels="c('Normal'," 'cancer'))p="">-><- ggplot(d,="" aes(v,="" mean,="" fill="V," width=".5))p">-><- p+geom_errorbar(aes(ymin="mean," ymax="mean+sd," width=".2)," ="" ="" ="" ="" ="" ="" ="" ="" ="" ="" position="position_dodge(width=.8))p">-><- p="" +="" geom_bar(stat='identity' ,="" position="position_dodge(width=.8)," colour='black' )p="">-><- p="" +="" scale_fill_manual(values="c('grey80'," 'white'))p="">-><- p="" +="" theme_bw()="" +theme(legend.position='none' )="" +="" xlab('')="" +="" ylab('')p="">-><- p="" +="" theme(axis.text.x="element_text(face='bold'," size="12)," ="" ="" ="" ="" ="" ="" ="" axis.text.y="element_text(face='bold'," size="12))p">-><- p+scale_y_continuous(expand="c(0,0)," limits="c(0," 1.2),="" breaks="seq(0," 1.2,="" by=".2))p">-><- p+geom_segment(aes(x="1," y=".98," xend="1," yend="1.1))p">-><- p+geom_segment(aes(x="2," y=".65," xend="2," yend="1.1))p">-><- p+geom_segment(aes(x="1," y="1.1," xend="2," yend="1.1))p">-><- p="" +="" annotate('text',="" x="1.5," y="1.08," label='*'>-> |
|
來自: 昵稱39769750 > 《文件夾1》