一個好的可視化例子
各國家都喜愛哪些寵物?
by La Nación
作品地址
該作品於2017年10月14日發表在《阿根廷國家報》上,並獲得了2018凱度信息之美獎藝術、娛樂與文化類獎項。該作品以GFK研究所對22個國家的網民進行的調查爲基礎。
從該作品的圖表類型來看,可視爲簇狀條形圖。創作者採用人物和寵物的卡通形象巧妙地替代條形圖,極具趣味也不失直觀性,受衆能夠從中獲知的信息也比較充實,比如:魚在中國比其他地方更受歡迎,而貓是法國人最喜歡的寵物,其他國家的人們大多最喜歡狗;阿根廷和巴西的毛絨和羽毛寵物的喜歡人數多於其他國家。該作品較好地符合了“一張好的圖表應具有的基本特徵”:
- 顯示數據:動物卡通圖片上標註了該動物受國民喜愛的佔比,並用虛線標註了該佔比數值在x軸上的刻度位置。
- 讓讀者將注意力集中在圖表內容上,而不是製作程序上。總體來說該作品所要表達的信息比較明瞭直接,創意點也是圖表內容的一部分,既吸引了讀者的注意力,又突出了圖表內容。
- 避免歪曲:座標軸標度合適,信息表達直觀準確。
- 強調數據間的比較:對不同動物採取對比鮮明的色彩,使得無論是同一國家不同寵物之間的比較,還是不同國家間的比較都得到很好的突出。
- 服務於一個明確的目的:該作品的目的在於展示研究者對各國國民的寵物偏好的調查結果。
- 有對圖表的統計描述和文字說明:圖中缺少具體的描述和說明,但該作品作爲報刊插圖,配合文章內容可被較好地理解。
數據可視化的實現
使用來自北大國家發展中心的數據中的數據表demographic_background,選取其中的三個變量進行研究:
- 年齡,定量變量。部分空值通過(調查年份-出生年份) 進行填補。
- 最高學歷,定性變量。
- 婚姻狀態,定性變量。
數據導入與處理:
library(foreign)
#導入數據
db_all<-read.dta("D:/4數據集四:北大國家發展中心數據/demographic_background/demographic_background.dta")
#選擇變量
db_data<-data.frame(age=db_all$ba004,edu=db_all$bd001,mrg=db_all$be001)
#利用出生年份計算受訪者受訪時的年齡以填補缺失
db_data$age[is.na(db_data$age)]<-(2012-db_all$ba002_1)[is.na(db_data$age)]
#查看數據缺失情況
library(mice)
md.pattern(db_data,plot=F)
數據缺失情況如下:
## age mrg edu
## 17650 1 1 1 0
## 23 1 1 0 1
## 1 1 0 1 1
## 8 1 0 0 2
## 2 0 1 1 1
## 21 0 0 0 3
## 23 30 52 105
在填補後的數據中,絕大多數記錄不存在缺失。將仍存在缺失的記錄移除,得到17650條完整記錄。
單變量製圖:
對所調查人羣的最高學歷作圖:
- 條形圖
爲了讀圖更直觀,將定型變量的各個水平用對應的中文表示。按照學歷水平從低到高對人羣的最高學歷分佈情況作條形圖:
library(ggplot2)
#最高學歷
levels(db_data$edu)<-c("文盲", "未讀完小學","私塾","小學","初中",
"高中","中專","大專","本科","碩士","博士")#用中文表述不同學歷水平
edu_table<-table(db_data$edu)
#條形圖
#R基礎作圖
barplot(edu_table,space = 1/2,ylim=c(0,5000),xlab = "最高學歷",ylab="人數")
#ggplot2
ggplot(db_data,aes(x=edu))+
geom_bar(width = 2/3)+
xlab( "最高學歷")+ylab("人數")
R基礎作圖:
ggplot2:
2. 餅圖
按頻數從大到小順時針作餅圖:
#R基礎作圖工具
pie(sort(edu_table,T),clockwise=T,main = "所調查人羣最高學歷的頻數分佈情況")
#ggplot2
reorder_size <- function(x,descending=T) {#自定義函數對levels按照頻數進行重新排列
factor(x, levels = names(sort(table(x),descending)))
}
label_per = paste(names(sort(table(db_data$edu),F)), "(",
round(prop.table(table(reorder_size(db_data$edu,F))),4)*100,
"%)", sep = "")#將百分比加到標籤文字上
ggplot(db_data,aes(x=factor(1),fill=reorder_size(edu,F))) +
geom_bar() +
coord_polar(theta = "y")+#變化爲極座標以形成餅圖
labs(x = "", y = "", title = "所調查人羣最高學歷的頻數分佈情況",
fill='學歷水平')+ #去除餅圖旁邊的標籤
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank(),axis.text.y = element_blank())+ #把原座標軸的刻度文字去掉
theme(panel.grid=element_blank())+ # 去掉白色圓框和中間的座標線
scale_fill_discrete(labels = label_per[-1]) #使用含有百分比的圖例
R基礎作圖工具:
ggplot2:
對所調查人羣的婚姻狀態作圖:
- 條形圖
按照不同婚姻狀態頻數從多到少作條形圖:
#婚姻狀態
levels(db_data$mrg)<-c("已婚並同居","已婚但因工作暫分居","分居(不再作爲配偶)",
"離異","喪偶","從未結婚")#用中文表述不同婚姻狀態
mrg_table<-sort(table(db_data$mrg),T)
knitr::kable(t.data.frame(mrg_table), caption = "所調查人羣婚姻狀態的頻數分佈情況")
#條形圖
#R基礎作圖
barplot(mrg_table,space = 1/2,xlab = "婚姻狀態",ylab="人數")
#ggplot2
ggplot(db_data,aes(reorder_size(mrg)))+
geom_bar(width = 2/3)+
xlab("婚姻狀態")+ylab("人數")+
theme(axis.text.x = element_text(size=8,angle = 60, hjust = 1, vjust = 1))
#旋轉x軸刻度標籤文字,以完整顯示
R基礎作圖工具:
ggplot2:
2. 餅圖
按頻數從大到小順時針作餅圖:
#R基礎作圖工具
pie(sort(mrg_table,T),clockwise=T,main = "所調查人羣婚姻狀態的頻數分佈情況")
#ggplot2
label_per = paste(names(sort(table(db_data$mrg),F)), "(",
round(prop.table(table(reorder_size(db_data$mrg,F))),4)*100,
"%)", sep = "")#將百分比加到標籤文字上
ggplot(db_data,aes(x=factor(1),fill=reorder_size(mrg,F))) +
geom_bar() +
coord_polar(theta = "y")+#變化爲極座標以形成餅圖
labs(x = "", y = "", title = "所調查人羣婚姻狀態的頻數分佈情況",
fill='婚姻狀態')+ #去除餅圖旁邊的標籤
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank(),axis.text.y = element_blank())+ #把原座標軸的刻度文字去掉
theme(panel.grid=element_blank())+ # 去掉白色圓框和中間的座標線
scale_fill_discrete(labels = label_per) #使用含有百分比的圖例
R基礎作圖工具:
ggplot2:
對所調查人羣的年齡分佈作圖:
- 直方圖
由於年齡數據的範圍是19-102,因而可在15-105歲的範圍內按每5歲爲1組進行分組,繪製直方圖。
summary(db_data$age)
#R基本繪圖工具hist
hist(db_data$age, breaks = seq(15,105,5), xlab = "年齡",main = "所調查人羣的年齡分佈直方圖")
#ggplot2
ggplot(db_data,aes(age))+
geom_histogram(breaks=seq(15,105,5),color="white")+
xlab("年齡")
R基本繪圖工具:
ggplot2:
對比R基礎作圖工具和ggplot2
聯繫
同一數據的同一統計圖形繪製結果大體一致,都能夠根據數據準確地繪製相應圖形。
區別
- 邏輯上的區別:基礎繪圖包所提供的函數主要通過調節參數對圖形進行繪製和修改,而ggplot2除了提供更豐富的參數外,最核心的特點是基於圖層進行繪圖。
- 繪圖風格有所區別:基礎繪圖包的繪圖風格更爲簡潔,ggplot2的繪圖風格更爲精緻,且允許使用者進行豐富的個性化,如主題風格、背景、配色等。
- 在本題繪製的幾種圖形中體現的具體的區別:
- 條形圖:當x軸的刻度文字較長時,barplot()函數繪製的直方圖則不能顯示部分較長的文字,而ggplot2可通過theme函數調整文字的角度,從而完整展示文字。另外,barplot()所需的數據是頻數分佈表,而ggplot2可直接使用原始數據,對其進行頻數統計並作圖,對於頻數爲0的分類,如最高學歷爲博士的,barplot()會作出該類的條形圖,而geom_bar()不予顯示。
- 餅圖:pie()函數所作的餅圖存在標籤文字的重疊,極大影響了使用者讀圖。ggplot2不直接提供餅圖工具,但通過將條形圖的座標軸修改爲極座標軸可繪製出餅圖,圖例的使用也可解決文字重疊的問題。
- 直方圖:兩個包中的直方圖繪製函數中分組數目的默認設定有所區別,但都可通過修改breaks參數進行重新設置。
以兩個定性變量作爲分類變量繪製分面統計圖
facet_wrap 纏繞分面
按單個分類變量進行分面。
- 按最高學歷進行分面繪製年齡分佈的直方圖:
ggplot(db_data,aes(age))+
geom_histogram(breaks=seq(15,105,5),color="white")+
xlab("年齡")+facet_wrap(~edu)
2. 按婚姻狀態進行分面繪製年齡分佈的直方圖:
ggplot(db_data,aes(age))+
geom_histogram(breaks=seq(15,105,5),color="white")+
xlab("年齡")+facet_wrap(~mrg)
3. 按婚姻狀態進行分面繪製最高學歷的條形圖:
ggplot(db_data,aes(x=edu,fill=edu))+
geom_bar()+
xlab("學歷")+facet_wrap(~mrg)+
theme(axis.text.x = element_text(size=8,angle = 60, hjust = 1, vjust = 1))+
guides(fill = guide_legend(title = NULL))
facet_grid 網格分面
可用多個標準(分類變量)進行分面。
ggplot(db_data,aes(age))+
geom_histogram(breaks=seq(15,105,5))+
xlab("年齡")+facet_grid(edu~mrg)
考察兩兩變量間的關係使用哪種圖?
定性變量&定性變量
除了以表格形式呈現的列聯表之外,可以採用簇狀條形圖、堆積條形圖以及ggplot2中提供的geom_tile()函數繪製“熱圖”。
#列聯表
ctable<-table(db_data$edu,db_data$mrg)
#簇狀條形圖
#堆積條形圖
ggplot(db_data)+
geom_bar(aes(x=edu,fill=mrg),position = "dodge")+
xlab("學歷")+
theme(axis.text.x = element_text(size=8,angle = 60, hjust = 1, vjust = 1))
#熱圖
library(reshape2)
melted_ctable <- melt(ctable)
ggplot(melted_ctable,aes(x=Var2, y=Var1,fill = value))+
geom_tile()+ylab("最高學歷")+xlab("婚姻狀況")+
theme(axis.text.x = element_text(size=8,angle = 60, hjust = 1, vjust = 1))
堆積條形圖:
熱圖:
定性變量&定量變量
分別爲定性變量的不同水平繪製箱線圖。以婚姻狀況與年齡爲例:
ggplot(db_data, aes(x=mrg,y=age))+
geom_boxplot()+
xlab("婚姻狀態")+ylab("年齡")+
theme(axis.text.x = element_text(size=8,angle = 60, hjust = 1, vjust = 1))
定量變量&定量變量
可利用散點圖初步探究兩個定量變量之間的關係,以鳶尾花數據集(iris)中花瓣長度(Petal.Length)與花瓣寬度(Petal.Width)兩個定量變量爲例:
ggplot(iris, aes(x=Petal.Length,y=Petal.Width))+
geom_point()