Must Learning With Statistics

[R 대시보드] Flexdashboard 패지키를 활용한 R 대시보드 만들기 1편 본문

R Code

[R 대시보드] Flexdashboard 패지키를 활용한 R 대시보드 만들기 1편

Doublek Park 2020. 2. 9. 21:29

R을 통해 Dashboard 만들어 보기

Ch1. Dashboard란?

  • BI(Business Intelligence) 화면이라고도 할 수 있습니다.
  • 데이터 시각화의 결과를 한 눈에 볼 수 있도록 구성되어 있는 하나의 보고서(화면) 입니다.
  • 무엇보다 실무에서 많이 쓰이며, 보통 태블로, Qlik Sense 등의 BI tool로 작업이 진행됩니다.
  • 저희가 R을 통해 만들어 보는 것은 복습하고자 하는 것도 있으며, 직접 가공한 데이터들을 통해 하나의 결과물을 만들어 보고자 하는 목표입니다.

Ch2. 마크다운

마크다운은 많은 개발자들이 선호하는 문서 편집기입니다. 작성방법이 매우 편리하며, 무엇보다 source code를 삽입하는 것이 매우 편리하여, 코드와 함께 결과보고서를 작성하는 데에는 마크다운보다 편리한 것이 없다고 할 수 있습니다.

  1. 마크다운만의 문법이 존재합니다. 구글에 검색하면 설명이 많이 나오나 걱정할 필요는 없습니다.

    • typora 편집기를 이용하면 편리하게 마크다운 형식의 문서를 편집할 수 있습니다.

    • typora 편집기는 매우 쉽습니다.

    • 일반 텍스트로 작성을 한 후, 이를 markdown 문법 혹은 html 문법으로 변환 가능합니다.

    • 다운로드 링크 : https://typora.io/

  2. 마크다운을 왜 소개하는건가요?

    • 대시보드를 만들려면 "flexdashboard" 라는 패키지를 사용해야 합니다. 이 패키지는 markdown형식으로 편집이 됩니다.

    • 물론 작성은 Rstuido에서 markdown파일을 열어서 합니다.

Ch3. Flexdashboard를 통한 Dashboard 만들기 1편

1. Dashboard 만드는 순서

  • 출력 옵션 설정

    • 대시보드 제목

    • 페이지 제목

    • 소스코드 삽입 여부

    • 레이아웃 배치 기준 설정(행 기준 혹은 열 기준)

    • 출력형식 설정

  • 대시보드 레이아웃 구성

    • 사이드바 삽입 여부

    • Row 혹은 Column 을 추가함으로써 레이아웃 추가

  • 그래프 추가

    • 사이드바 혹은 배치된 Row & Column 배치 코드 밑에 그래프 추가
  • Rendor plot 및 plotly 추가 여부

    • Rendor plot이란 대시보드에 직접 input parameter를 추가함으로써, input의 변경 여부에 따라 그래프가 변경되는 동적 대시보드를 만들고자 할 때 쓰이는 plot입니다.

    • plotly는 그래프를 확대해서 볼 수도 있고, 마우스를 그래프에 위치시키면 그래프의 값이 나오게 되는 패키지입니다.

참고 사이트 : https://rmarkdown.rstudio.com/flexdashboard/using.html

제가 사진으로 업로딩한 Dashboard 코드는 다음과 같습니다. 전체적인 구조를 한번 훑어보고 하나씩 따로 이해하는 것으로 진행하겠습니다.

참고로 이제부터 시작하는 코드들은 모두 markdown 문법형태입니다.

2. Dashboard 출력 옵션 적용

---
title: "LEARNIT"  <!-- Dashboard 이름 설정 -->
output: 
  flexdashboard::flex_dashboard:
    orientation: rows <!-- layout 배치를 행(row)이 늘어나는 식으로  배치 -->
    source_code: embed <!-- Source code 삽입 --> 
    theme: readable
  runtime: shiny
---

3. 시각화에 필요한 패키지 및 데이터 및 전처리 작업 진행

데이터 다운로드 링크 : https://www.kaggle.com/PromptCloudHQ/imdb-IMDB
대시보드를 구성하기 전에, 필요한 전처리는 미리 다 작업을 한 후에, 대시보드 작성을 시작합니다.

