1. 程式人生 > >R語言資料視覺化教程(ggplot2)_座標軸設定

R語言資料視覺化教程(ggplot2)_座標軸設定

# 8.座標軸
# 8.1交換x軸和y軸
# 使用coord_flip()來翻轉座標軸
library(ggplot2)
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+coord_flip()
# 如果x變數是一個因子型變數,則排列順序可以通過使用scale_x_discrete()和引數limits=rev(levels(...))進行反轉
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+coord_flip()+scale_x_discrete(limits=rev(levels(PlantGrowth$group)))


# 8.2設定連續型座標軸的值域
# 可以使用xlim()和ylim()來設定一條連續型座標軸的最小值和最大值
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
# 顯示圖形
p
p +ylim(0,max(PlantGrowth$weight))
# 使用ylim()來設定範圍是通過scale_y_continuous()來設定範圍的簡便寫法(對於xlim()和scale_x_continuous()同理)
# 以下兩種表達方式等價:
ylim(0,10)
scale_y_continuous(limits = c(0,10))
# 有時需要設定scale_y_continuous()的其他屬性,在這些情況下同時使用ylim()和scale_y_continuous()可能會讓程式產生一些不可預知的行為,這是因為只有命令中的後一條會生效
# 示例如下,僅有第二條命令生效
p+ylim(0,10)+scale_y_continuous(breaks = c(0,5,10)) # 將刻度線放在0,5,10的位置
p+scale_y_continuous(breaks = c(0,5,10))+ylim(0,10)
# 要讓兩項修改均生效,捨棄ylim()並直接在scale_y_continuous()中同時設定limits和breaks即可
p+scale_y_continuous(limits = c(0,10),breaks = c(0,5,10))


# ggplot2中有兩種設定座標軸值域的方式,第一種方式是修改標度,第二種方式是應用一個座標變換。
# 當你修改x標度和y標度的範圍時,任何在範圍以外的資料都會被移除


# 通過使用座標變換,資料則不會被修剪;從本質上說,它只是將資料放大或縮小到指定的範圍
p+scale_y_continuous(limits = c(5,6.5)) # 與使用ylim()相同
p+coord_cartesian(ylim = c(5,6.5))
# 最後,通過使用expand_limits()來單向擴充套件值域也是可以的,但是不能使用它來縮減值域
p+expand_limits(y=0)


# 8.3 反轉一條連續型座標軸
# 使用scale_y_reverse或scale_x_reverse(),座標軸的方向也可以通過指定反序的範圍來反轉,先寫最大值,再寫最小值
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_reverse()
#通過指定反序的範圍產生類似的效果
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+ylim(6.5,3.5)


# 與scale_y_continuous()類似,scale_y_reverse()也無法與ylim配合工作
# 如果希望反轉某條座標軸併為它設定值域,則必須通過反序設定範圍的方式,在scale_y_reverse()語句內完成
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_reverse(limits=c(8,0))


# 8.4修改類別型座標軸上專案的順序
# 對於類別型(或者說離散型)座標軸來說,會有一個因子型變數對映到它上面,座標軸上專案的順序可以通過設定scale_x_discrete()或scale_y_discrete()中的引數limits來修改
# 要手動設定座標軸上專案的順序,將一個依理想順序排列的水平向量指定給limits即可。也可以使用這個向量來忽略某些專案
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p+scale_x_discrete(limits=c("trt1","ctrl","trt2"))


# 也可以使用以上方法展示專案的子集:
p+scale_x_discrete(limits=c("ctrl","trt1"))
# 要反轉專案順序,設定limits=rev(levels(...)),將因子型變數放在括號中即可。
p + scale_x_discrete(limits=rev(levels(PlantGrowth$group)))


# 8.5設定x軸和y軸的縮放比例
# 使用coord_fixed()
# 以下程式碼將得到x軸和y軸之間1:1的縮放效果
library(gcookbook)
sp <- ggplot(marathon,aes(x=Half,y=Full))+geom_point()
sp + coord_fixed()


