대시보드 데이터 표시
대시보드는 탐색을 제공하고 데이터를 제시하는 구성 요소들의 조합입니다. 아래에서는 플롯, 표, 값 상자를 사용해 데이터를 제시하는 방법과 대시보드 안에 서술형 콘텐츠를 포함하는 방법을 다룹니다.
플롯
플롯은 대시보드에서 가장 흔한 콘텐츠 유형입니다. Altair와 Plotly 같은 인터랙티브 JavaScript 기반 플롯과 Matplotlib 또는 ggplot2 같은 표준 래스터 기반 플롯을 모두 지원합니다.
아래에서는 대시보드에서 플롯을 포함할 때의 언어별 팁과 기법을 소개합니다.
plotly
Plotly는 JavaScript 기반 플롯을 위한 인기 있는 Python 패키지이며 대시보드 레이아웃에서도 매우 잘 작동합니다. Plotly는 서버가 없어도 다양한 인터랙티브 기능을 제공한다는 점도 주목할 만합니다. 예를 들어, 아래 플롯은 시간이 지남에 따라 값이 변하는 모습을 애니메이션으로 보여줍니다.
```{python}
#| title: GDP and Life Expectancy
import plotly.express as px
df = px.data.gapminder()
px.scatter(
df, x="gdpPercap", y="lifeExp",
animation_frame="year", animation_group="country",
size="pop", color="continent", hover_name="country",
facet_col="continent", log_x=True, size_max=45,
range_x=[100,100000], range_y=[25,90]
)
```altair
Altair는 Vega와 Vega-Lite를 기반으로 하는 Python 선언형 통계 시각화 라이브러리입니다. Altair 플롯은 JavaScript 기반이므로 대시보드 안의 컨테이너 크기에 맞게 자동으로 크기가 조정됩니다.
```{python}
#| title: Iowa Electricity
import altair as alt
from vega_datasets import data
source = data.iowa_electricity()
alt.Chart(source).mark_area(opacity=0.3).encode(
x="year:T",
y=alt.Y("net_generation:Q").stack(None),
color="source:N"
)
```matplotlib
정적 대시보드에서 전통적인 플로팅 라이브러리를 사용할 때는, 표시될 레이아웃에 맞는 플롯 크기를 조금 더 신경 써야 합니다. 대화형 Shiny 대시보드에서는 모든 플롯이 Shiny에 의해 동적으로 크기가 조정되므로 이런 문제는 없습니다.
Matplotlib (또는 Seaborn 같은 Matplotlib 기반 라이브러리)을 사용하는 경우, figure.figsize 전역 옵션(또는 필요하다면 개별 플롯별 옵션)을 통해 플롯 크기를 설정할 수 있습니다.
```{python}
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (12, 3)
```플롯이 더 넓은 가로세로 비율로 배치되는 경우, 이 옵션은 사용 가능한 공간을 활용하는 데 큰 차이를 만들 수 있습니다. 예를 들어, 아래 스택에서 위쪽 플롯은 기본 크기 8 x 5를 사용하고, 아래쪽 플롯은 위에서 지정한 12 x 3 비율을 사용합니다.
플롯 크기를 명시적으로 지정해야 하는 것은 전통적인 플로팅 라이브러리에만 해당합니다. Plotly나 다른 JavaScript 기반 플로팅 시스템을 사용하면 플롯이 컨테이너를 채우도록 자동으로 크기가 조정됩니다.
htmlwidgets
htmlwidgets 프레임워크는 JavaScript 데이터 시각화 라이브러리를 위한 고수준 R 바인딩을 제공합니다. 인기 있는 htmlwidgets로는 Plotly, Leaflet, dygraphs 등이 있습니다.
htmlwidgets는 일반 R 플롯을 사용하는 것과 같은 방식으로 사용할 수 있습니다. 예를 들어, 아래는 Leaflet 지도를 임베드하는 방법입니다.
```{r}
library(leaflet)
leaflet() %>%
addTiles() %>%
addMarkers(lng=174.768, lat=-36.852,
popup="The birthplace of R")
```CRAN에는 htmlwidgets를 제공하는 수십 개의 패키지가 있습니다. 더 인기 있는 htmlwidgets의 예시는 htmlwidgets showcase에서 확인할 수 있으며, 사용 가능한 모든 위젯은 gallery에서 살펴볼 수 있습니다.
R Graphics
표준 R 래스터 그래픽(기본, lattice, grid 등)으로 만든 차트는 대시보드 안에서 사용할 수 있습니다. 정적 대시보드에서 표준 R 그래픽을 사용할 때는 플롯이 보여질 레이아웃에 맞도록 크기를 맞추는 데 조금 더 신경 써야 합니다. 반면, 인터랙티브 Shiny 대시보드에서는 모든 플롯 유형이 Shiny에 의해 동적으로 크기가 조정되므로 이 문제를 고려할 필요가 없습니다.
정적 대시보드에서 좋은 크기 조정 동작을 얻는 핵심은 knitr의 fig-width와 fig-height 옵션을 설정하여 플롯이 레이아웃 컨테이너에 최대한 가깝게 맞도록 하는 것입니다.
다음은 R 기본 그래픽으로 만든 3개의 차트를 포함하는 레이아웃 예시입니다.
## Row {height="65%"}
```{r}
#| fig-width: 10
#| fig-height: 8
plot(cars)
```
## Row {height="35%"}
```{r}
#| fig-width: 5
#| fig-height: 4
plot(pressure)
```
```{r}
#| fig-width: 5
#| fig-height: 4
plot(airmiles)
```각 플롯에 대해 fig-height와 fig-width를 명시하여 렌더링 결과가 레이아웃 컨테이너에 최대한 맞도록 했습니다. 이 값의 이상적인 크기는 보통 실험을 통해 결정해야 합니다.
정적 대시보드에서 JavaScript 기반 플롯을 사용할 때는 장단점이 있습니다. JavaScript 기반 플롯은 정적 플롯보다 컨테이너에 맞춰 리사이즈하는 동작이 우수하지만, 게시된 페이지에 기본 데이터가 직접 포함됩니다(플롯마다 데이터셋이 한 번씩 포함됨). 따라서 로드 시간이 느려질 수 있습니다.
대화형 Shiny 대시보드에서는 모든 플롯이 동적으로 크기가 조정되므로, 정적 대시보드에서처럼 리사이즈 동작을 걱정할 필요가 없습니다.
표
대시보드에서 데이터 테이블을 포함하는 방법은 두 가지입니다.
- 단순한 표 형식 표시로 제공
- 정렬과 필터링을 포함하는 인터랙티브 위젯으로 제공
아래에서는 대시보드에서 표를 포함할 때의 언어별 팁과 기법을 소개합니다.
표 형식 출력을 만드는 Python 패키지는 매우 많습니다. 아래에서는 더 인기 있는 라이브러리 두 가지(itables, tabulate)를 다룹니다.
itables
Python itables 패키지는 Pandas와 Polars 데이터프레임을 기반으로 정렬과 필터링이 가능한 인터랙티브 데이터 테이블을 만들 수 있습니다.
itables의 show() 메서드를 사용해 인터랙티브 테이블을 표시합니다.
```{python}
from itables import show
show(penguins)
```옵션
대시보드에서 카드 크기가 달라져도 잘 표시되도록, 일부 itables 옵션은 자동으로 설정됩니다. 기본 옵션은 다음과 같습니다.
from itables import options
options.dom = 'fiBrtlp'
options.maxBytes = 1024 * 1024
options.language = dict(info = "Showing _TOTAL_ entries")
options.classes = "display nowrap compact"
options.paging = False
options.searching = True
options.ordering = True
options.info = True
options.lengthChange = False
options.autoWidth = False
options.responsive = True
options.keys = True
options.buttons = []필요하다면 원하는 대로 다른 옵션을 지정해 기본값을 덮어쓸 수 있습니다. 옵션은 show() 호출에서 지정하거나 위와 같이 전역으로 지정할 수 있습니다. 아래는 show()에서 옵션을 지정하는 예입니다.
show(penguins, searching = False, ordering = False)모든 DataTables 옵션의 참고 문서는 여기에서 확인할 수 있습니다: https://datatables.net/reference/option/. 기본 옵션 외에도 다음 확장 옵션(Quarto가 자동으로 포함함)을 사용할 수 있습니다.
- https://datatables.net/extensions/buttons/
- https://datatables.net/extensions/keytable/
- https://datatables.net/extensions/responsive/
예를 들어, show() 호출에서 복사 및 내보내기(excel/pdf) 버튼을 활성화하려면 다음과 같이 합니다.
show(penguins, buttons = ['copy', 'excel', 'pdf'])또는 모든 테이블에 대해 해당 버튼을 활성화할 수도 있습니다.
from itables import options
options.buttons = ['copy', 'excel', 'pdf']다운샘플링
테이블이 표시될 때, 테이블 데이터는 대시보드 출력에 포함됩니다. 데이터셋이 큰 경우 대시보드가 너무 무거워지는 것을 방지하기 위해 itables는 maxBytes(기본값 1024kb)에 맞는 하위 집합만 표시합니다.
원한다면 maxBytes 값을 늘리거나 제한을 비활성화(maxBytes=0)할 수도 있습니다. 예를 들어 200kb 제한을 설정하려면 다음과 같이 합니다.
```{python}
show(penguins, maxBytes = 200 * 1024)
```tabulate
Python tabulate 패키지는 Pandas 데이터 프레임, NumPy 배열 및 기타 다양한 데이터 유형으로부터 마크다운 테이블을 생성할 수 있습니다. to_markdown() 메서드를 통해 어떤 Pandas 데이터 프레임이든 마크다운 테이블로 생성할 수 있습니다(IPython의 Markdown 출력으로 감싸야 합니다).
```{python}
import pandas as pd
from IPython.display import Markdown
penguins = pd.read_csv("penguins.csv")
Markdown(penguins.to_markdown(index=False))
```index = False 파라미터는 행 인덱스 표시를 숨깁니다. 아래는 tabulate 결과를 포함한 카드의 예입니다.
tabulate를 직접 가져와 객체를 전달해 출력할 수도 있습니다.
```{python}
from tabulate import tabulate
Markdown(
tabulate(penguins, showindex=False,
headers=penguins.columns)
)
```표 형식 출력을 만드는 R 패키지 역시 많습니다. 아래에서는 더 인기 있는 접근 두 가지(kable, DT)를 다룹니다.
kable
단순 마크다운 테이블은 비교적 작은 레코드 수(약 20~250행)에 적합합니다. knitr::kable() 함수를 사용해 마크다운 테이블을 출력합니다.
```{r}
knitr::kable(mtcars)
```대시보드의 단순 마크다운 테이블은 컨테이너를 자동으로 채우며, 필요에 따라 가로 및 세로로 스크롤됩니다.
DT
DT 패키지는 DataTables JavaScript 라이브러리에 대한 인터페이스로, R의 행렬이나 데이터 프레임을 필터링, 페이지네이션, 정렬을 지원하는 인터랙티브 HTML 테이블로 표시할 수 있습니다.
DataTable을 포함하려면 DT::datatable 함수를 사용합니다.
```{r}
library(DT)
datatable(mtcars)
```옵션
대시보드에서 카드 크기가 달라져도 잘 표시되도록, 일부 DT 옵션은 자동으로 설정됩니다. 기본 옵션은 다음과 같습니다.
options(DT.options = list(
bPaginate = FALSE,
dom = "ifrt",
language = list(info = "Showing _TOTAL_ entries")
))필요하다면 원하는 대로 다른 옵션을 지정해 기본값을 덮어쓸 수 있습니다.
값 상자
값 상자는 대시보드에서 단순한 값을 눈에 띄게 표시하는 좋은 방법입니다. 예를 들어, 아래는 세 개의 값 상자가 있는 대시보드 행입니다.
다음은 이 값 상자를 만들 때 사용할 수 있는 코드입니다. 이 예시는 각 언어의 문법을 보여주기 위해 Python과 R 셀을 함께 사용했습니다. 또한 articles, comments, spam 변수는 문서 앞부분에서 미리 계산되어 있다고 가정합니다.
## Row
```{python}
#| content: valuebox
#| title: "Articles per day"
#| icon: pencil
#| color: primary
dict(
value = articles
)
```
```{python}
#| content: valuebox
#| title: "Comments per day"
dict(
icon = "chat",
color = "primary",
value = comments
)
```
```{r}
#| content: valuebox
#| title: "Spam per day"
list(
icon = "trash",
color = "danger",
value = spam
)
```값 상자 옵션은 YAML 또는 셀에서 출력하는 dict()/list()(각각 Python과 R) 안에 지정할 수 있습니다. 후자의 문법은 icon이나 color를 값에 따라 동적으로 지정해야 할 때 유용합니다.
아이콘과 색상
값 상자에서 사용하는 icon은 2,000개 이상의 bootstrap 아이콘 중에서 선택할 수 있습니다.
color는 어떤 CSS 색상 값이든 지정할 수 있지만, 대시보드에 맞춰 튜닝된 색상 별칭이 있으므로 기본값으로 고려해볼 수 있습니다.
| 색상 별칭 | 기본 테마 색상 |
|---|---|
primary |
파랑 |
secondary |
회색 |
success |
초록 |
info |
밝은 파랑 |
warning |
노랑/주황 |
danger |
빨강 |
light |
연한 회색 |
dark |
검정 |
사용자 정의 테마에서 값 상자 Sass 변수를 지정해 기본값을 덮어쓸 수 있습니다.
별칭은 모든 테마에 적용되지만, 이에 대응하는 색상 값은 테마마다 다릅니다.
Shiny
Shiny 인터랙티브 대시보드에서는 애플리케이션 상태에 따라 동적으로 업데이트되는 값 상자를 만들 수 있습니다. 자세한 방법은 언어별로 다릅니다.
@render.ui로 데코레이션한 함수 안에서 ui.value_box() 함수를 사용합니다. 예:
```{python}
from shiny.express import render, ui
@render.ui
def value():
return ui.value_box("Value", input.value())
```bslib::value_box() 함수를 사용하고, 필요하면 bsicons 패키지의 아이콘을 사용합니다. 예:
```{r}
library(bslib)
library(bsicons)
value_box(
title = "Value",
value = textOutput("valuetext"),
showcase = bs_icon("music-note-beamed")
)
```마크다운 문법
값 상자를 일반 마크다운으로도 만들 수 있으며, 이 경우 인라인 표현식을 사용해 값을 넣는 것이 일반적입니다. 예:
## Row
::: {.valuebox icon="pencil" color="blue"}
Articles per day
`{python} articles`
:::텍스트 콘텐츠
대시보드 카드에 플롯과 표를 채우는 경우가 많지만, 대시보드 어디에서나 임의의 마크다운 콘텐츠를 포함할 수도 있습니다.
콘텐츠 카드
아래는 한 열의 마지막 카드를 일반 마크다운으로 채운 대시보드 예시입니다.
이를 위해 다른 셀과 나란히 .card div를 포함하면 됩니다.
## Column
```{python}
#| title: Population
px.area(df, x="year", y="pop", color="continent",
line_group="country")
```
```{python}
#| title: Life Expectancy
px.line(df, x="year", y="lifeExp", color="continent",
line_group="country")
```
::: {.card}
Gapminder combines data from multiple sources into
unique coherent time-series that can’t be found
elsewhere. Learn more about the Gampminder dataset at
<https://www.gapminder.org/data/>.
:::Jupyter Notebook으로 작성하는 경우 마크다운 셀은 자동으로 .card div가 됩니다(즉, ::: div로 감쌀 필요가 없습니다).
셀 내부 콘텐츠
셀 출력과 함께 콘텐츠를 포함하려면 셀과 콘텐츠를 모두 .card div로 감싸면 됩니다. 예:
::: {.card title="Life Expectancy"}
```{python}
px.line(df, x="year", y="lifeExp", color="continent",
line_group="country")
```
Gapminder combines data from multiple sources into
unique coherent time-series that can’t be found
elsewhere. Learn more about the Gampminder dataset at
<https://www.gapminder.org/data/>.
:::선행 콘텐츠
대시보드의 최상단에 포함된 콘텐츠(그리고 .card div에 명시적으로 포함되지 않은 콘텐츠)는 선행 콘텐츠로 간주되며, 카드 스타일(예: 테두리) 없이 그대로 표시됩니다. 예:
---
title: "My Dashboard"
format: dashboard
---
This content will appear above all of the other
rows/columns, with no border.
## Row
```{python}
```동적 콘텐츠
인라인 표현식을 사용해 텍스트 콘텐츠를 동적으로 만들 수 있습니다. 예를 들어, 아래 행에서는 Python 표현식을 사용해 텍스트를 생성합니다.
::: {.card}
The sample size was `{python} sample`. The mean reported
rating was `{python} rating`.
:::셀 출력
노트북이나 소스 문서의 각 계산 셀 출력은 카드에 포함됩니다. 아래에서는 카드를 만들 때 적용되는 몇 가지 규칙을 설명합니다.
동적 제목
셀의 첫 번째 출력으로 title= 표현식을 출력하면(셀 옵션 YAML에서 title을 지정하는 것과 대비), 동적인 title을 만들 수 있습니다. 예:
```{python}
from ipyleaflet import Map, basemaps, basemap_to_tiles
lat = 48
long = 350
print("title=", f"World Map at {lat}, {long}")
Map(basemap=basemap_to_tiles(basemaps.OpenStreetMap.Mapnik),
center=(lat, long), zoom=2)
``````{r}
library(leaflet)
lat <- 48
long <- 350
cat("title=", "World Map at", lat, long)
leaflet() |> addTiles() |>
setView(long, lat, zoom = 2)
```제외된 셀
출력을 생성하지 않는 셀은 카드가 되지 않습니다(예: 패키지 로드, 데이터 불러오기 및 필터링에 사용하는 셀). 셀이 예상치 못한 출력을 생성해 제외하고 싶다면 셀에 output: false 옵션을 추가하세요.
```{python}
#| output: false
# (code that produces unexpected output)
```표현식 출력
기본적으로 최상위 표현식의 모든 출력이 대시보드에 표시됩니다. 따라서 하나의 셀에서 여러 개의 플롯을 쉽게 생성할 수 있습니다. 예:
```{python}
#| title: "Tipping Behavior"
px.box(df, x="sex", y="total_bill", color="smoker")
px.violin(df, x="sex", y="total_bill", color="smoker")
```이 동작은 Jupyter 셸 상호작용의 "all" 설정에 해당합니다. Quarto에서는 ipynb-shell-interactivity 옵션으로 이 동작을 사용자 정의할 수 있습니다.
카드 레이아웃
셀이 여러 출력을 생성하는 경우, 셀 레이아웃 옵션을 사용해 표시를 정리할 수 있습니다. 예를 들어, 아래에서는 layout-ncol 옵션을 사용해 플롯을 나란히 배치합니다.
```{python}
#| title: "Tipping Behavior"
#| layout-ncol: 2
px.box(df, x="sex", y="total_bill", color="smoker")
px.violin(df, x="sex", y="total_bill", color="smoker")
```추가적인 사용자 정의 레이아웃 문서는 그림 문서를 참고하세요.
더 알아보기
Layout는 탐색 모음을 제어하고, 페이지, 행, 열, 탭셋, 카드로 콘텐츠를 배치하는 방법을 보여줍니다.
Inputs는 인터랙티브 대시보드에서 입력을 배치하는 다양한 방법(사이드바, 툴바, 입력을 카드에 직접 연결하는 방식 등)을 보여줍니다.
Examples는 참고할 수 있는 대시보드 예시 갤러리를 제공합니다.
Theming는 대시보드 외관의 글꼴, 색상, 레이아웃 등 다양한 커스터마이징 방법을 설명합니다.
Parameters는 매개변수를 정의하고 명령줄에서 서로 다른 값을 제공해 대시보드 변형을 만드는 방법을 설명합니다.
Deployment는 정적 대시보드(웹 호스트만 필요하고 서버는 필요 없음)와 Shiny 대시보드(Shiny Server 필요) 모두의 배포 방법을 다룹니다.
Interactivity는 더 유연한 데이터 탐색을 가능하게 하는 인터랙티브 기능을 만드는 다양한 방법을 살펴봅니다.










