R 數據可視化 —— ggplot2 分面

前言

分面的作用是在一個頁面上自動放置多幅圖像郁油,它先將數據劃分為多個不同的子集,然后分別將每個子數據集繪制到頁面的小圖形面板中腕窥。

ggplot2 有兩種分面類型:

  • 網格型 —— facet_grid

    生成一個 2 維面板網格,通過行列對應變量的不同 level

  • 封裝型 —— facet_wrap

    生成一個 1 維面板,然后按行或按列順序添加子圖進去吊档,形成 2 維布局

二者之間的區(qū)別,可以從下圖中看出

1. 網格分面

facet_grid(
  rows = NULL,
  cols = NULL,
  scales = "fixed",
  space = "fixed",
  shrink = TRUE,
  labeller = "label_value",
  as.table = TRUE,
  switch = NULL,
  drop = TRUE,
  margins = FALSE,
  facets = NULL
)

網格分面會根據分面表達式唾糯,自動設置哪些變量作為行怠硼,哪些變量作為列鬼贱,具體規(guī)則如下:

  1. 不分面

不使用 facet_grid 或加上 facet_null()

ggplot(mpg, aes(cty, hwy)) + 
  geom_point() +
  facet_null()
  1. 一行多列:. ~ var

寬屏顯示,所有圖繪制在同一行香璃,方便比較不同圖之間的 y 軸位置这难。