# 通過在scale_y_continuous()和scale_x_continuous()中調整引數breaks,從而將刻度間距設為相同
sp + coord_fixed()+ scale_y_continuous(breaks = seq(0,420,30))+scale_x_continuous(breaks = seq(0,420,30))


# 如果希望為兩個座標軸之間指定其他的固定比例而非相同的比例,可以設定引數ratio。
sp + coord_fixed(ratio = 1/2) + scale_y_continuous(breaks = seq(0,420,30))+scale_x_continuous(breaks = seq(0,420,15))


# 8.6 設定刻度線的位置
# 通常來說ggplot()會自動將刻度線擺放在合適的位置,但如果希望改變他們的位置,設定標度中的引數breaks即可
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_y_continuous(breaks = c(4,4.25,4.5,5,6,8))


# 刻度線的位置決定了繪製主網格線的位置。如果該座標軸表示一個連續型變數,那麼顏色更暗且沒有標籤的次網格線將被預設繪製在每兩個主網格線的正中間位置。
# 使用seq()函式或運算子:來生成刻度線的位置向量
seq(4,7,by=.5)
5:10
# 如果座標軸是離散的而不是連續型的,則預設會為每個專案生成一條刻度線。
# 對於離散型座標軸,可以通過指定limits來修改專案的順序或移除專案。
# 設定breaks將會決定為哪些水平加上標籤,但不會移除它們或是改變他們的順序
# 為離散型座標軸同時設定breaks和limits
ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_x_discrete(limits=c("trt2","ctrl"),breaks="ctrl")


# 8.7 移除刻度線和標籤
# 使用theme(axis.text.y=element_blank()),也可對axis.text.x做相同處理,對於連續型和離散型座標軸均有效
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p + theme(axis.text.y = element_blank())


# 要移除刻度線,可使用theme(axis.ticks=element_blank()).這樣將會同時移除兩軸的刻度線
 p + theme(axis.ticks = element_blank(),axis.text.y = element_blank())
 
# 要移除刻度線、刻度標籤和網格線,將breaks設定為NULL即可
p +scale_y_continuous(breaks = NULL) 
# 這種方法僅對連續型座標軸有效
# 事實上,共有三種專案可以控制:刻度標籤,刻度線和網格線,對於連續型座標軸,ggplot()通常會在每個breaks值得位置放置刻度線、刻度標籤和主網格線。
# 對於類別型座標軸,這些元素則出現在每個limits值的位置。
# 我們可以獨立控制每條座標軸上的刻度標籤。但是,刻度線和網格線必須同時控制。
# 8.8 修改刻度標籤的文字
library(gcookbook)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
hwp
# 任意設定標籤,在標度中為breaks和labels賦值即可。
hwp + scale_y_continuous(breaks=c(50,56,60,66,72),labels = c("Tiny","Really\nshort","Short","Medium","Tallish"))


# 定義一個格式刷(formatter)函式,這樣的函式可以讀入數值並返回相應的字串
# 以下函式將英寸數值轉換為英尺加英寸的格式:
footinch_formatter <- function(x){
  foot <- floor(x/12)
  inch <- x%%12
  return(paste(foot,"'",inch,"\"",sep=""))
}
footinch_formatter(56:64)
# 使用引數labels將我們的函式傳遞給標度
hwp+scale_y_continuous(labels = footinch_formatter)
# 通過指定引數breaks讓ggplot()每隔四英寸設定一條刻度線取而代之
hwp + scale_y_continuous(breaks = seq(48,72,4),labels = footinch_formatter)


