chartcontrol饼状图属性设置_温故而知新,ggplot2 饼图的几点笔记
其實 ggplot2 并沒有類似于 geom_pie() 這樣的函數實現餅圖的繪制,它是由 ?geom_bar() 柱狀圖經過 ?coord_polar() 極坐標彎曲從而得到的。
對于為什么 ggplot2 中沒有專門用于餅圖繪制的函,有人說:“柱狀圖的高度,對應于餅圖的弧度,餅圖并不推薦,因為人類的眼睛比較弧度的能力比不上比較高度(柱狀圖)?!?關于餅狀圖被批評為可視化效果差,不推薦在 R 社區中使用的文章在網絡也有不少,感興趣的可以去搜一下。
極坐標系
極坐標應該是高中數學的知識,對我而言,基本都已經忘光了,結合網上的一些資料重溫一下。
極坐標是指在平面內取一個定點 O,叫極點,引一條射線 Ox,叫做極軸,再選定一個長度單位和角度的正方向(通常取逆時針方向)。對于平面內任何一點 M,用 ?ρ 表示線段 OM 的長度(有時也用 r 表示),θ 表示從 Ox 到 OM 的角度,ρ 叫做點 M 的極徑,θ 叫做點 M 的極角,有序數對 (ρ, θ) 就叫點 M 的極坐標,這樣建立的坐標系叫做極坐標系。通常情況下,M 的極徑坐標單位為 1(長度單位),極角坐標單位為 rad(或 °)。
極坐標系中一個重要的特性是,平面直角坐標中的任意一點,可以在極坐標系中有無限種表達形式。通常來說,點(r, θ)可以任意表示為(r, θ ± n×360°)或 (?r, θ ± (2n + 1)180°),這里 n 是任意整數。如果某一點的 r 坐標為 0,那么無論 θ 取何值,該點的位置都落在了極點上。笛卡爾坐標和極坐標之間的轉換,請參考數學樂網站的《極坐標與笛卡爾坐標》一文,非常詳細直觀。
coord_polar
coord_polar() 是 ggplot2 中的極坐標函數,它可以彎曲橫縱坐標,使用這個函數做出蜘蛛圖或餅圖的效果。我在網絡上查了一下,比較少看到關于 coord_polar() 原理的介紹,只是在 ggplot2 的 Tidyverse 上發現了幾個例子。
library(ggpubr)library(ggplot2)
df?"A",?"B",?"C"),?value?=?c(10,?50,?30))
p?"identity",?width=1,?colour="black")
g?"",?y=value,?fill=name))?+?geom_bar(stat="identity",?width=1,?colour="black")
用法
coord_polar() 主要有四個參數:theta, start, direction 和 clip 。
coord_polar(theta?=?"x",?start?=?0,?direction?=?1,?clip?=?"on")theta:variable to map angle to ( x or y ).
start:offset of starting point from 12 o'clock in radians.
direction:1, clockwise; -1, anticlockwise.
clip:Should drawing be clipped to the extent of the plot panel? A setting of "on" (the default) means yes, and a setting of "off" means no.
小知識:角度制 vs 弧度制
1度=π/180≈0.01745弧度,1弧度=180/π≈57.3度。
角的度量單位通常有兩種,一種是角度制,另一種就是弧度制。角度制,就是用角的大小來度量角的大小的方法。在角度制中,我們把周角的 1/360 看作 1 度,那么,半周就是 180 度,一周就是 360 度。由于 1 度的大小不因為圓的大小而改變,所以角度大小是一個與圓的半徑無關的量。
弧度制,顧名思義,就是用弧的長度來度量角的大小的方法。單位弧度定義為圓周上長度等于半徑的圓弧與圓心構成的角。由于圓弧長短與圓半徑之比,不因為圓的大小而改變,所以弧度數也是一個與圓的半徑無關的量。角度以弧度給出時,通常不寫弧度單位,有時記為 rad 或 R。
參數示例
結合一些示例,理解一下 coord_polar() 的幾個參數。
theta="x"
x 軸極化,x 軸刻度值對應扇形弧度,y 軸刻度值對應圓環半徑。p 中由于 x 是等長的,所以 p1 每一個弧度為 60 度;p2 的每一個弧度為 360 度。
p1?"x")?+?labs(title="theta=\"x\"")g1?"x")?+?labs(title="theta=\"x\"")
ggarrange(p,?g,?p1,?g1,?ncol=2,?nrow=2,?labels=c("p",?"g",?"p1",?"g1"))
theta="y"
y 軸極化,y 軸刻度值對應扇形弧度,x 軸長度對應扇形半徑。對于并列柱狀圖 p,以最大的 y 值作為 360 度的弧度,剩下的按比例類推,由于 p 中 A、B、C 是等長的,所以在 p1 中它們的半徑是 1:2:3。對于堆疊柱狀圖 g,把 y 值按照比例劃分弧度,因此它們的弧度比等于各自的 y 值比例。
p2?"y")?+?labs(title="theta=\"y\"")g2?"y")?+?labs(title="theta=\"y\"")
ggarrange(p,?g,?p2,?g2,?ncol=2,?nrow=2,?labels=c("p",?"g",?"p2",?"g2"))
start=pi/6, direction=1
起始位置為距離 12 點針方向 30 度,順時針排列。
p3?"y",?start=pi/6,?direction=1)?+?labs(title="theta=\"x\",start=pi/6,direction=1")g3?"y",?start=pi/6,?direction=1)?+?labs(title="theta=\"x\",start=pi/6,direction=1")
ggarrange(p,?g,?p3,?g3,?ncol=2,?nrow=2,?labels=c("p",?"g",?"p3",?"g3"))
start=pi/6, direction=-1
起始位置為距離 12 點針方向 30 度,逆時針排序。
p4?"y",?start=pi/6,?direction=-1)?+?labs(title="theta=\"y\",start=pi/6,direction=-1")g4?"y",?start=pi/6,?direction=-1)?+?labs(title="theta=\"y\",start=pi/6,direction=-1")
ggarrange(p,?g,?p4,?g4,?ncol=2,?nrow=2,?labels=c("p",?"g",?"p4",?"g4"))
start=-pi/6, direction=1
起始位置為距離 12 點針方向負 30 度,順時針排序。
p5?"y",?start=-pi/6,?direction=1)?+?labs(title="theta=\"y\",start=-pi/6,direction=1")g5?"y",?start=-pi/6,?direction=1)?+?labs(title="theta=\"y\",start=-pi/6,direction=1")
ggarrange(p,?g,?p5,?g5,?ncol=2,?nrow=2,?labels=c("p",?"g",?"p5",?"g5"))
Github 上有關于 coord-pola.r 的源碼,整個代碼只有 300 多行,有興趣的同學可以去研究一下,上面的理解如有不對的地方還請幫忙指正。
餅圖中添加文字的位置控制 - 借助公式
繪制餅圖的過程中,利用 ggplot2 的 geom_bar 結合 coord_polar 實現。
#?Load?ggplot2library(ggplot2)
#?Create?Data
data?1:5],?value=c(13,7,9,21,2))
#?Basic?piechart
ggplot(data,?aes(x="",?y=value,?fill=group))?+
??geom_bar(stat="identity",?width=1)?+
??coord_polar("y",?start=0)
需要理解的點是餅圖的排布是按照 aes(fill) 的因子順序確定的。譬如數據如下:>?dat?1:5],?Num=c(90,?34,?56,?99,?15))
>?dat
??type?Num
1????A??90
2????B??34
3????C??56
4????D??99
5????E??15
必須根據數據先確定 mapping 中 aes(fill) 的因子順序,譬如這里會按照 dat$type 填充,這種非有序因子會基于字母順序來默認其填充順序。
為了確定數據填充的先后,同時方便在不同區域上填寫上對應數據的大小,所以會先去創建有序因子,從而使數據列 dat$Num 的自然順序和因子的順序在一定程度上一致(一致的同向對應或反向對應)。譬如如下使方向一致:
dat$type?T)dat$type
有序因子的結果則如下,和 dat$Num 的順序能夠一致上,不會出現對應錯亂問題。[1]?A?B?C?D?E
Levels:?A?畫圖:p_pie?"",?y=dat[,2],?fill=dat[,1]))+
??geom_bar(stat="identity",?width=1)+
??coord_polar(theta="y",?direction=1)+
??scale_fill_brewer(palette?="Set3",?direction?=?1)+
??labs(x="",?y="",?fill="Type")+
??ggtitle(label?="test",?subtitle=NULL)
p_pie
結合下圖結果可以看出坐標軸方向使順時針,而顏色設置 scale_fill_brewer(palette ="Set3",direction = 1) 設定了第一個顏色填充到第一個因子對應的 “A” 上,這樣就反映出在圖片實際分布中數據和因子是反向對應的。雖然在 dat 數據框中設置是順序一致方向相同的對應,但圖片分布中會改變。
小知識:scale_fill_brewer
scale_fill_brewer 是一個 ggplot2 和 RColorBrewer 關聯的一個擴展調色板,其他可用于 scale_fill_brewer 調色板的顏色包括:
Qualitative?????Accent,?Dark2,?Paired,?Pastel1,?Pastel2,?Set1,?Set2,?Set3
Sequential???????Blues,?BuGn,?BuPu,?GnBu,?Greens,?Greys,?Oranges,?OrRd,?PuBu,?
????????????????????????PuBuGn,?PuRd,?Purples,?RdPu,?Reds,?YlGn,?YlGnBu,?YlOrBr,?YlOrRd
參考:https://ggplot2.tidyverse.org/reference/scale_brewer.html
結合圖片中反向對應的關系,在 A 區塊上中間位置填充上對應的文字 "Num:90",它的坐標因該是 sum(dat$Num)-90 +90/2 ;如果是 B 區塊對應的應該坐標為 sum(dat$Num)-90-34 +34/2 ,歸納為:
sum(dat\$Num)-cumsum(dat$Num)+dat$Num/2,即:>?sum(dat$Num)-cumsum(dat$Num)+dat$Num/2[1]?249.0?187.0?142.0??64.5???7.5
小知識:R 語言 cumsum 函數cumsum 是 R 語言 base 包 cum 系列的一個函數,它的功能是計算向量的累積和并返回。
cum 系列還有另外三個函數:cumprod, cummin, cummax ,它們的作用分別是計算向量的累積的乘積、極小值、極大值,并返回。
#?對數值型向量求和>?cumsum(1:10)????
[1]??1??3??6?10?15?21?28?36?45?55
#?對數值型矩陣求和,結果返回仍是向量
>?cumsum(matrix(1:12,?nrow?=?3))??
[1]??1??3??6?10?15?21?28?36?45?55?66?78
#?對數據框求和,返回結果仍然是數據框,cumsum?會對對每個變量進行求和處理
>?cumsum(data.frame(a?=?1:10,?b?=?21:30))??
???a???b
1???1??21
2???3??43
3???6??66
4??10??90
5??15?115
6??21?141
7??28?168
8??36?196
9??45?225
10?55?255
結合 geom_text(aes(x,y)) 的位置設置,保證中間文字填寫不會出錯:
p_pie=p_pie+??geom_text(aes(x=1.2,y=sum(dat$Num)-cumsum(dat$Num)+dat$Num/2?,label=as.character(dat[,2])),size=3)
p_pie
如果最初構建有序因子的方向和實際數據的方向反向對應呢?dat$type=factor(dat$type,levels?=?rev(dat$type),order=T)
dat$type
p_pie=ggplot(dat,aes(x="",y=dat[,2],fill=dat[,1]))+
??geom_bar(stat="identity",width=1)+
??coord_polar(theta="y",direction=1)+
??scale_fill_brewer(palette?="Set3",direction?=?1)+
??labs(x="",y="",fill="Type")+
??ggtitle(label?="test",subtitle=NULL)
p_pie結合圖片可以知道,第一個因子 "E" 對應了第一個顏色,不過從圖片顯示坐標中可以看到,"A" 在前,而 "A" 在原始數據 dat$Num 中對應的數據也在前 90,這樣計算位置就會發生改變了,這時候 "A" 文字應該對應 90-90/2,文字 "B" 將對應 90+34-34/2,…,歸納為 cumsum(dat$Num)-dat$Num/2 。>?cumsum(dat$Num)-dat$Num/2
[1]??45.0?107.0?152.0?229.5?286.5
而且圖例也是反向的,需要結合 guides(fill=guide_legend(reverse=T)) ,并且希望第一個顏色對應最后一個因子 "A", scale_fill_brewer(palette ="Set3",direction = -1) :
dat$type
p_pie=ggplot(dat,aes(x="",y=dat[,2],fill=dat[,1]))+
??geom_bar(stat="identity",width=1)+
??coord_polar(theta="y",direction=1)+
??scale_fill_brewer(palette?="Set3",direction?=?-1)+
??labs(x="",y="",fill="Type")+
??ggtitle(label?="test",subtitle=NULL)+
??guides(fill=guide_legend(reverse?=?T))+
??geom_text(aes(x=1.2,y=cumsum(dat$Num)-dat$Num/2?,label=as.character(dat[,2])),size=3)
p_pie
總結可知:ggplot2 在畫餅圖的過程中設定填充的因子方向總和圖片坐標中的方向相反,不過因子的順序和數據 dat$Num 的對應關系是正向對應或者反向對應,會影響相關區塊的中心位置值計算的方式,從而影響 geom_text 中文字定位。
餅圖中添加文字的位置控制(借助公式)部分的內容主要參考了 Daitoue 在 OmicsClass 的一篇文章(詳見參考資料),OmicsClass 上還給出了不借助公式在餅圖中添加文字的位置控制,感興趣的同學也已點擊文章左下角 "閱讀原文" 進行閱讀。
sessionInfo 信息
本次學習 R 和相關包版本信息。
>?sessionInfo()R?version?3.6.2?(2019-12-12)
Platform:?x86_64-conda_cos6-linux-gnu?(64-bit)
Running?under:?CentOS?Linux?7?(Core)
Matrix?products:?default
BLAS/LAPACK:?/usr/local/software/miniconda3/lib/libopenblasp-r0.3.8.so
locale:
?[1]?LC_CTYPE=en_US.UTF-8???????LC_NUMERIC=C
?[3]?LC_TIME=en_US.UTF-8????????LC_COLLATE=en_US.UTF-8
?[5]?LC_MONETARY=en_US.UTF-8????LC_MESSAGES=en_US.UTF-8
?[7]?LC_PAPER=en_US.UTF-8???????LC_NAME=C
?[9]?LC_ADDRESS=C???????????????LC_TELEPHONE=C
[11]?LC_MEASUREMENT=en_US.UTF-8?LC_IDENTIFICATION=C
attached?base?packages:
[1]?stats?????graphics??grDevices?utils?????datasets??methods???base
other?attached?packages:
[1]?ggplot2_3.2.1
loaded?via?a?namespace?(and?not?attached):
?[1]?Rcpp_1.0.3?????????viridisLite_0.3.0??digest_0.6.25??????withr_2.1.2
?[5]?crayon_1.3.4???????dplyr_0.8.3????????assertthat_0.2.1???grid_3.6.2
?[9]?R6_2.4.0???????????gtable_0.3.0???????magrittr_1.5???????scales_1.0.0
[13]?pillar_1.4.3???????rlang_0.4.5????????lazyeval_0.2.2?????labeling_0.3
[17]?RColorBrewer_1.1-2?glue_1.3.1?????????purrr_0.3.2????????munsell_0.5.0
[21]?compiler_3.6.2?????pkgconfig_2.0.3????colorspace_1.4-1???tidyselect_0.2.5
[25]?tibble_2.1.3
>
FAQ:如何實現 R 語言餅圖標簽的 overlap 問題?
文章的最后,提個問題:有沒有通用的 R 包或者函數,可以得到下面效果的餅圖?
參考資料
Daitoue,《餅圖 pie - ggplot2》,OmicsClass
Daitoue,《餅圖中添加文字的位置控制-ggplot2(非公式)》,OmicsClass
特別聲明:文章中關于"餅圖中添加文字的位置控制(借助公式與非公式)" 部分內容,主要參考了 Daitoue 在 OmicsClass 的兩篇文章(詳見參考資料),在這里特別感謝一下。參考的文章主要用于學習交流目的,如有任何侵權,請第一時間與我聯系。
戳原文,更有料!總結
以上是生活随笔為你收集整理的chartcontrol饼状图属性设置_温故而知新,ggplot2 饼图的几点笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: electron 样式不加载_elect
- 下一篇: layui上传报错会有哪些原因_数据丢失