2018年5月10日 星期四

R 的視覺化之二:3D入門



R的立體3D繪圖,可分為靜態,互動與動態三種。這篇文章介紹靜態的兩種型態,互動式和動態另文介紹。
3D繪圖在財經數據上相當重要,尤其是期間結構商品,如果在接上時間序列,就會更繁複。我們先從簡單的開始。主要用兩個套件:scatterplot3d和plot3D。plot3D有更多可以表現的風格。資料還是用 reshape 套件內建的 tips

I. 使用 scatterplot3d
library(scatterplot3d)
tips=reshape::tips
names(tips)                                     
used=tips[,c("total_bill","size","tip")]

Case 1. 基本3D繪圖
scatterplot3d(used,main="3D Scatter Plot", xlab="Total bill",ylab="table size",zlab="Tip",pch=16, color="steelblue")

Case 2. 分組
   我們依照小費高低,用cut函數分成三群:L=Low tip, M=Medium tip, H=High tip。如下
group=cut(tips$tip,3,labels =c("L","M","H"))
   再給定形狀,就是pch使用的編號
myshapes=c(16,17,18)
   再把編號對應到樣本
myshapes=myshapes[as.numeric(group)] 
   給定三群對應顏色
mycols=c("green","blue", "red")
   再把三個色對應到樣本
mycols=mycols[as.numeric(group)]
scatterplot3d(used,main="3D Scatter Plot", xlab="Total bill",ylab="table size",zlab="Tip",pch=myshapes, color=mycols,box=FALSE,grid=TRUE)


Case 3. 添加 legends
須要上添加物時,必須先把圖物件存起來,下例為my3d
plot.new()
my3d=scatterplot3d(used,main="3D Scatter Plot", xlab="Total bill",ylab="table size",zlab="Tip",pch= 16, color=mycols)
第1個方法是指定座標,使用 xyx.convert()
legend(my3d$xyz.convert(50,5,4),legend=levels(group),col=c("green","blue", "red"),pch=16)
第2個方法是用文字 "bottom","center","right"等等。bty="n" 可取消 legend 框框。
legend("bottomright",legend=levels(group),col=c("green","blue", "red"),pch=16, bty="n")

第3個方法使用 inset指定 legend 和 origin 的距離。下圖同時也指定legend文字水平呈現。
legend("bottom",legend=levels(group),col=c("green","blue", "red"),pch=16:18,inset=-0.15, xpd=TRUE, horiz=TRUE, bty="n")

Case 4. 在不同面添加格線
這功能須要一個小工具graph3D,由git上裝置
devtools::install_github("kassambara/graph3d")
library(graph3d)
plot.new()
s3d=scatterplot3d(used,main="3D Scatter Plot", xlab="Total bill",ylab="table size",zlab="Tip",pch= "", box=FALSE,grid=FALSE)
   指定添加格線平面
s3d_addgrids(used, grid=c("xy","xz","yz"))
s3d$points3d(used,pch=myshapes, col=mycols)
繪圖如下:

上例中的繪圖,風格較少,同時顯示的角度調整不容易(基本上是不能調),plot3D則具備更多的功能。

II. 使用plot3D


library(plot3D)
宣告座標資料。
x=used$total_bill
y=used$size
z=used$tip

Case 1. 標準繪圖,如不需顯示右邊的色棒,colkey=FALSE就可以。
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill", ylab="table size", zlab="Tip", pch=18, clab=c("Tip, US$"), colkey=TRUE)


Case 2. 分組上色
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill",ylab="table size", zlab="Tip", pch=18, col.var=as.integer(group), col=c("#E69F00","#56B4E9", "#B2182B"), clab=c("Tip, US$"))

Case 3. 背景形式 bty="b2"
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill", ylab="table size", zlab="Tip", bty="b2", colkey=FALSE)
Case 4. 背景形式 bty="g" 是 ggplot2 的風格。
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill",ylab="table size", zlab="Tip", bty="g", cex=1.5, colkey=FALSE)
Case 5. 檢視角度,之前的圖,都是俯視,如果要平行檢視,則 phi=0。如下
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill",ylab="table size", zlab="Tip", bty="g", clab=c("Tip, US$"), pch=20, cex=2, phi=0)
Case 6.  在座標刻度做明確顯示,ticktype="detailed",這個圖也是這筆資料最佳的檢視圖。
scatter3D(x,y,z,main="3D Scatter Plot", xlab="Total bill",ylab="table size", zlab="Tip", bty="g", clab=c("Tip, US$"), pch=20,cex=2,phi=0, ticktype="detailed")


