R 數(shù)據(jù)可視化 —— ggpol

前言

ggpolggplot2 的一個(gè)擴(kuò)展包亿汞,添加了一些圖形。主要可以繪制 parliament diagrams(議會(huì)圖),也可以方便的繪制金字塔圖桐早,以及箱線圖和散點(diǎn)圖的混合等逊笆。

下面我們簡(jiǎn)要介紹一下如何使用 ggpol 繪制對(duì)應(yīng)的圖形栈戳。

使用

安裝導(dǎo)入,推薦安裝開(kāi)發(fā)版难裆,功能更全

# 從 bioconductor 安裝
BiocManager::install("ggpol")

# 從 CRAN 安裝
install.packages("ggpol")

# 安裝開(kāi)發(fā)版
if (!require(devtools)) {
    install.packages('devtools')
}
devtools::install_github('erocoar/ggpol')

library(ggpol)

1. 半圓弧形柱狀圖

使用 geom_arcbar 可以繪制只有 180 度子檀,也就是半圓的圓弧形條形圖镊掖。

其中 aes 函數(shù)中的 參數(shù):

  • shares:與扇形的大小成正比,
  • r0:指定圓弧的內(nèi)半徑褂痰,
  • r1:指定圓弧的外半徑

還有其他參數(shù) color亩进、filllinetype缩歪、alpha 用于指定顏色归薛、線型和透明度。

data <- tibble(
  months = factor(month.name, levels = month.name),
  sales = sample(30:90, 12),
  colors = RColorBrewer::brewer.pal(12, "Paired")
)

ggplot(data) +
  geom_arcbar(aes(shares = sales, r0 = 6, r1 = 10, fill = month.name), sep = 0.1) +
  scale_fill_manual(values = data$colors) +
  coord_fixed() +
  theme_void()

2. Parliament diagrams

geom_parliament 可以繪制 parliament diagrams匪蝙,該圖像類似于半圓形的弧形柱狀圖主籍。使用 seats 參數(shù)來(lái)設(shè)置,以點(diǎn)來(lái)表示每個(gè)分組的成員骗污。

data <- tibble(
  months = factor(month.name, levels = month.name),
  sales = sample(1:100, 12),
  colors = RColorBrewer::brewer.pal(12, "Paired")
)

ggplot(data) +
  geom_parliament(aes(seats = sales, fill = month.name)) +
  scale_fill_manual(values = data$colors, labels = month.name) +
  coord_fixed() +
  theme_void()

3. 條形圖文本注釋

使用 geom_bartext 為條形圖添加文本信息崇猫,可以避免文本之間的重疊。如果文本之間存在堆疊需忿,會(huì)在水平或豎直方向添加偏移來(lái)避免文本重疊诅炉。

目前在開(kāi)發(fā)版中的具有較好的展示,穩(wěn)定版可能在某些情況下交疊的文本無(wú)法分開(kāi)屋厘。

geom_bartext 接受與 geom_text 一樣的參數(shù)涕烧,還有一個(gè) dir 參數(shù),可選的值為 hv汗洒,分別表示在水平和豎直方向添加偏移议纯。

spacing 參數(shù)可以設(shè)置文本之間的最小間隔,單位為 NPC

df <- tibble(
  L = rep(LETTERS[1:2], each = 4),
  l = rep(letters[1:4], 2),
  val = c(96.5, 1, 2, 0.5, 48, 0.7, 0.3, 51)
)

p1 <- ggplot(df, aes(x = L, y = val, fill = l)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = scales::percent(val / 100)), position = position_stack(vjust = 0.5)) +
  ggtitle("GeomText")

p2 <- ggplot(df, aes(x = L, y = val, fill = l)) +
  geom_bar(stat = "identity") +
  geom_bartext(aes(label = scales::percent(val / 100)), position = position_stack(vjust = 0.5)) +
  ggtitle("GeomBartext")

p1 + p2

4. 圓形

geom_circle 可以繪制指定半徑的圓溢谤,而不是像 geom_point 函數(shù)中設(shè)置 size 參數(shù)瞻凤。

data.frame(x = sample(1:10, 6), y = sample(1:10, 6),
           r = sample(1:2, 6, replace = TRUE)) %>%
  ggplot() + geom_circle(aes(x = x, y = y, r = r, fill = gl(6, 1))) +
  coord_fixed()

5. 時(shí)序高亮

geom_tshighlight 可以用來(lái)高亮?xí)r間序列中的一個(gè)時(shí)段,是對(duì) geom_rect 的封裝世杀,

ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line() +
  geom_tshighlight(
    aes(xmin = as.Date("01/01/1990", format = "%d/%m/%Y"), 
        xmax = as.Date("01/01/2000", format = "%d/%m/%Y")),
    alpha = 0.005, fill = "blue"
  )

6. geom_boxjitter

geom_boxjitter 用于繪制混合的箱線圖:一半箱線圖和一半 jitter 散點(diǎn)圖阀参,以及可選的誤差線。