# 將時間測度轉換為HH:MM:SS(時:分:秒)或者其他類似的格式。
timeHMS_formatter <- function(x){
  h <- floor(x/60)
  m <- floor(x%%60)
  s <- round(60*(x%%1)) # 舍入到最接近的秒數
  lab <- sprintf("%02d:%02d:%02d",h,m,s) # 格式化字串為HH:MM:SS的格式
  lab <- gsub("^00:","",lab)  # 如果開頭存在00: 則移除
  lab <- gsub("^0","",lab)  # 如果開頭存在0 則移除
  return(lab)
}
timeHMS_formatter(c(.33,50,51.25,59.32,60,60.1,130.23))
# 隨ggplot2()安裝的scales包自帶了一些內建的格式化函式
# comma()在千、百萬、十億等位置向數字新增逗號
# dollar()新增一個美元符號並舍入到最接近的美分
# percent()乘以100,舍入到最接近的整數值,並新增一個百分號
# scientific()對大數字和小數字給出科學計數法表示。
# 要使用這些函式,必須首先使用library(scales)載入scales包


# 8.9 修改刻度標籤的外觀
bp <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()+scale_x_discrete(breaks=c("ctrl","trt1","trt2"),labels=c("Control","Treatment 1","Treatment 2"))
bp
# 將文字逆時針旋轉90°
bp+theme(axis.text.x = element_text(angle = 90,hjust = 1,vjust = .5))
# 將文字旋轉30°
bp+theme(axis.text.x = element_text(angle = 30,hjust = 1,vjust = 1))
# 引數hjust和vjust設定了橫向對齊(左對齊、居中、右對齊)和縱向對齊(頂部對齊/居中/底部對齊)


# 除了旋轉以外,其他的文字屬性,如大小、樣式(粗體/斜體/常規)和字型族(如Times和Helvetica)可以使用element_text()進行設定
bp +theme(axis.text.x = element_text(family = "Times",face = "italic",colour = "darkred",size = rel(0.9)))
# size(文字大小)被設為rel(0.9),意為當前主體基礎字型大小的0.9倍
# 這些命令僅僅控制了單個座標軸刻度標籤的外觀,並不影響其他座標軸、座標軸標籤、整體的標題或圖例
# 要控制所有這些元素的外觀,可以使用主題系統


# 8.10修改座標軸標籤的文字
# 使用xlab()或ylab()來修改座標軸標籤的文字
library(gcookbook)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn,colour=sex))+geom_point()
# 使用預設的座標軸標籤
hwp
# 設定座標軸標籤
hwp+xlab("Age in years")+ylab("Height in inches")
# 預設情況下,圖形將直接使用資料框中的列名作為座標軸標籤。
# 也可以使用labs()
hwp + labs(x="Age in years",y="Height in inches")
# 設定座標軸標籤的另一種方法是在標度中指定
hwp+scale_x_continuous(name = "Age in years")
# 這種方法同樣適用於其他的座標軸標度,如scale_y_continuous()、scale_x_discrete()等
# 還可以使用\n來新增換行
hwp +scale_x_continuous(name = "Age\n(Years)")


# 8.11移除座標軸標籤
# 對於x軸標籤,使用theme(axis.title.x=element_blank())。對於y軸標籤,針對axis.title.y處理
# 隱藏x軸標籤
p <- ggplot(PlantGrowth,aes(x=group,y=weight))+geom_boxplot()
p + theme(axis.title.x = element_blank())
# 移除座標軸標籤的另一種方法是將其設定為一個空字串。但如果以這種方式去做,那麼圖中將仍為文字留出空間
p + xlab("")
# 當使用theme()來設定axis.title.x=element_blank()時,x或y標度的名稱是不會改變的,只是這樣不會顯示文字而且不會為其留出空間。
# 當你設定標籤為“"時,標度的名稱就改變了,並且實際上顯示了(空白的)文字


# 8.12 修改座標軸標籤的外觀
# 要修改x軸標籤的外觀,使用axis.title.x即可
library(gcookbook)
library(ggplot2)
hwp <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
hwp + theme(axis.title.x = element_text(face = "italic",colour="darkred",size=14))