ggplot(mpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(. ~ cyl)
  1. 多行一列:var ~ .

豎直排列,具有相同的橫坐標葡秒,方便比較 x 軸的位置姻乓,尤其適用于不同數據分布的比較。

ggplot(mpg, aes(cty)) + 
  geom_histogram(binwidth = 2) +
  facet_grid(cyl ~ .)
  1. 多行多列:var1 ~ var2

通常將 level 最多的變量按列放置眯牧,充分利用屏幕的寬高比

ggplot(mpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(drv ~ cyl)

注意:在上面的圖形中糖权,我們可以看到三個空白的面板,這是由于行列變量的不同 level 會兩兩組合炸站,每種組合繪制一張圖片星澳,而沒有在數據中出現的組合會產生空白圖。

  1. 多個變量組合在同一行或同一列:. ~ var1 + var2(一行) 或 var1 + var2 ~ .(一列)
ggplot(mpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(cyl + drv ~ .)

與多行多列圖形不同旱易,只有出現的組合才會被繪制禁偎,所以不會出現空白圖片。

注意

上面的表達式也可以轉換為用 vars 函數引用的變量阀坏,例如

. ~ var         => cols = vars(var)
var ~ .         => rows = vars(var)
var1 ~ var2     => rows = vars(var1), cols = vars(var2)
. ~ var1 + var2 => cols = vars(var1, var2)

對于 facet_gridfacet_wrap 均適用

邊際圖

對于多行多列的網格狀圖如暖,我們可能希望在每行或每列的數據值進行一個匯總,添加一個匯總圖忌堂。

我們可以設置 margins = TRUE 來展示所有的邊際匯總圖盒至,或者指定一個字符串或字符串向量如 margins = c("", ""),來展示某一個變量的邊際匯總圖

例如

smpg <- mpg %>% subset(drv != 'r' & cyl != 5)

p1 <- ggplot(smpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(rows = vars(drv), cols = vars(cyl))

p2 <- ggplot(smpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(rows = vars(drv), cols = vars(cyl), 
             margins = TRUE)

p3 <- ggplot(smpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(rows = vars(drv), cols = vars(cyl), 
             margins = "drv")

p4 <- ggplot(smpg, aes(cty, hwy)) + 
  geom_point() +
  facet_grid(rows = vars(drv), cols = vars(cyl), 
             margins = "cyl")

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

2. 封裝分面

facet_wrap(
  facets,
  nrow = NULL,
  ncol = NULL,
  scales = "fixed",
  shrink = TRUE,
  labeller = "label_value",
  as.table = TRUE,
  switch = NULL,
  drop = TRUE,
  dir = "h",
  strip.position = "top"
)

不同于網格分面士修,封裝分面可以這樣理解枷遂,它首先生成一個長的繪圖面板,然后將圖形一個個添加進去棋嘲,填充完一行后另起一行開始填充酒唉,這樣看起來也是二維的面板。

示例

p <- ggplot(mpg, aes(displ, hwy)) + geom_point()

p1 <- p + facet_wrap(vars(class))

# 控制行列數
p2 <- p + facet_wrap(vars(class), nrow = 4)

# 組合多變量
p3 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl, drv))

# 控制顯示的標簽
p4 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl, drv), labeller = "label_both")

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

想要更改面板圖形的顯示順序沸移,需要修改對應因子變量的 level 順序

mpg$class2 <- reorder(mpg$class, mpg$displ)
p5 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  facet_wrap(vars(class2))

plot_grid(p1, p5, labels = LETTERS[1:2], nrow = 2)

通過將數據的分面變量設置為 NULL痪伦,可以在所有的子圖中繪制一個相同的圖像

例如,我們通過將分面變量設置為空雹锣,在所有子圖中繪制了一個包含所有數據點的淺色點圖网沾,這樣可以更清晰的看出各部分占總體的情況

ggplot(mpg, aes(displ, hwy)) +
  geom_point(data = transform(mpg, class = NULL), colour = "grey85") +
  geom_point() +
  facet_wrap(vars(class))

這也相當于為所有面板添加了一個背景圖

3. 標度控制

兩種分面都可以使用 scales 來控制面板的位置標度是否固定,可以取以下值:

  • fixed:所有面板的 xy 都是一樣的蕊爵,默認值
  • free:所有面板的 xy 都是自由變化的
  • free_xx 軸可變辉哥,y 軸固定
  • free_yx 軸固定,y 軸可變
p1 <- ggplot(mpg, aes(cty, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl), scales = "fixed")

p2 <- ggplot(mpg, aes(cty, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl), scales = "free")

p3 <- ggplot(mpg, aes(cty, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl), scales = "free_x")

p4 <- ggplot(mpg, aes(cty, hwy)) +
  geom_point() +
  facet_wrap(vars(cyl), scales = "free_y")

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

對于 facet_grid 還有一個 space 參數在辆,可接受的值同 scales 一樣

  • fixed:所有面板的大小一樣证薇,默認值
  • free:它們的高度和寬度與標度范圍成比例
  • free_x:它們的寬度與 x 標度的長度成比例
  • free_y:它們的高度與 y 標度的長度成比例
ggplot(mpg, aes(drv, model)) +
  geom_point() +
  facet_grid(manufacturer ~ ., scales = "free", space = "free")

4. 分組與分面

我們可以將分組和分面放在一起進行比較。在之前的示例中匆篓,我們可以為數據設置不同的圖像屬性浑度,如顏色、大小等鸦概,來區(qū)分不同的分組

而分面是根據變量的 level 繪制不同的子圖箩张。這兩種方式都有各自的優(yōu)缺點。

在分面中窗市,不同組別擁有不同的面板先慷,相隔較遠,難以看出組間的關系咨察;但是不存在組間數據的重疊论熙,能夠很好的分隔數據。

而分組則與分面互補摄狱,組間容易重疊脓诡,但是能夠較容易可以看出組間的關系。

例如

xmaj <- c(0.3, 0.5, 1,3, 5) 
xmin <- as.vector(outer(1:10, 10^c(-1, 0))) 
ymaj <- c(500, 1000, 5000, 10000) 
ymin <- as.vector(outer(1:10, 10^c(2,3,4))) 

dsub <- subset(diamonds, color %in% c("D","E","G","J"))

p <- ggplot(dsub, aes(carat, price, colour = color)) +
  scale_x_log10(breaks = xmaj, labels = xmaj, minor = xmin) +
  scale_y_log10(breaks = ymaj, labels = ymaj, minor = ymin) +
  scale_colour_hue(limits = levels(diamonds$color)) +
  theme(legend.position = "none")

p1 <- p + geom_point() 
p2 <- p + geom_point() + facet_grid(. ~ color)

plot_grid(p1, p2, labels = LETTERS[1:2], nrow = 2)

在圖 A 中媒役,各分組之間都交疊在一起了祝谚,很難區(qū)分誰是誰,而使用分面酣衷,可以將每組都區(qū)分開交惯,每組的趨勢也很明顯

但是,當我們使用回歸線時穿仪,情況又有些不同了

p3 <- p + geom_smooth(method = lm, se = F, fullrange = T) 
p4 <- p + geom_smooth(method = lm, se = F, fullrange = T) + facet_grid(. ~ color)

plot_grid(p3, p4, labels = LETTERS[3:4], nrow = 2)

在圖 C 中席爽,我們可以看到 DEG 幾乎完全重疊啊片,而 J 則與它們相隔更遠

分面還有其他優(yōu)點拳昌,比如,能夠很好的設置分組的圖形屬性和標度等钠龙。

5. 并列與分面

可以使用分面繪制出與并列圖形類似的效果炬藤,但是分面的標注方式會更多一些。

例如

p1 <- ggplot(diamonds, aes(color, fill = cut)) +
  geom_bar(position = "dodge")

p2 <- ggplot(diamonds, aes(cut, fill = cut)) + 
  geom_bar() +
  facet_grid(. ~ color) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 8, 
                                   colour = "grey50"))

