Praktikum Dashboard Interaktif
Setelah praktikum ini, Anda mampu:
- Menjelaskan perbedaan antara Shiny biasa dan
shinydashboard. - Membangun struktur layout dashboard (header, sidebar, body).
- Menampilkan beberapa visualisasi sekaligus dalam satu dashboard.
- Mengintegrasikan elemen interaktif (input dan output reaktif) dalam dashboard.
- Mendistribusikan aplikasi dashboard ke shinyapps.io.
Catatan: Kode di halaman ini dijalankan di RStudio. Salin blok kode ke file app.R, lalu klik Run App.
1. Shinydashboard vs Shiny Biasa
shinydashboard adalah ekstensi Shiny yang menyediakan template dashboard siap pakai, lengkap dengan header, sidebar menu, dan kotak konten (box).
Instalasi
install.packages("shiny")
install.packages("shinydashboard")
install.packages("ggplot2")
install.packages("DT")Perbandingan Struktur
| Shiny Biasa | shinydashboard | |
|---|---|---|
| Layout utama | fluidPage() |
dashboardPage() |
| Navigasi | tabsetPanel() |
dashboardSidebar() + menuItem() |
| Konten | Bebas | Dalam box() |
| Tampilan | Minimalis | Dashboard profesional |
Gunakan shinydashboard ketika:
(1) Ada banyak visualisasi yang perlu diatur dalam satu halaman
(2) Dibutuhkan navigasi antar halaman/tab
(3) Audiens mengharapkan tampilan seperti business intelligence dashboard
Cukup gunakan shiny biasa untuk aplikasi dengan satu atau dua visualisasi sederhana.
Pertanyaan: Jika Anda hanya perlu menampilkan satu histogram interaktif, apakah perlu shinydashboard?
2. Struktur Dasar Dashboard
library(shiny)
library(shinydashboard)
library(ggplot2)
library(DT)
# ───── UI ──────────────────────────────────────────────────
ui <- dashboardPage(
# 1. Header: judul di pojok kiri atas
dashboardHeader(title = "Dashboard Analisis Data"),
# 2. Sidebar: menu navigasi
dashboardSidebar(
sidebarMenu(
menuItem("Beranda", tabName = "beranda", icon = icon("home")),
menuItem("Tabel Data", tabName = "tabel_data", icon = icon("table"))
)
),
# 3. Body: konten tiap tab
dashboardBody(
tabItems(
# Tab 1: Beranda
tabItem(tabName = "beranda",
fluidRow(
box(title = "Histogram", status = "primary", solidHeader = TRUE,
width = 8,
plotOutput("plot_histogram", height = 300)),
box(title = "Kontrol", status = "warning", solidHeader = TRUE,
width = 4,
sliderInput("bins", "Jumlah Bin:", min = 5, max = 50, value = 20))
)
),
# Tab 2: Tabel Data
tabItem(tabName = "tabel_data",
fluidRow(
box(title = "Dataset faithful", status = "primary", solidHeader = TRUE,
width = 12,
DTOutput("tabel_data"))
)
)
)
)
)
# ───── Server ──────────────────────────────────────────────
server <- function(input, output) {
output$plot_histogram <- renderPlot({
x <- faithful$eruptions
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = "steelblue", border = "white",
main = "Durasi Letusan Geyser Old Faithful",
xlab = "Durasi (menit)")
})
output$tabel_data <- renderDT({
datatable(faithful, options = list(pageLength = 10))
})
}
shinyApp(ui = ui, server = server)status: warna garis atas box,"primary"(biru),"warning"(kuning),"danger"(merah),"success"(hijau)
solidHeader = TRUE: mengisi header box dengan warna penuh (lebih mencolok)
width: lebar dalam grid 12 kolom Bootstrap,width = 6artinya setengah layar
Pertanyaan: Apa yang terjadi jika dua box dalam satu fluidRow() memiliki width = 8 dan width = 6? (Total > 12)
3. Dashboard dengan Beberapa Tab dan Visualisasi
library(shiny)
library(shinydashboard)
library(ggplot2)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Dashboard mtcars"),
dashboardSidebar(
sidebarMenu(
menuItem("Histogram", tabName = "hist", icon = icon("chart-bar")),
menuItem("Scatter Plot", tabName = "scatter", icon = icon("circle-dot")),
menuItem("Data", tabName = "data", icon = icon("table"))
)
),
dashboardBody(
tabItems(
# Tab 1: Histogram
tabItem(tabName = "hist",
fluidRow(
box(title = "Kontrol", status = "warning", solidHeader = TRUE, width = 4,
selectInput("var_hist", "Variabel:",
choices = colnames(mtcars)[sapply(mtcars, is.numeric)],
selected = "mpg"),
sliderInput("bins_hist", "Jumlah Bin:", min = 5, max = 50, value = 15)
),
box(title = "Histogram", status = "primary", solidHeader = TRUE, width = 8,
plotOutput("histogram"))
)
),
# Tab 2: Scatter Plot
tabItem(tabName = "scatter",
fluidRow(
box(title = "Kontrol", status = "warning", solidHeader = TRUE, width = 4,
selectInput("xvar", "Sumbu X:",
choices = colnames(mtcars)[sapply(mtcars, is.numeric)],
selected = "wt"),
selectInput("yvar", "Sumbu Y:",
choices = colnames(mtcars)[sapply(mtcars, is.numeric)],
selected = "mpg"),
checkboxInput("reg_line", "Garis regresi", value = FALSE)
),
box(title = "Scatter Plot", status = "primary", solidHeader = TRUE, width = 8,
plotOutput("scatter"),
textOutput("korelasi_teks"))
)
),
# Tab 3: Tabel
tabItem(tabName = "data",
fluidRow(
box(title = "Dataset mtcars", status = "primary", solidHeader = TRUE,
width = 12, DTOutput("tabel"))
)
)
)
)
)
server <- function(input, output) {
output$histogram <- renderPlot({
x <- mtcars[[input$var_hist]]
bins <- seq(min(x), max(x), length.out = input$bins_hist + 1)
hist(x, breaks = bins, col = "steelblue", border = "white",
main = paste("Histogram:", input$var_hist), xlab = input$var_hist)
})
output$scatter <- renderPlot({
x <- mtcars[[input$xvar]]
y <- mtcars[[input$yvar]]
plot(x, y, pch = 16, col = "steelblue", cex = 1.2,
xlab = input$xvar, ylab = input$yvar,
main = paste(input$xvar, "vs", input$yvar))
if (input$reg_line) abline(lm(y ~ x), col = "tomato", lwd = 2)
})
output$korelasi_teks <- renderText({
r <- cor(mtcars[[input$xvar]], mtcars[[input$yvar]])
paste("Korelasi Pearson:", round(r, 4))
})
output$tabel <- renderDT({
datatable(mtcars, options = list(pageLength = 10, scrollX = TRUE))
})
}
shinyApp(ui = ui, server = server)tabName di menuItem() harus persis sama dengan tabName di tabItem(). Shiny menggunakan string ini sebagai penghubung antara klik menu dan konten yang ditampilkan. Kesalahan ejaan akan membuat tab tidak muncul tanpa pesan error.
Pertanyaan: Jika dua menuItem() memiliki tabName yang sama, apa yang terjadi?
4. Mendistribusikan Dashboard ke Shinyapps.io
Setelah dashboard selesai, Anda bisa membagikannya melalui internet menggunakan shinyapps.io (gratis untuk penggunaan terbatas).
Langkah-langkah
# Langkah 1: Install paket rsconnect
install.packages("rsconnect")
# Langkah 2: Hubungkan akun shinyapps.io
# (token tersedia di dashboard shinyapps.io → Account → Tokens)
library(rsconnect)
rsconnect::setAccountInfo(
name = "<USERNAME_ANDA>",
token = "<TOKEN_ANDA>",
secret = "<SECRET_ANDA>"
)
# Langkah 3: Deploy aplikasi
rsconnect::deployApp("path/ke/folder/app")- Buka shinyapps.io dan buat akun gratis
- Login: klik nama pengguna di pojok kanan atas: Tokens
- Klik Show untuk melihat token dan secret
- Salin dan tempel ke
rsconnect::setAccountInfo()
Alternatif: di RStudio, klik Publish (ikon biru) di pojok kanan atas editor saat file app.R terbuka.
Pertanyaan: Apa batasan akun gratis shinyapps.io yang perlu diperhatikan sebelum deploy?
5. Latihan
Latihan 1: Tambahkan valueBox di Beranda
valueBox menampilkan angka ringkasan (seperti total, rata-rata) di kotak kecil yang mencolok, umum dalam dashboard bisnis.
Tambahkan tiga valueBox di Tab “Beranda” pada dashboard Bagian 2 yang menampilkan mean, min, dan max dari variabel yang dipilih.
# Tambahkan di fluidRow baru di Tab beranda (UI):
fluidRow(
valueBox(
value = textOutput("mean_val"),
subtitle = "Rata-rata",
icon = icon("___"), # pilih ikon: "calculator", "chart-line", dll.
color = "blue"
),
valueBox(
value = textOutput("min_val"),
subtitle = "Minimum",
icon = icon("arrow-down"),
color = "___" # pilih warna: "red", "yellow", "green"
),
valueBox(
value = textOutput("max_val"),
subtitle = "Maksimum",
icon = icon("arrow-up"),
color = "green"
)
)
# Tambahkan di server:
output$mean_val <- renderText({ round(mean(faithful$eruptions), 2) })
output$min_val <- renderText({ round(___(faithful$eruptions), 2) }) # isi fungsi
output$max_val <- renderText({ round(___(faithful$eruptions), 2) }) # isi fungsi# UI:
icon("calculator"), color = "blue"
color = "red"
# Server:
output$min_val <- renderText({ round(min(faithful$eruptions), 2) })
output$max_val <- renderText({ round(max(faithful$eruptions), 2) })Warna yang tersedia: "blue", "black", "purple", "green", "yellow", "red", "orange", "navy", "teal", "olive", "lime", "fuchsia", "maroon", "aqua".
Latihan 2: Tambahkan Tab Baru “Boxplot”
Tambahkan tab ketiga pada dashboard Bagian 3 yang menampilkan boxplot dari variabel mtcars yang dipilih pengguna.
# Di dashboardSidebar, tambahkan:
menuItem("Boxplot", tabName = "___", icon = icon("box"))
# Di dashboardBody, tambahkan tabItem baru:
tabItem(tabName = "___",
fluidRow(
box(title = "Kontrol Boxplot", status = "warning", solidHeader = TRUE, width = 4,
selectInput("var_box", "Variabel:",
choices = colnames(mtcars)[sapply(mtcars, is.numeric)])
),
box(title = "Boxplot", status = "primary", solidHeader = TRUE, width = 8,
plotOutput("boxplot_out"))
)
)
# Di server, tambahkan:
output$boxplot_out <- renderPlot({
boxplot(
mtcars[[input$var_box]],
col = "___", # pilih warna
main = paste("Boxplot:", input$var_box),
ylab = input$var_box
)
})# tabName yang konsisten antara menuItem dan tabItem:
tabName = "boxplot"
# renderPlot untuk boxplot:
output$boxplot_out <- renderPlot({
boxplot(
mtcars[[input$var_box]],
col = "steelblue",
main = paste("Boxplot:", input$var_box),
ylab = input$var_box
)
})Latihan 3: Dashboard Lengkap dari Awal
Buat dashboard baru menggunakan dataset iris (bawaan R) dengan spesifikasi:
- Tab 1 “Eksplorasi”: scatter plot sepal length vs sepal width, diwarnai berdasarkan
Species - Tab 2 “Distribusi”: histogram salah satu variabel numerik (bisa dipilih lewat dropdown)
- Tab 3 “Data”: tabel lengkap dataset
iris
library(shiny)
library(shinydashboard)
library(DT)
# Variabel numerik iris
var_iris <- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")
ui <- dashboardPage(
dashboardHeader(title = "___"), # isi judul dashboard
dashboardSidebar(
sidebarMenu(
menuItem("Eksplorasi", tabName = "___", icon = icon("circle-dot")),
menuItem("Distribusi", tabName = "___", icon = icon("chart-bar")),
menuItem("Data", tabName = "___", icon = icon("table"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "___", # Tab 1: Scatter plot iris
fluidRow(
box(title = "Scatter Iris", status = "primary", solidHeader = TRUE,
width = 12, plotOutput("scatter_iris"))
)
),
tabItem(tabName = "___", # Tab 2: Histogram
fluidRow(
box(title = "Kontrol", status = "warning", solidHeader = TRUE, width = 4,
selectInput("var_dist", "Variabel:", choices = ___)),
box(title = "Histogram", status = "primary", solidHeader = TRUE, width = 8,
plotOutput("hist_iris"))
)
),
tabItem(tabName = "___", # Tab 3: Tabel
fluidRow(
box(width = 12, DTOutput("tabel_iris"))
)
)
)
)
)
server <- function(input, output) {
output$scatter_iris <- renderPlot({
plot(iris$Sepal.Length, iris$Sepal.Width,
col = as.integer(iris$Species),
pch = 16, cex = 1.2,
xlab = "Sepal Length", ylab = "Sepal Width",
main = "Scatter: Sepal Length vs Sepal Width")
legend("topright", legend = levels(iris$Species),
col = 1:3, pch = 16)
})
output$hist_iris <- renderPlot({
x <- iris[[input$var_dist]]
hist(x, col = "steelblue", border = "white",
main = paste("Distribusi:", input$var_dist),
xlab = input$var_dist)
})
output$tabel_iris <- renderDT({
datatable(___, options = list(pageLength = 10)) # isi nama dataset
})
}
shinyApp(ui = ui, server = server)# Header:
dashboardHeader(title = "Dashboard Iris")
# tabName yang konsisten (contoh):
# menuItem → tabName = "eksplorasi", "distribusi", "data"
# tabItem → tabName = "eksplorasi", "distribusi", "data"
# choices untuk histogram:
choices = var_iris
# Dataset untuk tabel:
datatable(iris, options = list(pageLength = 10))Pastikan setiap tabName di menuItem() sama persis dengan tabName di tabItem() yang sesuai.
Ringkasan: Komponen Utama shinydashboard
| Komponen | Fungsi |
|---|---|
dashboardPage() |
Pembungkus utama aplikasi |
dashboardHeader() |
Bar atas dengan judul |
dashboardSidebar() + sidebarMenu() |
Menu navigasi kiri |
menuItem() |
Satu item navigasi |
dashboardBody() + tabItems() |
Area konten utama |
tabItem() |
Konten satu tab |
box() |
Kotak konten dengan judul & warna |
valueBox() |
Kotak angka ringkasan |
fluidRow() |
Baris dalam grid 12 kolom |