# 對於y軸標籤來說,有時不對文字進行旋轉會比較有用
# 標籤中的\n表示另起一行
hwp + ylab("Height\n(inches)")+theme(axis.title.y = element_text(angle = 0,face = "italic",size = 14))
# 呼叫element_text()時,預設的角度是0,如果設定了axis.title.y但沒有指定這個角度,它將以文字的頂部指向上方的朝向顯示。
# 如果修改了axis.title.y中的其他任何屬性並且希望它以正常朝向,即旋轉90°顯示,則必須手動指定這個角度
hwp + ylab("Height\n(inches)")+theme(axis.title.y = element_text(angle = 90,face="italic",colour = "darkred",size=14))
# 8.13沿座標軸顯示直線
# 使用主題設定中的axis.line
library(gcookbook)
p <- ggplot(heightweight,aes(x=ageYear,y=heightIn))+geom_point()
p + theme(axis.line = element_line(colour = "black"))


# 如果最初使用的主題在繪圖區域的周圍就有一條邊,則需要同時重置引數panel.border
p + theme_bw()+theme(panel.border = element_blank(),axis.line = element_line(colour = "black"))
# 如果邊界線比較粗,則它們的末端將僅會部分地重疊,要讓它們完全重疊,設定lineend="square"即可
# 對於較粗的線條,只有一半重疊
p + theme_bw()+theme(panel.border = element_blank(),axis.line = element_line(colour = "black",size = 4))
# 完全重疊
p + theme_bw()+ theme(panel.border = element_blank(),axis.line = element_line(colour = "black",size = 4,lineend = "square"))


# 8.14 使用對數座標軸
# 使用scale_x_log10()和/或scale_y_log10()
library(MASS)
# 基本圖形
p <- ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)
p
# 使用對數x標度和對數y標度
p + scale_x_log10()+scale_y_log10()
# 使用對數座標軸時,視覺上某段給定的距離表示著常數倍的比例改變
# 使用線性座標軸時,視覺上某段給定的距離表示著常數單位數量的改變


# 某些資料集在x軸上是呈指數分佈的,而另一些則是在y軸上呈指數分佈(或者兩軸皆是)
Animals
10^(0:3)
10^(-1:3)
p + scale_x_log10(breaks=10^(-1:5))+scale_y_log10(breaks=10^(0:3))


# 要讓刻度線標籤轉而使用指數計數法,只要使用scales包中的函式trans_format()即可
library(scales)
p + scale_x_log10(breaks=10^(-1:5),labels=trans_format("log10",math_format(10^.x)))+scale_y_log10(breaks=10^(0:3),labels=trans_format("log10",math_format(10^.x)))
# 使用對數座標軸的另一種方法是,在將資料對映到x和y卓彪之前,先對其進行變換
# 座標軸仍然是線性的——它表示對數變換後的數值
ggplot(Animals,aes(x=log10(body),y=log10(brain),label=rownames(Animals)))+geom_text()


library(scales)
# 對x使用自然對數變換,對y使用log2變換
p + scale_x_continuous(trans = log_trans(),breaks = trans_breaks("log",function(x) exp(x)),labels = trans_format("log",math_format(e^.x)))+scale_y_continuous(trans = log2_trans(),breaks = trans_breaks("log2",function(x) 2^x),labels = trans_format("log2",math_format(2^.x)))


