본문 바로가기

Data

[R] 데이터 시각화 with R ( 롤리팝차트 / 덤벨차트 / 슬로프차트 )

오늘은 저번 포스팅에 이어서 T아카데미 데이터 시각화 with R 복습을 해보겠다

강의 링크는 아래를 참조!

 

tacademy.skplanet.com/live/player/onlineLectureDetail.action?seq=172

 

데이터 시각화 with R | T아카데미 온라인강의

1. R 시각화 라이브러리인 ggplot2의 기본적인 사용방법에 대해 알아봅니다. 2. ggplot2를 활용하여 기본 그래프 및 차트, 비정형 그래프 그리기 등 표현방법에 대해 ..

tacademy.skplanet.com

 

롤리팝차트

 

데이터 불러오기

read.csv("kovo.csv") %>% as_tibble() -> kovo # 남녀부 배구데이터

 

남녀 구분하여 구단별 퀵오픈에 대한 롤리팝 차트 그리기

kovo %>% ggplot(aes(x=reorder(구단,퀵오픈), y=퀵오픈, color=남녀부))+ # reorder 기본값은 오름차순, 내림차순: -퀵오픈
  geom_segment(aes(xend=구단,yend=0))+ 
  geom_point(size=5)+
  coord_flip()+
  facet_grid(남녀부~.,scales="free_y")



# facet_grid, facet_wrap 차이
# facet_grid, ~변수,변수~. 에따라 x,y축 순서 변경
# facet_wrap은 그렇지 않음, 대신 ncol, nrow등 행렬로 ,변수 2개 사용 가능

 

 

geom_segment는 aes(x,y,xend,yend) : (x,y),(xend,yend)를 직선으로 연결함, 롤리팝 차트 위해 필수!!

지금 퀵오픈 값에 선을 그어야 하므로 x=구단,y=퀵오픈 -> xend=구단,yend=0

 

scales="free_y" , facet_grid로 칸 나눠지면서 생기는 빈칸 없애줌

 

 

theme 함수를 통해 다듬기

kovo %>% ggplot(aes(x=reorder(구단,퀵오픈), y=퀵오픈, color=남녀부))+ 
  geom_segment(aes(xend=구단,yend=0))+ 
  geom_point(size=5)+
  coord_flip()+
  facet_grid(남녀부~.,scales="free_y")+
  labs(x="")+
  scale_color_manual(values = c("#2D2C76","#D12C76"))+ # 남녀 색깔 지정
  theme(axis.ticks =element_blank(),				# 눈금 없애기
        panel.grid = element_blank(), 				# 배경 그리드 없애기
        panel.background = element_rect("#F6F6F6"), # 배경색 변경
        strip.background = element_rect("#989797")) # 남녀 써있는 상단바
  

여기까지가 수업 내용이었지만, 추가적으로 중간값을 넣어주면 남녀를 더 구분하기 쉬울것이라고 생각했다

 

 

남녀 퀵오픈 중간값 표시

kovo %>% mutate(med_line = ifelse(남녀부 == "남",812,971)) -> kovo2


kovo2 %>% ggplot(aes(x=reorder(구단,퀵오픈), y=퀵오픈, color=남녀부))+ 
  geom_segment(aes(xend=구단,yend=0))+ 
  geom_point(size=5)+
  coord_flip()+
  facet_grid(남녀부~.,scales="free_y")+
  labs(x="")+
  scale_color_manual(values = c("#2D2C76","#D12C76"))+
  theme(axis.ticks =element_blank(),
        panel.grid = element_blank(),
        panel.background = element_rect("#F6F6F6"),
        strip.background = element_rect("#989797"))+
  geom_hline(aes(yintercept=med_line),color="#989797")
  

중간값을 달기 위해서 med_line이라는 새로운 변수를 생성했다.

변수를 새로 생성하면 쉽게 facet_grid로 나누어진 자료에도 각각 라인을 그릴 수 있다.

그 후 geom_hline 함수를 통해 중간값 선을 넣어 주었다.

 

이제 저 회색선이 중간값이다! 라고 라벨을 달아줘야하는데 문제는 남녀를 구분해야한다는 것,,

 

 

남녀 퀵오픈 중간값 라벨 표시하기

text_df = data.frame(label = c("남자 퀵오픈 중간값", "여자 퀵오픈 중간값"),
                     x = c(1,1),
                     y = c(812,971),
                    남녀부 = c("남","여")) # 이거 중요!! 없으면 에러