如果要設(shè)置點(diǎn)的填充色瞻坝, 則需要指定 jitter.shape21-25

df <- data.frame(
  score = rgamma(150, 4, 1), 
  gender = sample(c("M", "F"), 150, replace = TRUE), 
  genotype = factor(sample(1:3, 150, replace = TRUE))
)

ggplot(df) + 
  geom_boxjitter(aes(x = genotype, y = score, fill = gender),
                 jitter.shape = 21, jitter.color = NA, 
                 jitter.params = list(height = 0, width = 0.04),
                 outlier.color = NA, errorbar.draw = TRUE) +
  scale_fill_manual(values = c("#fb8072", "#80b1d3")) +
  theme_minimal()

如果我們關(guān)注離群點(diǎn)蛛壳,想對(duì)這些點(diǎn)進(jìn)行高亮,可以設(shè)置 outlier.intersect = TRUE所刀,并用 outlier.shapeoutlier.size 來(lái)設(shè)置點(diǎn)的形狀和大小

ggplot(df) + 
  geom_boxjitter(aes(x = genotype, y = score, fill = gender),
                 jitter.shape = 21, jitter.color = NA, 
                 jitter.params = list(height = 0, width = 0.04),
                 outlier.color = "black", errorbar.draw = TRUE,
                 outlier.intersect = TRUE, outlier.shape = 24,
                 outlier.size = 1.5) +
  scale_fill_manual(values = c("#fb8072", "#80b1d3")) +
  theme_minimal()

如果將 boxplot.expand 參數(shù)設(shè)置為 TRUE衙荐,則會(huì)隱藏 jitter 點(diǎn)圖,其功能就類似于 geom_boxplot 繪制完整的箱線圖浮创,但添加了誤差線

ggplot(df) + 
  geom_boxjitter(aes(x = genotype, y = score, fill = gender),
                 errorbar.draw = TRUE, boxplot.expand = TRUE,
                 errorbar.length = 0.4, varwidth = TRUE) +
  scale_fill_manual(values = c("#fb8072", "#80b1d3")) +
  theme_minimal()

7. 混淆矩陣

geom_confmat 可以用于繪制混淆矩陣忧吟,本質(zhì)上就是一個(gè)熱圖。

x <- sample(LETTERS[seq(4)], 50, replace = TRUE)
y <- sample(LETTERS[seq(4)], 50, replace = TRUE)

ggplot() + 
  geom_confmat(aes(x = x, y = y), normalize = TRUE, text.perc = TRUE)

8. 軸共享分面

facet_share 用于生成具有共享軸標(biāo)簽的分面圖斩披,由于該函數(shù)只是實(shí)驗(yàn)性的溜族,目前只支持兩個(gè)分面共享同一個(gè)軸胸嘴。

如果想要將軸以鏡像的方式放置,需要將其中一個(gè)分面乘上 -1斩祭,如果想要水平方式,則將放置在左邊的分面乘上 -1乡话,如果是豎直放置摧玫,則將下面的分面乘上 -1。但是這樣會(huì)改變軸標(biāo)簽绑青,需要設(shè)置 reverse_num = TRUE

可以用來(lái)展示對(duì)稱的人口金字塔圖

df <- data.frame(sex = sample(c("M", "F"), 1000, replace = TRUE),
                 age = rnorm(1000, 45, 12))

df$age_bins <- cut(df$age, 15)
df$count <- 1
df <- aggregate(count ~ sex + age_bins, data = df, length)


df_h <- df
df_h$count <- ifelse(df_h$sex == "F", df_h$count * -1, df_h$count)

ggplot(df_h, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "h", scales = "free", reverse_num = TRUE) + 
  coord_flip() +
  scale_fill_manual(values = c("#fb8072", "#80b1d3"))

如果想要豎直放置诬像,需要對(duì)第二個(gè)因子乘以 -1

df_v <- df
df_v$count <- ifelse(df_v$sex == levels(factor(df_v$sex))[2], df_v$count * -1, df_v$count)

ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE)

但是運(yùn)行上面的代碼,我得到了一行報(bào)錯(cuò)信息

 Error in unit(c(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]],  : 
  'list' object cannot be coerced to type 'double' 

是類型轉(zhuǎn)換出現(xiàn)了問(wèn)題闸婴。通過(guò)下載閱讀源碼進(jìn)行試調(diào)坏挠,找到報(bào)錯(cuò)的代碼所在文件(facet_share.R),在代碼前添加一行打印命令

print(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]])
shared_axis <- gtable::gtable_matrix(
          "shared.ax.x", shared_axis,
          widths = unit(1, "npc"),
          heights = unit(c(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]], 1,
                           axes$x$bottom[[1]]$children$axis$heights[[tick_idx]]),
                         c("pt", "grobwidth", "pt"),
                         list(NULL, axes$x$bottom[[1]]$children$axis$grobs[[lab_idx]], NULL)),
          clip = "off")

同時(shí)邪乍,重新加載函數(shù)降狠,還要收到導(dǎo)入用到的包

