使用lattice進行高級繪圖是我之前在學習《R實戰(zhàn)》這本書少有涉及的章節(jié)之一浓瞪,在R里面懈玻,主要有兩大底層圖形系統(tǒng),一是base乾颁,二是grid涂乌。lattice與ggplot2正是基于grid構建,它們都有自己獨特的圖形語法英岭。我當前使用的主要是ggplot2湾盒,base畫圖基本不用,這里學習下lattice包并想后續(xù)深入學習繪圖的底層原理與實現(xiàn)诅妹。
內容:
- lattice包介紹
- 分組與調節(jié)
- 在面板函數(shù)中添加信息
- 自定義lattice圖形的外觀
這幾年開始學習R語言的估計對ggplot2要比lattice包熟悉很多罚勾,后者雖然在初學者中名聲不顯,但就憑lattice內置于R吭狡,而ggplot2要額外安裝來看尖殃,前者毫無疑問是被前輩們所廣泛使用的,這篇文章來正式學習一下划煮。
我們將一起學習Deepayan Sarkar(2008)編寫的lattice包送丰,它實現(xiàn)了Cleveland(1983,1993)提出的網格圖形。lattice包已經超越了Cleveland的初始可視化數(shù)據的方法弛秋,并且提供了一系列創(chuàng)建統(tǒng)計圖形的復雜方法器躏。
像ggplot2一樣,lattice圖形有它自己的語法蟹略,提供了對基礎圖形的替代方案登失,并且擅長繪制復雜數(shù)據。
lattice包
網格圖形能夠展示變量的分布或變量之間的關系挖炬,每幅圖代表一個或多個變量的各個水平揽浙。思考下面一個問題:紐約合唱團各聲部的歌手身高是如何變化的?
lattice包在singer數(shù)據集中提供了這兩個變量的數(shù)據:
library(lattice)
histogram(~height | voice.part, data = singer, main = "Distribution of Heights by Voice Pitch",
xlab = "Height (inches)")
從這幅圖可以看出,似乎男高音和男低音比女低音和女高音的身高更高捏萍。
在網格圖中太抓,調節(jié)變量的每個水平生成一個獨立的面板空闲。如果指定多個調節(jié)變量令杈,這些變量因子水平的每個組合都會生成一個面板(類似于ggplot2中的分面概念)。面板被分配到數(shù)組中以便于比較碴倾。在每個面板名為條帶的區(qū)域中會提供一個標簽逗噩。用戶可以控制每個面板上的圖形,條板的格式與放置的位置跌榔,面板的安排异雁,圖例的放置和內容以及其他許多的圖形特征。
lattice包提供了大量的函數(shù)來產生單因素圖(點圖僧须、核密度圖纲刀、直方圖、條形圖與箱線圖)担平,二元圖(散點圖示绊、條形圖、平行箱線圖)和多元圖(3D圖暂论、散點圖矩陣)面褐。每個高水平的畫圖函數(shù)都服從下面的格式:
graph_function(formula, data=, options)
- graph_function 是下表的一個函數(shù)铸豁;
- formula 指定要展示的變量和任意的調節(jié)變量球订;
- data 指定數(shù)據框苏章;
- options 是用逗號分隔的參數(shù)亡脸,用來調整圖形的內容颖杏、安排和注釋领突。
我們假定小寫字母代表數(shù)值型變量笋敞,大寫字母代表分類型變量(因子)观挎。高水平的畫圖函數(shù)通常采用的格式是:
y ~ x | A * B
其中豎線左側稱為主要變量觉痛,右邊的變量稱為調節(jié)變量役衡。
圖類型 | 函數(shù) | 公式例子 |
---|---|---|
3D等高線圖 | contourplot() | z~x*y |
3D水平圖 | levelplot() | z~y*x |
3D散點圖 | cloud() | z~x*y|A |
3D線框圖 | wireframe() | z~y*x |
條形圖 | barchart() | xA或Ax |
箱線圖 | bwplot() | xA或Ax |
點圖 | dotplot() | ~x|A |
柱狀圖/直方圖 | histogram() | ~x |
核密度圖 | densityplot() | ~x|A*B |
平行坐標曲線圖 | parallelplot() | dataframe |
散點圖 | xyplot() | y~x|A |
散點圖矩陣 | splom() | dataframe |
線框圖 | stripplot() | xA或Ax |
為了盡快對lattice圖有一個認識,我們嘗試運行下面的代碼秧饮。里面的圖基于mtcars數(shù)據框中的汽車數(shù)據(里程映挂、車重、擋數(shù)盗尸、汽缸數(shù)等)柑船。
library(lattice)
attach(mtcars)
gear <- factor(gear, levels = c(3, 4, 5),
labels = c("3 gears", "4 gears", "5 gears"))
cyl <- factor(cyl, levels = c(4, 6, 8),
labels = c("4 cylinders", "6 cylinders", "8 cylinders"))
# 開始畫圖
densityplot(~mpg, main = "Density Plot",
xlab = "Miles per Gallon")
densityplot(~mpg | cyl,
main = "Density Plot by Number of Cylinders",
xlab = "Miles per Gallon")
bwplot(cyl ~ wt | gear,
main = "Box Plots by Cylinders and Gears",
xlab = "Miles per Gallon",
ylab = "Cylinders")
xyplot(mpg ~ wt | cyl * gear,
main = "Scatter Plots by Cylinders and Gears",
xlab = "Car Weight", ylab = "Miles per Gallon")
[圖片上傳失敗...(image-81350d-1528447963024)]
cloud(mpg ~ wt * qsec | cyl,
main = "3D Scatter Plots by Cylinders")
dotplot(cyl ~ mpg | gear,
main = "Dot Plots by Number of Gears and Cylinders",
xlab = "Miles Per Gallon")
splom(mtcars[c(1:6)],
main = "Scatter Plot Matrix for mtcars Data")
detach(mtcars)
其中ggplot2不能畫3D圖形,而lattice可以泼各。
lattice包中的高水平畫圖函數(shù)能產生可保存和修改的圖形對象鞍时,例如:
library(lattice)
mygraph <- densityplot(~height|voice.part, data=singer)
創(chuàng)建一個網格密度圖,并把它保存為對象mygraph
,但是沒有圖形展示逆巍。使用plot(mygraph)
將會顯示該圖及塘。
通過調整選項很容易更改lattice圖形,常見的選項列在下表中:
選項 | 描述 |
---|---|
aspect | 指定每個面板圖形的縱橫比(高度/寬度)的一個數(shù)字 |
col锐极、pch笙僚、lty、lwd | 分別指定在圖中使用的顏色灵再、符號肋层、線類型和線寬度的向量 |
group | 分組變量(因子) |
index.coord | 列出展示面板順序的列表 |
key (auto.key) | 支持分組變量中圖例的函數(shù) |
layout | 指定面板設置(列數(shù)與行數(shù))的二元素數(shù)值向量,如果需要翎迁,可以增加一個元素來表示頁面數(shù) |
main栋猖、sub | 指定主標題和副標題的字符向量 |
panel | 在每個面板中生成圖的函數(shù) |
scales | 列出提供坐標軸注釋信息的列表 |
strip | 用于自定義面板條帶的函數(shù) |
split、position | 數(shù)值型向量汪榔,在一頁上繪制多幅圖像 |
type | 指定一個或多個散點圖繪圖選項(p=點蒲拉、l=線、r=回歸線痴腌、smooth=局部多項式回歸擬合雌团、g=網格圖形)的字符向量 |
xlab、ylab | 指定橫軸和縱軸標簽的字符向量 |
xlim衷掷、ylim | 指定橫軸和縱軸最小值辱姨、最大值的二元數(shù)值向量 |
我們可以在高級函數(shù)內部或者后面討論的面板函數(shù)內使用這些選項。
我們也可以使用update()函數(shù)來調整lattice圖形對象戚嗅。
繼續(xù)歌手的例子:
plot(mygraph)
update(mygraph, col="red", pch=16, cex=.8, jitter=.05, lwd=2)
調節(jié)變量
通常情況下雨涛,調節(jié)變量是因子。但是對于連續(xù)的變量該如何操作呢懦胞?一種方式是使用R的cut()函數(shù)將連續(xù)的變量轉換為離散的變量替久,另一種方法是lattice包提供可以將連續(xù)變量轉換為名為shingle的數(shù)據結構。具體來說躏尉,連續(xù)變量被分成一系列(可能)重疊的范圍蚯根。
例如函數(shù)
myshingle <- equal.count(x, number=n, overlap=proportion)
將連續(xù)的變量x分成n個間隔,重疊的比例是proportion胀糜,每個間隔里的觀測值個數(shù)相同颅拦,并將其返回為變量myshingle。
一旦變量轉化為shingle教藻,就可以用它作為一個調節(jié)變量距帅。例如mtcars中的發(fā)動機排量是一個連續(xù)的變量,我們可以首先把它轉換為3水平的shingle變量:
displacement <- equal.count(mtcars$disp, number=3, overlap=0)
接下來把它應用到xyplot()
函數(shù)中:
xyplot(mpg ~ wt|displacement, data = mtcars,
main = "Miles per Gallon vs. Weight by Engine Displacement",
xlab = "Weight", ylab = "Miles per Gallon",
layout = c(3, 1), aspect = 1.5)
這里我們使用了選項來調整面板的布局(一行3列)和縱橫比(高/寬)來讓三組的對比變得更容易括堤。
下面我們學習面板函數(shù)來進一步自定義輸出碌秸。
面板函數(shù)
每一個高水平的畫圖函數(shù)都采用了默認的函數(shù)來繪制面板圖绍移。默認函數(shù)遵循命名規(guī)則panel.graph_function
,例如
xyplot(mpg~wt|displacement, data=mtcars)
也可以寫成:
xyplot(mpg~wt|displacement, data=mtcars, panel=panel.xyplot)
這是一個強大的功能讥电,因為它可以讓我們用自己設計的默認函數(shù)來代替默認的面板函數(shù)蹂窖。我們也可以將lattice包50多個默認函數(shù)中的一個或者多個集成到我們自定義的函數(shù)中,自定義的面板函數(shù)在設計滿足我們需求的輸出時給了我們很大的靈活性恩敌。
下面我們來看些例子瞬测。
在前面,我們畫出了以汽車發(fā)動機排量為條件的汽車重量的油耗潮剪,如果你想要加上回歸線涣楷、地毯圖和網格線分唾,我們需要怎么做呢抗碰?
library(lattice)
displacement <- equal.count(mtcars$disp, number=3, overlap=0)
mypanel <- function(x, y){
panel.xyplot(x, y, pch=19)
panel.rug(x,y)
panel.grid(h=-1, v=-1) # 添加水平和垂直的網格線
panel.lmline(x, y, col="red", lwd=1, lty=2) # 添加回歸曲線
}
xyplot(mpg ~ wt|displacement, data=mtcars,
layout=c(3,1),
aspect=1.5,
main = "Miles per Gallon vs. Weight by Engine Displacement",
xlab = "Weight",
ylab = "Miles per Gallon",
panel = mypanel)
在第二個例子中,我們將畫出以汽車變速器類型為條件的油耗和發(fā)動機排量之間的關系绽乔。除了畫出自動和手動變速器發(fā)動機獨立的面板圖外弧蝇,我們還將添加擬合曲線和水平均值曲線。
library(lattice)
mtcars$transmission <- factor(mtcars$am, levels=c(0,1), labels=c("Automatic", "Manual"))
panel.smoother <- function(x, y){
panel.grid(h=-1, v=-1)
panel.xyplot(x, y)
panel.loess(x, y)
panel.abline(h = mean(y), lwd = 2, lty = 2, col = "darkgreen")
}
xyplot(mpg~disp|transmission,data=mtcars,
scales=list(cex=.8, col="red"),
panel = panel.smoother,
xlab = "Displacement", ylab = "Miles per Gallon",
main = "MPG vs Displacement by Transmission Type",
sub = "Dotted lines are Groups Means", aspect = 1)
分組變量
當你在lattice繪圖公式中增加調節(jié)變量時折砸,該變量的每個水平的獨立面板就會產生看疗。如果想添加的結果和每個水平正好相反,可以指定改變了為分組變量睦授。
比如說两芳,我們想利用核密度圖展示使用手動和自動變速器時汽車的油耗的分布:
densityplot(~mpg, data=mtcars,
group=transmission,
main="MPG Distribution by Transmission Type",
xlab = "Miles per Gallon",
auto.key = TRUE)
默認情況下,group=選項添加分組變量每個水平的圖去枷。值得注意的是怖辆,圖例和關鍵字不會在默認情況下生成,這里auto.key=TRUE
創(chuàng)建一個基本圖例并把它放在圖的上方删顶。
下面實現(xiàn)更加自定義的圖形:
colors <- c("red", "blue")
lines <- c(1,2)
points <- c(16, 17)
key.trans <- list(title="Transmission",
space="bottom", columns=2,
text=list(levels(mtcars$transmission)),
points=list(pch=points, col=colors),
lines=list(col=colors, lty=lines),
cex.title=1, cex=.9)
densityplot(~mpg, data=mtcars,
group=transmission,
main="MPG Distribution by Transmission Type",
xlab = "Miles per Gallon",
pch=points, lty=lines, col=colors,
lwd=2, jitter=.005,
key=key.trans)
讓我們使用R自帶的CO2數(shù)據集討論一下在單個圖中包含分組和調節(jié)變量的例子竖螃。
這個數(shù)據集描述了12種植物在7種二氧化碳濃度下的二氧化碳吸收率。6種植物來自魁北克逗余,6種來自密西西比特咆。每個產地有3種植物在冷藏條件下研究,3種在非冷藏條件下研究录粱。在該例子中腻格,plant
是分組變量,Type
和Treatment
是調節(jié)變量啥繁。
library(lattice)
colors <- "darkgreen"
symbols <- c(1:12)
linetypes <- c(1:3)
key.species <- list(title="Plant",
space = "right",
text = list(levels(CO2$Plant)),
points = list(pch=symbols, col=colors))
xyplot(uptake~conc|Type*Treatment, data=CO2,
group=Plant,
type="o",
pch=symbols, col=colors, lty=linetypes,
main = "Carbon Dioxide Uptake\nin Grass Plants",
ylab = "Uptake",
xlab = "Concentration",
sub = "Grass Species: Echinochloa crus-galli",
key = key.species)
圖形參數(shù)
lattice圖形不受par()
函數(shù)的影響菜职,它使用的默認設置在一個大的列表對象中,可以通過trellis.par.get()
函數(shù)獲得并通過trellis.par.set()
函數(shù)更改输虱。我們可以使用show.settings()
函數(shù)來直觀地展示當前的圖形設置些楣。
查看默認設置:
show.settings()
將它們保存到列表:
mysettings <- trellis.par.get()
可以使用names()
查看列表成分:
names(mysettings)
## [1] "grid.pars" "fontsize" "background"
## [4] "panel.background" "clip" "add.line"
## [7] "add.text" "plot.polygon" "box.dot"
## [10] "box.rectangle" "box.umbrella" "dot.line"
## [13] "dot.symbol" "plot.line" "plot.symbol"
## [16] "reference.line" "strip.background" "strip.shingle"
## [19] "strip.border" "superpose.line" "superpose.symbol"
## [22] "superpose.polygon" "regions" "shade.colors"
## [25] "axis.line" "axis.text" "axis.components"
## [28] "layout.heights" "layout.widths" "box.3d"
## [31] "par.xlab.text" "par.ylab.text" "par.zlab.text"
## [34] "par.main.text" "par.sub.text"
修改:
mysettings$superpose.symbol$pch <- c(1:10)
trellis.par.set(mysettings)
查看更改:
show.settings()
自定義圖形條帶
面板條帶默認的背景是:第一個調節(jié)變量時桃紅色,第二個調節(jié)變量時淺綠色,第三個調節(jié)變量的淺藍色愁茁。我們可以使用上一節(jié)描述的方法蚕钦;或是加強控制,寫一個自定義條帶各方面的函數(shù)鹅很。
library(lattice)
histogram(~height | voice.part, data = singer,
strip = strip.custom(bg="lightgrey",
par.strip.text = list(color="black", cex=.8, font=3)),
main = "Distribution of Heights by Voice Pitch",
xlab = "Height (inches)")
option=
選項用來指定設定條帶外觀的函數(shù)嘶居,盡管我們可以從頭寫一個函數(shù)(參見?strip.default
),但是改變一些設置并使用其他項的默認值更簡單促煮。strip.custom()
函數(shù)可以幫助我們實現(xiàn)邮屁。bg
選項控制了背景顏色,par.strip.text
允許我們控制條帶文本的外觀菠齿。font
選項可以分別取數(shù)值1佑吝、2、3绳匀、4芋忿,代表正常字體、粗體疾棵、斜體和粗斜體戈钢。
頁面布局
split
選項將一個頁面分成指定數(shù)量的行和列,并把圖放到結果矩陣的特定單元格是尔。split
選項的格式是:
split = c(x, y, nx, ny)
也就是在包括nx
乘以ny
個圖形的數(shù)組中殉了,把當前圖形放在x,y
的位置,圖形的起始位置是在左上角拟枚。
library(lattice)
graph1 <- histogram(~height | voice.part, data = singer,
main = "Height of Choral Singers by Voice Part")
graph2 <- bwplot(height~voice.part, data = singer)
plot(graph1, split = c(1, 1, 1, 2))
plot(graph2, split = c(1, 2, 1, 2), newpage = FALSE)
我們可以更好的控制尺寸:
plot(graph1, position = c(0, .3, 1, 1))
plot(graph2, position = c(0, 0, 1, .3), newpage = FALSE)
這里的position=c(xmin, ymin, xmax, ymax)
選項中薪铜,頁面的坐標系是x軸和y軸都從0到1的矩形,原點在左下角的(0,0)梨州。
我們還可以控制面板的順序
histogram(~height | voice.part, data = singer,
index.cond = list(c(2, 4, 6, 8, 1, 3, 5, 7)))
深入學習
Deepayan Sarkar 的“Lattice Graphics: An Introduction”(http://mng.bz/jXUG, 2008)和Willian G.Jacoby的“An Introduction to Lattice Graphics in R” (http://mng.bz/v4TO, 2010)