kovo2 %>% ggplot(aes(x=reorder(구단,퀵오픈), y=퀵오픈, color=남녀부))+ 
  geom_segment(aes(xend=구단,yend=0))+ 
  geom_point(size=5)+ 
  coord_flip()+
  facet_grid(남녀부~.,scales="free_y")+
  labs(x="")+
  scale_color_manual(values = c("#2D2C76","#D12C76"))+
  theme(axis.ticks =element_blank(),
        panel.grid = element_blank(),
        panel.background = element_rect("#F6F6F6"),
        strip.background = element_rect("#989797"))+
  geom_hline(aes(yintercept=med_line),color="#989797")+
  geom_text(data = text_df, mapping = aes(label=label,x=x,y=y),size=2.5) # 주석

 

중간값 라인을 그려주기 위해서 새로운 변수를 만들었다면, 이번에는 라벨링을 위한 데이터프레임을 만들었다.

여기서 x, y는 라벨이 놓여줄 위치를 의미한다.

남녀부를 추가한 이유는 새 데이터가 남녀로 구분되어있어야만 라벨링도 구분되어서 따로 나올 수 있다!!!! 매우 중요

 

그 후, geom_text에서 mapping을 통해 라벨링을 했다.

 

 

y축 범위 바꾸고 퀵오픈값 라벨링

kovo2 %>% ggplot(aes(x=reorder(구단,퀵오픈), y=퀵오픈, color=남녀부))+ 
  ylim(300,1200)+ 
  geom_segment(aes(xend=구단,yend=300))+ 
  geom_point(size=8)+ # 크기 키움
  coord_flip()+
  facet_grid(남녀부~.,scales="free_y")+
  labs(x="", y="", title = "배구 퀵오픈")+ # y축 없애기, 제목 생성
  scale_color_manual(values = c("#2D2C76","#D12C76"))+
  theme(axis.ticks =element_blank(),
        panel.grid = element_blank(),
        panel.background = element_rect("#F6F6F6"),
        strip.background = element_rect("#989797"),
        axis.text.x = element_blank(), # 숫자 없애기
        plot.title = element_text(hjust = 0.5))+ # 제목 가운데에 위치
  geom_hline(aes(yintercept=med_line),color="#989797")+
  geom_text(aes(label=퀵오픈),col="white",size=3)+ # 퀵오픈 추가
  geom_text(data = text_df, mapping = aes(label=label,x=x,y=y),size=2.5) # 주석

차이를 좀 더 극명하게 보여주기 위해 y축을 300부터 시작하도록 했다. 이때 주의할 점은 geom_segment의 yend=300으로 변경해줘야 한다는 점!

 

또한, 밑의 퀵오픈 축을 삭제하고 퀵오픈값을 라벨링 했다. 디자인적으로 훨씬 더 깔끔해진 것을 확인할 수 있다.

 

다만 아쉬운점은 구단별 간격이 좁다는 것인데 늘리는 방법을 모르겠다..축 길이를 늘리는 방법 아시는 분 있으면 댓글로 남겨주세요..

 

덤벨차트       

다음으로는 덤벨차트! 두 변수를 비교하는 시각화를 할 때 유용하다

 

데이터 불러오기

read.csv("fifa.csv") %>% as_tibble() -> fifa # 1993~2018 피파 데이터

 

아시안컵에서 국가별 최고랭킹과 최저랭킹을 시각화 해보자

 

 

국가별 최고 랭킹 점으로 표시

fifa %>%
  filter(confederation == "AFC") %>% # AFC: 아시안컵
  group_by(country_full) %>%
  summarise(최고=min(rank), 최저=max(rank)) %>%
  ggplot(aes(x=최고, y=reorder(country_full, -최고)))+ # 등수 높은 국가가 맨 위에
  geom_point()+
  scale_x_reverse() # 랭킹은 작을수록 좋으므로
  

여기서 주의할 점은 랭킹 순위는 작을수록 높다! 라는 사실을 간과해선 안된다.

그래서 국가명을 정렬할때도 "-최고" 변수앞에 -를 붙여주었다.

또한 scale_x_reverse() 함수를 통해 x축도 뒤집어주었다 (큰->작)

 

 

국가별 최저 랭킹 점으로 표시

fifa %>%
  filter(confederation == "AFC") %>% 
  group_by(country_full) %>%
  summarise(최고=min(rank), 최저=max(rank)) %>%
  ggplot(aes(x=최고, y=reorder(country_full, -최고)))+ 
  geom_point(col="red")+
  scale_x_reverse()+
  geom_point(aes(x=최저),col="blue")

또다시 geom_point를 이용해 이번에는 최저 순위까지 찍어주었다

 

 