​```{r setup, include=FALSE} <!-- include = FALSE 옵션, 해당되는 R code는 표시되지 않음 -->
library(flexdashboard)
library(ggplot2)
library(plotly)
library(shiny)
library(plyr)
library(dplyr)
library(plotly)
library(tm)
IMDB = read.csv("C:/R/IMDB-Movie-IMDB.csv")
IMDB$Genre2 = IMDB$Genre

IMDB$Genre2=gsub(","," ",IMDB$Genre2)

CORPUS=Corpus(VectorSource(IMDB$Genre2))
CORPUS_TM = tm_map(CORPUS,removePunctuation)
CORPUS_TM = tm_map(CORPUS_TM, removeNumbers)
CORPUS_TM = tm_map(CORPUS_TM, tolower)

DTM = DocumentTermMatrix(CORPUS_TM)

DTM = as.data.frame(as.matrix(DTM))

IMDB = cbind(IMDB,DTM)

FIRST_GENRE = c()
for(i in 1:nrow(IMDB)){
  FIRST_GENRE[i] = strsplit(as.character(IMDB$Genre[i]),",")[[1]][1]
}

IMDB$FIRST_GENRE = FIRST_GENRE



##### 4. Dashboard 페이지 이름 및 아이콘 설정(윗단 구성 완료)

​```markdown
DASHBOARD CREATING {IMDB-icon="fa-signal"} <!-- Dashboard 이름 설정 및 아이콘 설정 -->
========================== <!-- = 으로 분리하면 격자선이 생기면서 윗단 구성을 완료 -->

5. Dashboard 레이아웃 구성

  • 전체 레이아웃

  • 1번 레이아웃 배치 코드 (사이드바)

    Column {.sidebar}  <!--1번 레이아웃 설정 코드-->
    --------------------------
    
    Today : 2018-12-04 TUE    
    Learnit Job Class    
    Description :    
    
    1. 대시보드 만들기      
    2. 새로운 평가지표 만들어보기    
    3. 그래프 이쁘게 그려보기    
    4. 유지보수 잘하기    
    
    ```{r}
    selectInput('Genre', 'Genre',IMDB$FIRST_GENRE,
                selected = 'action')
    
    numericInput("Rating", "min Rating:", 6)
    
    ```

    레이아웃을 배치할 때는 항상 Column 혹은 Row를 써준 다음에 '-------------------'를 써서 구분지어주면 바로 배치가 완성이 됩니다.

  • 2번 레이아웃 배치 코드

    일반적인 layout 배치도 다음과 같습니다 . Row를 선언해주고 '-------------------'를 써서 구분지어주면 배치는 완료됩니다. 그 밑에는 제목을 적어주고 컨텐츠를 작성해주면 됩니다.

    Row {IMDB-height=100} <!-- Row 를 선언해줌으로써 2번 레이아웃 배치 선선 -->
    ------------------------ <!-- 2번 레이아웃 배치코드 구분선 -->
    ### Target Of Dashboard <!-- 레이아웃 제목 정해주기 -->
    
    parameter 설정에 따라 변경되는 동적 대시보드 만들기
  • 3번 레이아웃 배치코드

    3번 레이아웃은 다음의 코드로 만들어 집니다. 내부 valueBox라던지, selectedIMDB같은 명령어는 후에 정리하도록 하겠습니다.

    Row <!-- 3번 레이아웃 배치코드 -->
    -------------------------------- <!-- 3번 레이아웃 배치코드 구분선 -->
    
    <!-- 레이아웃 제목을 추가한만큼 레이아웃이 제목 수만큼 분할하고 컨텐츠를 보여줌 -->
    <!-- 추가하는 레이아웃은 좌측부터 우측으로 순서대로 배치 -->
    
    ### Total Movies <!-- 3번 레이아웃 좌측 컨텐츠 제목 작성 -->
    
    <!-- 컨텐츠 작성 -->
    ```{r}
    valueBox(value = paste(nrow(IMDB),"movies"),
             color='royalblue')
    ```
    
    ### Selected Movies <!-- 3번 레이아웃 중앙 컨텐츠 제목 작성 -->
    
    <!-- 컨텐츠 작성 -->
    ```{r}
    selectedIMDB = reactive({
      subset(IMDB,FIRST_GENRE==input$Genre)
    })
    ```
    
    ```{r}
    
    renderValueBox({
      valueBox(
        value = nrow(selectedIMDB()),
        icon = "fa-area-chart",
        color = ifelse(nrow(selectedIMDB()) < 50, "warning", "primary")
      )
    })
    
    ```
    
    ### Ratings Gauge <!-- 3번 레이아웃 우측 컨텐츠 제목 작성 -->
    
    ```{r}
    
    renderGauge({
      gauge(round(mean(selectedIMDB()$Metascore,na.rm = TRUE),2), 
            min = 0, max = 100, 
          gaugeSectors(
      success = c(80, 100), warning = c(40, 79), danger = c(0, 39)
    ))
    })
    
    ```
  • 4번 레이아웃 배치코드

    Row {IMDB-width=650}  <!-- 4번 레이아웃 배치코드 -->
    ------------------------ 
    ### 년도별 영화 매출 추이(전체) <!-- 4번 레이아웃 좌측 그래프 제목 -->
    
    <!-- 4번 레이아웃 좌측 그래프 코드 -->
    ```{r}
    
     YEAR1 = IMDB %>%
      group_by(Year) %>%
      dplyr::summarise(MEAN = mean(Revenue..Millions.,na.rm = TRUE),
                       MEDIAN = median(Revenue..Millions.,na.rm = TRUE))
     p = ggplot(YEAR1) +
      geom_line(aes(x=Year,y=MEAN),group = 1 , col ='red') +
      geom_point(aes(x=Year,y=MEAN), col ='red') +
      geom_line(aes(x=Year,y=MEDIAN),group = 1 , col = 'royalblue') +
      geom_point(aes(x=Year,y=MEDIAN) , col = 'royalblue') +
      xlab("년도") + ylab("매출액") 
    
     ggplotly(p)
    
    ```
    
    ### 년도별 영화 매출 추이(장르 선택) <!-- 4번 레이아웃 우측 그래프 제목 -->
    
    <!-- 4번 레이아웃 우측 그래프 코드 -->
    ```{r}
    
    renderPlotly({
     YEAR2 = selectedIMDB() %>%
      group_by(Year) %>%
      dplyr::summarise(MEAN = mean(Revenue..Millions.,na.rm = TRUE),
                       MEDIAN = median(Revenue..Millions.,na.rm = TRUE))
     p = ggplot(YEAR2) +
      geom_line(aes(x=Year,y=MEAN),group = 1 , col ='red') +
      geom_point(aes(x=Year,y=MEAN), col ='red') +
      geom_line(aes(x=Year,y=MEDIAN),group = 1 , col = 'royalblue') +
      geom_point(aes(x=Year,y=MEDIAN) , col = 'royalblue') +
      xlab("년도") + ylab("매출액") 
    
     ggplotly(p)
    })
    
    ```

