iT邦幫忙

0

R 語言 ggplot2 繪圖問題請教 (Bar Chart + Line Chart 合併呈現)

  • 分享至 

  • xImage

各位大大好
小弟近期在學習 R ggplot2
目前我想試著繪出下面這張圖
https://ithelp.ithome.com.tw/upload/images/20211111/20110872inzdZXxpOa.png

但自己試了蠻久的,畫出來結果都會變成這樣
https://ithelp.ithome.com.tw/upload/images/20211111/20110872bgfBwQr2Ho.png
主要卡點在於不太清楚如何把「總平均」獨立出來,以及Legend 自己獨立一個,即使自己已經分成兩個 DataFrame 了,好像也沒比較好

我的Code 如下:

library("ggplot2")
library("scales")
library("readxl")
windowsFonts(A=windowsFont("微軟正黑體")) 

df <- read_excel("./data/fi00128y2a2021523591831.xlsx")
# 資料表處理
df <- df[2:5]
df <- df[complete.cases(df), ]
colnames(df) <- c('年份', '總平均', '男', '女')
df[2:4] <- sapply(df[2:4], as.numeric)


new_df <- cbind(stack(df[, -1]), 年份=df$年份)
new_df$年份 <- factor(new_df$年份, levels = unique(new_df$年份))

(new_df.sex <- new_df[new_df$ind != '總平均',])
(new_df.avg <- new_df[new_df$ind == '總平均',])

# 繪圖
ggplot(new_df.sex, aes(x=年份, y=values, fill=ind)) + 
    geom_bar(stat='identity', position= position_dodge(width=1)) +
    geom_line(data=new_df.avg, aes(x=年份, y=values), stat='identity', size=0.5) +
    geom_point(data=new_df.avg, aes(x=年份, y=values), colour="black", size=2, shape=21, fill="darkgreen", group=2) +
    labs(x='Year', y='Salary', title='臺北市所得收入者每人所得-性別:本業月均薪資', fill='性別') +
    scale_y_continuous(labels=comma) +
    theme(plot.title=element_text(face="bold",size=12,family="A",color="black",hjust=0))

new_df 資料集內容:

> new_df

values    ind  年份
1  384362 總平均  982  393629 總平均  993  392977 總平均 1004  400942 總平均 1015  385983 總平均 1026  410951 總平均 1037  375280 總平均 1048  361584 總平均 1059  393979 總平均 10610 385462 總平均 10711 391033 總平均 10812 4026999813 4111939914 41625310015 42361410116 41131110217 45054210318 39845310419 38051210520 42512310621 41587910722 42441410823 3598649824 3706629925 36316310026 37235110127 35216210228 36071410329 34734210430 33703810531 35485510632 34894910733 351266108

希望有熟悉 R 繪圖的大大可以協助,感恩

new_df 內容似乎少了 sex, avg ?
huahualiu iT邦新手 2 級 ‧ 2021-11-11 11:25:54 檢舉
兩者都歸類在 ind 欄位中
我的做法比較是想透過 ind 欄位篩選出我要的項目 進行繪圖
.
圖片
  直播研討會

1 個回答

1
barry282228
iT邦新手 2 級 ‧ 2021-11-12 14:33:10
最佳解答
ggplot()+
  geom_bar(data = new_df[new_df$ind != '總平均',],aes(年分, values,fill = ind),stat='identity', position= position_dodge(width=1))+
  geom_point(data = new_df[new_df$ind == '總平均',],aes(年分, values))+
  geom_line(data = new_df[new_df$ind == '總平均',],aes(年分, values,group = 1))

不要一開始就把資料塞進ggplot()裡面去
在繪圖時再分別指定資料即可
其餘細節再自己調整囉

huahualiu iT邦新手 2 級 ‧ 2021-11-12 15:05:55 檢舉

謝謝 大大 後來自己在研究的時候也發現這件事情XD
不過另外想請教的是
像例圖這樣將兩種 geom 圖拆成兩個 legend 顯示
這到底該怎麼實作呢?

自己後來的硬做解法如下:(右上圖例是硬畫出來的XD)

new_df.sex <- new_df[new_df$ind != '總平均',]
(new_df.avg <- new_df[new_df$ind == '總平均',])
avg <- data.frame(avg.x = new_df.avg$年份[1:length(new_df.avg$年份)-1],
                  avg.y = new_df.avg$values[1:length(new_df.avg$values)-1],
                  avg.xend = new_df.avg$年份[2:length(new_df.avg$年份)],
                  avg.yend = new_df.avg$values[2:length(new_df.avg$values)])

# 繪圖
ggplot(new_df.sex, aes(x=年份, y=values)) + 
    geom_bar(stat='identity', position= position_dodge(width=1), aes(fill=ind)) +
    geom_segment(data=avg, mapping=aes(x=avg.x, y=avg.y, xend=avg.xend, yend=avg.yend), size=1, color="darkgreen") +
    geom_segment(data=avg, mapping=aes(x=c('106年'), y=c(450000), xend=c('107年'), yend=c(450000)), size=2, color="darkgreen") +
    geom_text(x=c('108年'), y=c(450000), label='總平均', family="A") +
    geom_point(data=new_df.avg, aes(x=年份, y=values), colour="black", size=2, shape=21, fill="darkgreen", group=2) +
    labs(x='Year', y='Salary', title='臺北市所得收入者每人所得-性別:本業月均薪資', fill='性別') +
    scale_y_continuous(labels=dollar) +
    theme(plot.title=element_text(face="bold",size=12,family="A",color="black",hjust=0))

畫出來的圖:
https://ithelp.ithome.com.tw/upload/images/20211112/201108720lV2YBJKXc.jpg

ggplot()+
  geom_bar(data = df[df$ind != '總平均',],aes(年分, values,fill = ind),stat='identity', position= position_dodge(width=1))+
  geom_point(data = df[df$ind == '總平均',],aes(年分, values))+
  geom_line(data = df[df$ind == '總平均',],aes(年分, values,color = ind,group = 1))+
  scale_fill_manual(values = c("#CB9498", "#D8AD48"), labels = c("男男", "女女"))+
  scale_color_manual(values = "#AC9D98", labels = "總平均")

一個用scale_fill_manual
一個用scale_color_manual
這樣就有兩個圖例

可以參考這篇
https://ggplot2.tidyverse.org/reference/scale_manual.html

我要發表回答

立即登入回答