최고순위, 최저순위 이어주기

fifa %>%
  filter(confederation == "AFC") %>% 
  group_by(country_full) %>%
  summarise(최고=min(rank), 최저=max(rank)) %>%
  ggplot(aes(x=최고, y=reorder(country_full, -최고)))+ 
  geom_point(col="red")+
  scale_x_reverse()+
  geom_point(aes(x=최저),col="blue")+ 
  geom_segment(aes(yend=reorder(country_full, -최고),xend=최저-1.5,x=최고+1.5),col="grey")+ # 선위치 조절
  labs(title="피파 아시안컵  최저순위 최고순위",y="",x="순위")+
  theme(axis.ticks =element_blank(),
        panel.grid = element_blank(),
        panel.background = element_rect("white"),
        plot.title = element_text(hjust = 0.5))

역시나 롤리팝 차트처럼 geom_segment를 이용해서 최저 순위와 최고 순위를 연결해주었다

이때 geom_segment에서 xend=최저-1.5, x=최고+1.5 로 한 이유는 이렇게 하지 않으면 선의 길이가 너무 길어져서 점과 겹치기 때문이다.

 

이렇게 덤벨차트도 끝! 최저 순위와 최고 순위를 한눈에 비교할 수 있게 되었다.

 

슬로프 차트

덤벨차트는 순위만을 비교했다면, 슬로프 차트는 다양한 속성의 증감을 비교할 때 더 효과적이다

 

데이터 불러오기

read.csv("kal.csv") %>% as_tibble() -> kal # 두 선수 데이터

두 배구 선수에 관한 데이터이다. 얼핏 보면 전혀 문제가 없어보이지만 이는 wide form 데이터이므로

long form 으로 바꿔줘야 컴퓨터가 그래프를 그리기 훨씬 수월하다.

 

 

tidy data로 형태 변경하기

kal %>% gather(-세터, key="공격", value="점유율")

wide form을 long form으로 변경시켜주는 함수는 gather! (반대는 spread)

gather(data, key,value)
key: column 이름에 나타난 값을 위한 변수명 

value: column에서 가지고 있는 값을 저장하기 위한 변수명

 

data 부분에서 -세터는 세터를 제외한 나머지 변수 모두를 gather하라는 의미

 

 

두 선수의 공격 점유율 슬로프 차트로 표현하기

kal %>% gather(-세터, key="공격", value="점유율") %>%
  ggplot(aes(x=세터, y=점유율,group=공격))+ # group=공격 없으면 세터기준으로 세로 직선 그어짐
  geom_point()+
  geom_line()+
  geom_text(aes(label=paste(공격,format(점유율,digits=1))))

# label=paste(변수1,변수2...) : 여러개 변수 라벨링 하고싶을때

슬로프 차트의 핵심은 groupgeom_line()

group = 공격 옵션이 있어야 geom_line()에서 공격별로 라인을 그어준다

 

하지만 지금은 라벨이 너무 지저분하다. 공격명은 굳이 2번 써줄 필요가 없으므로 다음단계에서 지워주자!

 

 

 

공격명 라벨링 한 번만 쓰기 , 공격별 색깔 다르게 표시

kal %>% gather(-세터, key="공격", value="점유율") %>%
  ggplot(aes(x=세터, y=점유율,group=공격,color=공격))+ # group=공격 없으면 세터기준으로 세로 직선 그어짐
  geom_point()+
  geom_line()+
  geom_text(data=.%>%filter(세터=="유광우"),
            aes(label=paste(공격, format(점유율, digits=1))), hjust=1.1)+
  geom_text(data=.%>% filter(세터=="한선수"),
            aes(label=format(점유율,digits=1)),hjust=-0.2)+
  labs(title = "세터선수 공격 점유율 비교")+
  theme(legend.position = "none",
        axis.ticks=element_blank(),
        panel.grid=element_blank(),
        panel.background = element_blank(),
        axis.text.y=element_blank(),
        axis.title.y = element_blank(),
        axis.title.x=element_blank(),
        plot.title = element_text(hjust=0.5))

  

geom_text(data=.%>%filter(세터=="유광우"),
            aes(label=paste(공격, format(점유율, digits=1))), hjust=1.1)

여기서 data=. 은 위 코드 데이터를 이어 받겠다라는 의미

 

훨씬 깔끔하고 가독성 좋은 슬로프 차트 완성!

 

 


이렇게 두번째 복습까지 포스팅 끝

하지만 아직 갈길이 멀다..

다음에는 네트워크 시각화와 가능하다면 레이스 차트까지 복습하기로!!