# 預設的刻度線間距可能不夠好,可以在標度中使用引數breaks來設定它們
library(gcookbook)
ggplot(aapl,aes(x=date,y=adj_price))+geom_line()
ggplot(aapl,aes(x=date,y=adj_price))+geom_line()+scale_y_log10(breaks=c(2,10,50,250))
# 8.15 為對數座標軸新增刻度
# 使用annotation_logticks()
library(MASS)
library(scales)
library(ggplot2)
ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)+annotation_logticks()+scale_x_log10(breaks = trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))+scale_y_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))
# 使用annotation_logticks()建立的刻度線事實上是繪圖區域中的幾何物件
# 使用theme_bw()讓刻度線和網格線的顏色更協調一些
# 預設情況下,次網格線在視覺上出現在兩條主網格線的正中間,但這與對數標度下表示“5”的刻度線位置並不相同。
# 要讓兩者位置相同,可以手動設定標度的minor_breaks引數
ggplot(Animals,aes(x=body,y=brain,label=rownames(Animals)))+geom_text(size=3)+annotation_logticks()+scale_x_log10(breaks = trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)),minor_breaks=log10(5)+ -2:5)+scale_y_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)),minor_breaks=log10(5)+ -1:3)+coord_fixed()+theme_bw()
# 所謂5的位置,是指前一個長刻度線對應數值5倍的位置
# 8.16 繪製環狀圖形
# 使用coord_polar()
library(gcookbook)
wind
ggplot(wind,aes(x=DirCat,fill=SpeedCat))+geom_histogram(binwidth = 15,origin=-7.5)+coord_polar()+scale_x_continuous(limits = c(0,360))
# 使用極座標圖時要小心,因為這種圖形會扭曲對資料的感知
# 通過反轉圖例、使用不同的調色盤、新增外框線以及將分割點設定為某些更熟悉的值得方式,讓圖形稍微美觀一些
ggplot(wind,aes(x=DirCat,fill=SpeedCat))+geom_histogram(binwidth = 15,origin=-7.5,colour="black",size=.25)+guides(fill=guide_legend(reverse = TRUE))+coord_polar()+scale_x_continuous(limits = c(0,360),breaks = seq(0,360,by=45),minor_breaks = seq(0,360,by=15))+scale_fill_brewer()
# 使用引數start設定圖形起始的角度可能也是有用的,特別是當我們使用一個離散型變數對映為角度(theta)時。
# 起始角度的值以弧度計,如果知道要調整的角度,則必須將它轉換為弧度:
coord_polar(start = -45*pi/180)
# 預設情況下,對於對映到y(或者說r)的變數,最小值將被對映到中心;換句話說,資料中的最小值將被對映到視覺上半徑為0的位置。
# 如果希望一個為0的資料值被對映到半徑為0的位置,為了確保圖形能這樣繪製,需要設定對應的界限(limit)
# 在使用一個連續型的x(或者說theta)時,資料中的最小值和最大值是重合的。有時這樣是可取的,有時卻不是。要修改這種預設行為,需要設定對應的界限
# 極座標的theta值不能環繞一週
# 將mdeaths的時間序列資料放入一個數據框
md <- data.frame(deaths = as.numeric(mdeaths),month = as.numeric(cycle(mdeaths)))
# 計算每個月的平均死亡數量
library(plyr)
md <- ddply(md,"month",summarise,deaths=mean(deaths))
md
# 繪製基本圖形
p <- ggplot(md,aes(x=month,y=deaths))+geom_line()+scale_x_continuous(breaks = 1:12)
# 使用coord_polar
p + coord_polar()
# 通過設定y(或者說r)的界限為從0到資料中的最大值來解決這個問題
# 使用coord_polar並將y(r)的下屆設定為0
p+coord_polar()+ylim(0,max(md$deaths))
# 設定x的界限為0~12
p + coord_polar()+ylim(0,max(md$deaths))+xlim(0,12)
# 首尾不相接的問題。需要修改資料框,新增一個月份為0,對應值與12月相同的行
# 通過新增一個值與12的值相同的0來連線曲線
mdx <- md[md$month==12,]
mdx$month <- 0
mdnew <- rbind(mdx,md)