plot_grid(p1, p2, labels = LETTERS[1:2], nrow = 2)

6. 連續(xù)型變量的分面

在本章前面的示例中碴里,都是對離散型變量進行分面沈矿,對于連續(xù)型數據,需要先將其轉換為離散型咬腋。

有三種轉換方式:

  • 按區(qū)間劃分:
    • cut_interval(x, n = 10): 劃分為 10 個區(qū)間
    • cut_interval(x, length = 10):每個區(qū)間長度為 10
  • 等數量劃分:
    • cut_number(x, n=10): 劃分為 10 個區(qū)間羹膳,每個區(qū)間數量相同

例如

df <- subset(mpg, year == 1999)
df$disp_ww <- cut_interval(df$displ, length = 1) 
df$disp_wn <- cut_interval(df$displ, n = 6) 
df$disp_nn <- cut_number(df$displ, n = 6) 

p <- ggplot(df, aes(cty, hwy)) + 
  geom_point() +
  labs(x = NULL, y = NULL) 

p1 <- p + facet_wrap(~ disp_ww, nrow = 1) 
p2 <- p + facet_wrap(~ disp_wn, nrow = 1) 
p3 <- p + facet_wrap(~ disp_nn, nrow = 1)

plot_grid(p1, p2, p3, labels = LETTERS[1:3], nrow = 3)
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市根竿,隨后出現的幾起案子陵像,更是在濱河造成了極大的恐慌就珠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件醒颖,死亡現場離奇詭異妻怎,居然都是意外死亡,警方通過查閱死者的電腦和手機泞歉,發(fā)現死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門逼侦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腰耙,你說我怎么就攤上這事榛丢。” “怎么了挺庞?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵晰赞,是天一觀的道長。 經常有香客問我选侨,道長宾肺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任侵俗,我火速辦了婚禮锨用,結果婚禮上,老公的妹妹穿的比我還像新娘隘谣。我一直安慰自己增拥,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布寻歧。 她就那樣靜靜地躺著掌栅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪码泛。 梳的紋絲不亂的頭發(fā)上猾封,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音噪珊,去河邊找鬼晌缘。 笑死,一個胖子當著我的面吹牛痢站,可吹牛的內容都是我干的磷箕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼阵难,長吁一口氣:“原來是場噩夢啊……” “哼岳枷!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤空繁,失蹤者是張志新(化名)和其女友劉穎殿衰,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體盛泡,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡闷祥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了饭于。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜀踏。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡维蒙,死狀恐怖掰吕,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情颅痊,我是刑警寧澤殖熟,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站斑响,受9級特大地震影響菱属,放射性物質發(fā)生泄漏。R本人自食惡果不足惜舰罚,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一纽门、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧营罢,春花似錦赏陵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至考传,卻和暖如春吃型,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背僚楞。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工勤晚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泉褐。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓运翼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親兴枯。 傳聞我的和親對象是個殘疾皇子血淌,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容