這個圖的分群方式,如果依照 time/day/sex 劃分的話,會呈現出更多的色聚型態,資料科學往往須要檢視型態。這技術就很有用。

資料最佳檢視角度個個不同,所以,互動式圖形就可以利用滑鼠來調整角度,更為簡便。下次的文就來介紹互動式繪圖套件。


2018年5月3日 星期四

R 的視覺化之一:風格美學篇

ggplot2 應該是R社群內最受歡迎的繪圖套件之一。繪圖除了結構清楚,ggplot2 還有就是有很多的風格模版,例如,華爾街日報,經濟學人等等。本文介紹如何使用主題套件ggthemes和其他package套入入風格,程式碼內風格指令反藍,圖形的資料結構反紅,其餘是內建的設定選項。範例資料檔是 tips.csv,這是200筆紀錄小費金額的數據,餐廳發現每張帳單的小費,差距頗大。因此想知道,有哪些因素影響了小費額度。資料如圖


tip =小費金額,美金
total_bill =帳單金額, 美金
sex = 結帳者性別
smoker=結帳者是否吸煙
day=用餐日
time=用餐時段
                         size=帳單顧客人頭數(table size)

require("ggplot2")
tips<-read.csv("tips.csv")
.df <- data.frame(y = tips$tip, x = tips$day, z = tips$sex)

第1個圖是ggplot2內建的盒鬚圖。
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) +  geom_boxplot(position = position_dodge(width = 0.9)) + 
  xlab("day") + ylab("tip") +  labs(fill = "sex") +
  theme_bw(base_size = 14, base_family = "sans")
print(.plot)
ggplot2 內建風格

第2個圖是經濟學人
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) +  geom_boxplot(position = position_dodge(width = 0.9)) + 
  xlab("day") + ylab("tip") +  labs(fill = "sex")
  ggthemes::theme_economist(base_size = 14, base_family = "sans")
print(.plot)


經濟學人風格


第3個圖是華爾街日報風格,必須由第三方套件 RcmdrPlugin.KMggplot2 呼叫
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) +  geom_boxplot(position = position_dodge(width = 0.9)) + 
  xlab("day") + ylab("tip") +  labs(fill = "sex") +
  RcmdrPlugin.KMggplot2::theme_wsj2(base_size = 14, base_family = "sans")
print(.plot)
華爾街日報風格


第4個圖是著名的Few風格,是視覺化大師 Stephen Few的設計風格,Few著有Show me the numbers-- Designing Tables and Graphs to Enlighten一書,超級一流。
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) +  geom_boxplot(position = position_dodge(width = 0.9)) + 
  xlab("day") + ylab("tip") +  labs(fill = "sex") +
  ggthemes::theme_few(base_size = 14, base_family = "sans")
print(.plot)
Few風格

第5個圖是著名的網站538風格,fivethirtyeight是預測高手Nate Silver所創立,Nate著有Noices and Signals一書,中譯「精準預測」
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) +  geom_boxplot(position = position_dodge(width = 0.9)) + 
  xlab("day") + ylab("tip") +  labs(fill = "sex") +
  ggthemes::theme_fivethirtyeight(base_size = 14, base_family = "sans")  
print(.plot)  
538風格

最後一個是利用 igray 風格呈現新的資料結構,把前面的圖,再依照星期和吸煙與否做成2x2=4格。
.df <- data.frame(y = tips$tip, x = tips$day,z = tips$sex, s = tips$time, t = tips$smoker)
.plot <- ggplot(data = .df, aes(x = factor(x), y = y, fill = z)) + 
  stat_boxplot(geom = "errorbar", position = position_dodge(width = 0.9), 
  width = 0.5) + 
  geom_boxplot(position = position_dodge(width = 0.9)) + 
  facet_grid(s ~ t) + 
  xlab("day") +  ylab("tip") + labs(fill = "sex") + 
  ggthemes::theme_igray(base_size = 14, base_family = "sans") + 
  theme(panel.spacing = unit(0.3, "lines"))
print(.plot)
 igray 風格