# 通過使用%+%,繪製與之前相同的圖形,只是使用的資料不同
p %+%mdnew+coord_polar()+ylim(0,max(md$deaths))
# 注意運算子%+%的使用,當你使用%+%向一個ggplot物件新增一個數據框時,它會替換ggplot物件中的預設資料框
# 8.17 在座標軸上使用日期
# 將一列類為Date的變數對映為x軸或y軸即可。
# 觀察資料結構
str(economics)
ggplot(economics,aes(x=date,y=psavert))+geom_line()
# ggplot2可以處理兩類時間相關的物件,日期物件(類為Date的物件)和日期時間物件(類為POSIXt的物件)。
# 兩類物件的區別是,Date物件表示的是日期,解析度為一天,而POSIXt物件則表示時刻,擁有精確到秒的小數部分的解析度
# 設定分割點與數值座標軸的方式類似——主要的不同在於設定所要使用的日期序列
# 如果未設定分割點,則將自動選擇
# 取economics的一個子集
econ <- subset(economics,date >= as.Date("1992-05-01") & date < as.Date("1993-06-01"))
# 基本圖形——不指定分割點
p <- ggplot(econ,aes(x=date,y=psavert))+geom_line()
p
# 分割點可使用函式seq()來建立,給定起始和終止日期和一個步長區間
# 指定一個日期向量為分割點
datebreaks <- seq(as.Date("1992-06-01"),as.Date("1993-06-01"),by="2 month")
# 使用分割點並旋轉文字標籤
p + scale_x_date(breaks = datebreaks)+theme(axis.text.x = element_text(angle = 10,hjust = 1))
# 可以通過使用scales包中的date_format()函式來指定分割點(標籤)的格式
library(scales)
p + scale_x_date(breaks = datebreaks,labels=date_format("%Y %b"))+theme(axis.text.x = element_text(angle = 30,hjust = 1))
# %Y:含世紀的年份(2012)
# %y:不含世紀的年份(12)
# %m:十進位制數表示月份(08)
# %b:當前區域設定(locale)的月份名縮寫(Aug)
# %B:當前區域設定的月份名全稱(August)
# %d:十進位制數表示的月份中的日期(04)
# %U:十進位制數表示的一年中的第幾周,星期日作為每週的第一天(00-53)
# %W:十進位制數表示的一年中的第幾周,星期一作為每週的第一天(00-53)
# %w:星期幾(0-6,星期日為0)
# %a:星期幾的縮寫名(Thu)
# %A:星期幾的全稱(Thursday)
# 以上選型中的一部分依賴於計算機的區域設定(locale)。月份和日期在不同的語言中會有不同的名稱
# 可以使用Sys.setlocale()來修改區域設定
# Windows
# Sys.setlocale("LC_TIME","italian")
# 8.18在座標軸上使用相對時間
# 時間值通常以數字的形式儲存。時間也能從某個起始時間經過的分鐘數或秒數來儲存。這些情況下,可以將一個值對映到x軸或y軸上,並使用一個格式刷來生成合適的座標軸標籤
# 轉換時間序列物件WWWusage為資料框
www <- data.frame(minute = as.numeric(time(WWWusage)),users=as.numeric(WWWusage))
# 定義一個格式刷函式——可將以分鐘表示的時間轉換為字串
timeHM_formatter <- function(X){
  h <- floor(x/60)
  m <- floor(x %% 60)
  lab <- sprintf("%d:%02d",h,m) #將字串格式化為HH:MM(時:分)的格式
  return(lab)
}
# 預設的x軸
ggplot(www,aes(x=minute,y=users))+geom_line()
# 使用格式化後的時間
ggplot(www,aes(x=minute,y=users))+geom_line()+scale_x_continuous(name="time",breaks = seq(0,100,by=10),labels = timeHM_formatter())
# 手動設定分割點和標籤
scale_x_continuous(breaks = c(0,20,40,60,80,100),labels = c("0:00","0:20","0:40","1:00","1:20","1:40"))
# 使用函式timeHM_formatter()來講數值時間(以分鐘表示)轉換為一個類似於“1:10”的字串
timeHM_formatter(c(0,50,51,59,60,130,604))
timeHMS_formatter(c(20,3000,3075,3559.2,3600,3606,7813.8))