5번 레이아웃 코드

Row {IMDB-width=650} <!-- 5번 레이아웃 배치코드 -->
------------------------ 
### 데이터 테이블 <!-- 5번 레이아웃 테이블 제목 설정 -->

```{r}
selectedIMDB2 = reactive({
  subset(IMDB,FIRST_GENRE==input$Genre & Rating > input$Rating)
})
```

```{r}
renderTable({
 DF = selectedIMDB2()[,c(2,3,5:10,34)]
 DF[order(-DF$Rating),]
})

```

여기까지 대시보드 작성 코드였습니다. 대략적인 구조는 이해가 되셨나요? 어려워 보이지만 구조를 파악하면 어려울 것이 없습니다. 출력옵션을 정해주고, 레이아웃 배치를 간단하게 정한다음 그래프를 넣어주면 끝나는 겁니다.

다음으로 예시 레이아웃 예시본을 보여드리면서 레이아웃 구성은 마무리 짓도록 하겠습니다.

전체코드는 다음과 같습니다.

---
title: "LEARNIT"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
    source_code: embed
    theme: readable
  runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(ggplot2)
library(plotly)
library(shiny)
library(plyr)
library(dplyr)
library(plotly)
library(tm)
```

```{r}
IMDB = read.csv("C:/R/IMDB-Movie-IMDB.csv")
```

```{r}
IMDB$Genre2 = IMDB$Genre

IMDB$Genre2=gsub(","," ",IMDB$Genre2)

CORPUS=Corpus(VectorSource(IMDB$Genre2))
CORPUS_TM = tm_map(CORPUS,removePunctuation)
CORPUS_TM = tm_map(CORPUS_TM, removeNumbers)
CORPUS_TM = tm_map(CORPUS_TM, tolower)

DTM = DocumentTermMatrix(CORPUS_TM)

DTM = as.IMDB.frame(as.matrix(DTM))

IMDB = cbind(IMDB,DTM)

FIRST_GENRE = c()
for(i in 1:nrow(IMDB)){
  FIRST_GENRE[i] = strsplit(as.character(IMDB$Genre[i]),",")[[1]][1]
}

IMDB$FIRST_GENRE = FIRST_GENRE
```

 

DASHBOARD CREATING {IMDB-icon="fa-signal"}
==========================
Column {.sidebar}
--------------------------
Today : 2018-12-04 TUE    
Learnit Job Class    
Description :    

1. 대시보드 만들기      
2. 새로운 평가지표 만들어보기    
3. 그래프 이쁘게 그려보기    
4. 유지보수 잘하기    

```{r}
selectInput('Genre', 'Genre',IMDB$FIRST_GENRE,
            selected = 'action')