library(grid)
library(rlang)

source("Downloads/facet_share.R")
ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE)

打印出了

2.75points 

是一個(gè) unit 對(duì)象,也就是坐標(biāo)系統(tǒng)的度量單位庇楞。通過(guò)查閱 unit 函數(shù)榜配,發(fā)現(xiàn)函數(shù)的第一個(gè)參數(shù)需要傳入一個(gè)數(shù)值向量,也就是說(shuō)

c(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]], 1,
                           axes$x$bottom[[1]]$children$axis$heights[[tick_idx]])

必須是一個(gè)數(shù)值向量吕晌,我們?cè)俅蛴】纯?/p>

source("Downloads/facet_share.R")
ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE)

輸出了一個(gè)嵌套的 list

[[1]]
[[1]][[1]]
[1] 2.75

[[1]][[2]]
NULL

[[1]][[3]]
[1] 8


[[2]]
[1] 1

[[3]]
[[3]][[1]]
[1] 2.75

[[3]][[2]]
NULL

[[3]][[3]]
[1] 8

問(wèn)題就在這里蛋褥,數(shù)值 1 肯定不會(huì)錯(cuò),錯(cuò)的應(yīng)該是另外兩個(gè) unit 對(duì)象睛驳,可以嘗試將這兩個(gè)對(duì)象轉(zhuǎn)換為數(shù)值型烙心。將 heights 的值改為

heights = unit(c(as.numeric(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]]), 1,
                           as.numeric(axes$x$bottom[[1]]$children$axis$heights[[tick_idx]])),
                         c("pt", "grobwidth", "pt"),
                         list(NULL, axes$x$bottom[[1]]$children$axis$grobs[[lab_idx]], NULL))

再運(yùn)行代碼,就得到了我們想要的圖形了乏沸。

source("Downloads/facet_share.R")
ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE)

標(biāo)簽都擠到一塊了淫茵,將其旋轉(zhuǎn) 90 度,刻度線也不要了

ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE) +
  theme(axis.text = element_text(angle = 90, size = 6), axis.ticks.length.x = unit(0, "cm"))

但是下面的空白有點(diǎn)大屎蜓,再設(shè)置一下痘昌。只需先獲取 ggplot 對(duì)象,然后設(shè)置對(duì)象的高度就行

p <- ggplot(df_v, aes(x = age_bins, y = count, fill = sex)) + 
  geom_bar(stat = "identity") +
  facet_share(~sex, dir = "v", scales = "free", reverse_num = TRUE) +
  theme(axis.text = element_text(angle = 90, size = 6), axis.ticks.length.x = unit(0, "cm"))

gp <- ggplotGrob(p)
gp$heights[15] <- unit(0, 'cm')

grid.newpage()
grid.draw(gp)

嗯炬转,這樣就好多了辆苔。

你可能要問(wèn),為什么我能知道要設(shè)置 15 個(gè)扼劈,哈哈哈驻啤,我也是通過(guò)觀察和不斷的嘗試。先打印圖形對(duì)象的高度屬性荐吵,發(fā)現(xiàn)是一個(gè)數(shù)值向量

> gp$heights
 [1] 5.5points                          0cm                                0cm                               
 [4] 0cm                                0cm                                0cm                               
 [7] 0.59683986336016cm                 1null                              sum(0.456897744568977cm, 11points)
[10] 0cm                                5.5points                          0cm                               
[13] 0.59683986336016cm                 1null                              1.08935240677321cm                
[16] 1grobheight                        0cm                                0points                           
[19] 5.5points 

看到第 15 個(gè)值是最大的骑冗,與圖形下面間距最大相符赊瞬,所以蠻設(shè)置看下。然后就行了贼涩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巧涧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子遥倦,更是在濱河造成了極大的恐慌谤绳,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袒哥,死亡現(xiàn)場(chǎng)離奇詭異缩筛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)堡称,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)瞎抛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人却紧,你說(shuō)我怎么就攤上這事桐臊。” “怎么了啄寡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵豪硅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我挺物,道長(zhǎng)懒浮,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任识藤,我火速辦了婚禮砚著,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痴昧。我一直安慰自己稽穆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布赶撰。 她就那樣靜靜地躺著舌镶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豪娜。 梳的紋絲不亂的頭發(fā)上餐胀,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音瘤载,去河邊找鬼否灾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸣奔,可吹牛的內(nèi)容都是我干的墨技。 我是一名探鬼主播惩阶,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扣汪!你這毒婦竟也來(lái)了断楷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤崭别,失蹤者是張志新(化名)和其女友劉穎脐嫂,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體紊遵,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年侥蒙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暗膜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鞭衩,死狀恐怖学搜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情论衍,我是刑警寧澤瑞佩,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站坯台,受9級(jí)特大地震影響炬丸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜒蕾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一稠炬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咪啡,春花似錦首启、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至准夷,卻和暖如春钥飞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冕象。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工代承, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渐扮。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓论悴,卻偏偏與公主長(zhǎng)得像掖棉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膀估,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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