numericInput("Rating", "min Rating:", 6)

```

Row {IMDB-height=100}
------------------------
### Target Of Dashboard

parameter 설정에 따라 변경되는 동적 대시보드 만들기

Row
--------------------------------
### Total Movies

```{r}
valueBox(value = paste(nrow(IMDB),"movies"),
         color='royalblue')
```

### Selected Movies
```{r}

selectedIMDB = reactive({
  subset(IMDB,FIRST_GENRE==input$Genre)
})

```

```{r}

renderValueBox({
  valueBox(
    value = nrow(selectedIMDB()),
    icon = "fa-area-chart",
    color = ifelse(nrow(selectedIMDB()) < 50, "warning", "primary")
  )
})

```

### Ratings Gauge

```{r}

renderGauge({
  gauge(round(mean(selectedIMDB()$Metascore,na.rm = TRUE),2), 
        min = 0, max = 100, 
      gaugeSectors(
  success = c(80, 100), warning = c(40, 79), danger = c(0, 39)
))
})

```


Row {IMDB-width=650}
------------------------ 
### 년도별 영화 매출 추이(전체)

```{r}

 YEAR1 = IMDB %>%
  group_by(Year) %>%
  dplyr::summarise(MEAN = mean(Revenue..Millions.,na.rm = TRUE),
                   MEDIAN = median(Revenue..Millions.,na.rm = TRUE))
 p = ggplot(YEAR1) +
  geom_line(aes(x=Year,y=MEAN),group = 1 , col ='red') +
  geom_point(aes(x=Year,y=MEAN), col ='red') +
  geom_line(aes(x=Year,y=MEDIAN),group = 1 , col = 'royalblue') +
  geom_point(aes(x=Year,y=MEDIAN) , col = 'royalblue') +
  xlab("년도") + ylab("매출액") 

 ggplotly(p)

```

### 년도별 영화 매출 추이(장르 선택)

```{r}

renderPlotly({
 YEAR2 = selectedIMDB() %>%
  group_by(Year) %>%
  dplyr::summarise(MEAN = mean(Revenue..Millions.,na.rm = TRUE),
                   MEDIAN = median(Revenue..Millions.,na.rm = TRUE))
 p = ggplot(YEAR2) +
  geom_line(aes(x=Year,y=MEAN),group = 1 , col ='red') +
  geom_point(aes(x=Year,y=MEAN), col ='red') +
  geom_line(aes(x=Year,y=MEDIAN),group = 1 , col = 'royalblue') +
  geom_point(aes(x=Year,y=MEDIAN) , col = 'royalblue') +
  xlab("년도") + ylab("매출액") 

 ggplotly(p)
})

```

Row {IMDB-width=650}
------------------------ 
### 데이터 테이블
```{r}
selectedIMDB2 = reactive({
  subset(IMDB,FIRST_GENRE==input$Genre & Rating > input$Rating)
})
```

```{r}
renderTable({
 DF = selectedIMDB2()[,c(2,3,5:10,34)]
 DF[order(-DF$Rating),]
})

```
~~~
  • 예시 1

 

~

markdown
---
title: "Dashboard 1"
output:
flexdashboard::flex_dashboard:
orientation: rows
source_code: embed
theme: readable
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
```

DASHBOARD 1
========================

Row
------------------------
### GRAPH1

Row{IMDB-width=650}
------------------------
### GRAPH1 


### GRAPH2

Row{IMDB-width=650}
------------------------

### GRAPH1

### GRAPH2

### GRAPH3

DASHBOARD 1_2
========================

Row
------------------------
### GRAPH1

Row{IMDB-width=650}
------------------------
### GRAPH1 


### GRAPH2

Row{IMDB-width=650}
------------------------

### GRAPH1

### GRAPH2

### GRAPH3
~~~
  • 예시 2

    ---
    title: "Dashboard 2"
    output: 
      flexdashboard::flex_dashboard:
        orientation: rows
        source_code: embed
        theme: readable
      runtime: shiny
    ---
    
    ```{r setup, include=FALSE}
    library(flexdashboard)
    ```
    
    DASHBOARD 2
    ========================
    
    Column{.sidebar}
    ------------------------
    
    ### Graph1
    
    ### Graph2
    
    Row
    ------------------------
    
    ### Graph1
    
    ### Graph2
    
    Row
    ------------------------
    
    ### Graph1
    
Comments