Membuat Statistik Menjadi Dinamis dan Interaktif

Statistik bukan hanya untuk statistikawan tetapi juga untuk orang awam. Untuk itu, statistik perlu dikemas secara lebih menarik dan menawan. Shiny memungkinkan agar statistik disajikan secara dinamis dan interaktif agar menarik dan mudah dipelajari oleh orang awam.

statistik dunia
tutorial
visualisasi data
Pengarang
Afiliasi
Terbit

August 10, 2024

Kata kunci

Shiny, Gapminder, harapan hidup, produk domestik bruto, PDB, diagram pencar

Jelajah data itu seringkali kompleks dan menantang. Apalagi yang kita jelajahi adalah data raya. Apakah penjelajahan data tersebut dapat kita buat menjadi lebih mudah dan menarik? Artikel blog ini akan mendemonstrasikan bagaimana mengembangkan aplikasi Shiny untuk menjelajah data dari pos sebelumnya.

Kita berkenalan dengan Shiny terlebih dahulu. Shiny adalah sebuah cara yang memungkinkan kita untuk membuat aplikasi berbasis web dengan bahasa pemrograman R (atau Python). Shiny ini cocok bagi kamu yang baru awal-awal memelajari R maupun yang sudah lama dan lihai menggunakan bahasa pemrograman itu.

Mengapa Perlu Aplikasi Shiny?

Bayangkan kamu adalah seorang analis data. Kamu sedang menganalisis data Gapminder dengan R. Tujuannya adalah untuk melihat hubungan antara PDB (Pendapatan Domestik Bruto) per kapita dan angka harapan hidup berbagai negara. Pertama, kamu panggil dulu paket yang diperlukan. Paket tersebut adalah {tidyverse}.

library(tidyverse)

Setelah itu, kamu impor data yang tersedia secara daring dengan menggunakan fungsi load() dan url(). Hasilnya, kamu mendapatkan data dengan nama gapminder.

load(url("https://github.com/jennybc/gapminder/raw/main/data/gapminder.rdata"))

Data tersebut memiliki enam variabel, yaitu negara (country), benua (continent), tahun (year), angka harapan hidup (lifeExp), dan PDB per kapita (gdpPercap, dalam dolar internasional). Tak ingin berlama-lama, kamu langsung memvisualisasikan hubungan antara PDB per kapita dan angka harapan hidup dengan diagram pencar. Hasilnya ditunjukkan pada Gambar 1.

gapminder |> 
  ggplot(aes(x = gdpPercap, y = lifeExp)) + 
  geom_point()
Gambar 1: Hubungan antara PDB per kapita dan angka harapan hidup berbagai negara

Sayangnya, Gambar 1 menggambarkan semua titik datanya. Padahal, kamu ingin menggambarkan titik-titik pada tahun tertentu saja. Untuk itu, kamu perlu mengetahui tahun berapa saja yang tersedia dalam data.

unique(gapminder$year)
 [1] 1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 2002 2007

Tahunnya ternyata mulai dari 1952 sampai 2007 dengan interval lima tahun. Selanjutnya, kamu ingin menggambar seperti pada Gambar 1 tetapi hanya untuk tahun 2007. Keinginanmu ini terwujud dengan menjalankan baris kode di bawah. Hasilnya tersaji pada Gambar 2.

gapminder |> 
  filter(year == 2007) |> 
  ggplot(aes(x = gdpPercap, y = lifeExp)) + 
  geom_point()
Gambar 2: Hubungan antara PDB per kapita dan angka harapan hidup berbagai negara pada tahun 2007

Dalam baris kode di atas, terdapat perintah filter(year == 2007). Kode tersebut berguna untuk memfilter datanya agar nilai variabel year-nya sama dengan 2007.

Sekarang kamu ingin memvisualisasikan lagi data tersebut tetapi untuk tahun 2002. Caranya mudah. Kamu tinggal mengganti 2007 dengan 2002 dalam fungsi filter() di atas. Alternatifnya, kamu dapat membuat sebuah variabel baru, misalnya tahun_int, dan membuat nilainya menjadi 2002. Setelah itu, kamu ganti 2007 dalam fungsi filter() di atas dengan variabel tersebut. Alhasil, kamu mendapatkan diagram pencar seperti yang ditunjukkan Gambar 3.

# Variabel `tahun_int` dan nilainya sama dengan 2002
tahun_int <- 2002

# Memvisualisasikan data untuk tahun 2002
gapminder |> 
  filter(year == tahun_int) |> 
  ggplot(aes(x = gdpPercap, y = lifeExp)) + 
  geom_point()
Gambar 3: Hubungan antara PDB per kapita dan angka harapan hidup berbagai negara pada tahun 2002

Bagaimana jika kamu ingin membuat visualisasi data untuk tahun 1997? Kamu ganti nilai variabel tahun_int dengan 1997 dan jalankan baris kodenya. Bagaimana untuk tahun-tahun lainnya? Caranya sama:

  1. kamu ganti nilai varibel tahun_int dengan tahun yang kamu mau, dan kemudian

  2. jalankan lagi baris kodenya.

Dua langkah tersebut perlu dilakukan agar kamu dapat memvisualisasikan data untuk tahun-tahun tertentu. Adakah cara yang lebih efisien? Adakah cara agar langkah kedua di atas otomatis dijalankan ketika kamu mengganti nilai variabel tahun_int? Tentu saja ada! Caranya adalah dengan menggunakan Shiny.

Shiny menggunakan pemrograman yang reaktif. Artinya, Shiny akan secara otomatis menjalankan baris perintah untuk menghasilkan luaran ketika nilai inputnya diganti. Dalam kasusmu ini, inputnya adalah nilai variabel tahun_int dan luarannya adalah diagram pencar seperti pada Gambar 2 atau Gambar 3. Dengan demikian, Shiny akan langsung membuat diagram pencar seperti itu ketika nilai variabel tahun_int kamu ganti.

Membuat Aplikasi Shiny

Kamu telah mengenal Shiny. Sekarang kita akan membuat aplikasi Shiny berdasarkan proses analisis data yang dipaparkan pada Bagian 1. Karena kita akan menggunakan paket {shiny}, paket tersebut perlu terpasang di komputermu. Jika belum, kamu perlu memasangnya dengan perintah berikut.

install.packages("shiny")

Aku menyarankanmu untuk membuat aplikasi Shiny dengan RStudio agar lebih mudah. Di RStudio, kamu dapat membuat aplikasi Shiny dengan mengklik File | New File | Shiny Web App… Pada jendela New Shiny Web Application, tuliskan nama aplikasinya dan klik Create. Setelah itu, kamu akan mendapatkan fail app.R yang isinya seperti ini.

app.R
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    https://shiny.posit.co/
#

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Old Faithful Geyser Data"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

        # Show a plot of the generated distribution
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

    output$distPlot <- renderPlot({
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white',
             xlab = 'Waiting time to next eruption (in mins)',
             main = 'Histogram of waiting times')
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

Baris kode di atas adalah baris kode yang sudah lengkap untuk sebuah aplikasi. Tetapi, aplikasi tersebut tidak sesuai dengan tujuanmu, yaitu memvisualisasikan hubungan antara PDB per kapita dan angka harapan hidup. Untuk itu, hapus semua baris kode di atas dan ganti dengan baris kode seperti pada Daftar 1 berikut.

Daftar 1: Baris kode di dalam app.R
app.R
library(shiny)
library(tidyverse)
load(url("https://github.com/jennybc/gapminder/raw/main/data/gapminder.rdata"))

ui <- fluidPage(
  sliderInput(
    inputId = "tahun",
    label = "Tahun",
    min = 1952,
    max = 2007,
    value = 2007,
    step = 5
  ),
  plotOutput("diagram_pencar")
)

server <- function(input, output, session) {
  output$diagram_pencar <- renderPlot({
    tahun_int <- input$tahun
    
    gapminder |> 
      filter(year == tahun_int) |> 
      ggplot(aes(x = gdpPercap, y = lifeExp)) + 
      geom_point()
    
  })
}

shinyApp(ui = ui, server = server)

Aplikasi app.R tersebut memuat baris kode yang melakukan empat hal sebagai berikut.

  1. Baris kode tersebut memanggil paket {shiny} dan {tidyverse} melalui perintah library(shiny) dan library(tidyverse). Selain itu, baris kode tersebut juga mengimpor data gapminder dengan perintah load(url("https://github.com/jennybc/gapminder/raw/main/data/gapminder.rdata")).

  2. Baris kode tersebut membuat antarmuka (ui): laman yang menjadi tempat berinteraksinya pengguna. Ada tiga fungsi yang digunakan untuk membuat antarmuka tersebut, yaitu fluidPage(), sliderInput(), dan plotOutput(). Lebih lengkapnya akan dijelaskan pada Bagian 2.1.

  3. Baris kode tersebut menentukan perilaku dari aplikasi tersebut dengan fungsi server. Pembahasan lebih lanjut dapat dilihat pada Bagian 2.2.

  4. Baris kode yang terakhir, yaitu shinyApp(ui = ui, server = server), berfungsi untuk membuat aplikasi Shiny berdasarkan antarmuka ui dan fungsi server dan kemudian menjalankannya.

Apabila kamu sudah penasaran dengan aplikasi Shiny tersebut, kamu dapat menjalankannya. Untuk melakukannya di RStudio, klik tombol Run App yang terletak di bagian kanan-atas dokumen. Perhatikan Gambar 4!

Tombol Run App dalam RStudio
Gambar 4: Tombol Run App yang dapat ditemukan di bagian kanan-atas dokumen

Setelah kamu mengklik tombol tersebut, beberapa saat kamu dapat melihat aplikasi tersebut. Tampilannya ditunjukkan pada Gambar 5.

Gambar 5: Tampilan aplikasi Shiny

Kamu dapat berinteraksi dengan aplikasi tersebut. Silakan geser-geser slidernya (bagian kiri-atas aplikasi dengan label “Tahun”) untuk mengubah tahunnya. Ketika tahun tersebut kamu ganti, kamu dapat melihat tampilan diagram pencarnya juga menyesuaikan. Untuk menutup aplikasi tersebut, klik tombol Close yang terletak di sebelah kanan-atas.

Antarmuka Aplikasi Shiny

Salah satu bagian baris kode aplikasi Shiny adalah kode antarmukanya. Pada baris kode Daftar 1, pendefinisian antarmukanya ada di ui. Terdapat tiga fungsi yang digunakan, yaitu fluidPage(), sliderInput(), dan plotOutput().

  • fluidPage() merupakan fungsi tata letak. Fungsi ini mengatur tata letak dari tampilan aplikasi Shiny kita.

  • sliderInput() merupakan salah satu kontrol input. Fungsi ini memungkinkan pengguna untuk berinteraksi dengan aplikasi kita. Dengan menggeser-geser slidernya, pengguna menyediakan input bagi aplikasi kita. Terdapat enam argumen yang kita isikan dalam fungsi tersebut. Argumen inputId = "tahun" memberikan identitas terhadap slider tersebut. Identitas ini selanjutnya digunakan lagi dalam fungsi server nantinya. Argumen label="Tahun" berfungsi untuk memberikan label terhadap slider tersebut. Label ini ditampilkan dalam antarmuka aplikasi kita. Argumen min = 1952 , max = 2007, dan step = 5 memberikan nilai-nilai yang mungkin untuk inputnya, yaitu bilangan mulai dari 1952 sampai 2007 dengan interval 5. Terakhir, value = 2007 memberikan nilai awal untuk slider tersebut.

  • plotOutput() merupakan salah satu kontrol luaran aplikasi Shiny. Fungsi ini memberitahu Shiny tempat meletakkan luaran plot yang memiliki identitas diagram_pencar.

Dapur Aplikasi Shiny

Bagian 2.1 telah menunjukkan adanya input dan luaran dalam aplikasi Shiny kita. Dari input menjadi luaran, terdapat proses komputasi yang dilakukan di dapur Shiny. Proses ini kita tentukan di dalam fungsi server.

Di dalam fungsi server, kita memberikan resep kepada Shiny untuk melakukan komputasi. Ruas kiri dari operator <-, yaitu output$diagram_pencar, mengindikasikan bahwa kita memberikan resep untuk luaran dengan identitas diagram_pencar.

Ruas kanan operator <- merupakan fungsi render. Fungsi render ini bermacam-macam jenisnya, tergantung dari luarannya. Karena di antarmuka kita akan membuat plot dengan plotOutput, kita perlu menggunakan fungsi renderPlot() di sini.

Logika di dalam fungsi renderPlot() sama dengan logika yang kita gunakan pada Bagian 1, tetapi dengan sedikit penambahan. Penambahannya adalah pada tahun_int <- input$tahun. Kode ini berfungsi untuk memberikan nilai sebesar input$tahun kepada variabel tahun_int. Nilai input$tahun tersebut tergantung dari nilai yang diberikan oleh pengguna terhadap slider dengan identitas tahun pada antarmuka.

Alur kerja aplikasi Shiny kita ringkasnya seperti ini. Pertama, pengguna melihat antarmuka aplikasi kita. Di situ dia dapat menggeser slider dengan identitas tahun untuk mengganti-ganti nilanya. Nilai ini kemudian dikirim ke dapur Shiny dalam rupa input$tahun untuk diolah di dalam fungsi render, yaitu renderPlot(). Olahan tersebut menghasilkan luaran yang disebut dengan output$diagram_pencar. Luaran ini kemudian dikirimkan lagi ke antarmuka agar dapat dilihat oleh pengguna. Di mana posisinya? Posisinya terletak di mana plotOutput("diagram_pencar") berada.

Sentuhan Akhir

Aplikasi Shiny kita masih sederhana dan seperlunya. Kita dapat memperindah aplikasi tersebut. Beberapa hal yang dapat kita lakukan antara lain

  • menambahkan judul ke dalam antarmukanya,

  • mengatur slidernya agar menampilkan bilangan yang tidak memuat pemisah ribuan, dan

  • memperbaiki diagram pencar yang disajikan agar tampilannya sama dengan diagram pencar pada pos sebelumnya, serta mengatur agar batasan jendelanya konsisten dari tahun ke tahun.

Ketiga hal tersebut dapat kita penuhi dengan baris kode seperti pada Daftar 2 berikut.

Daftar 2: Baris kode di dalam app.R
app.R
library(shiny)
library(tidyverse)
load(url("https://github.com/jennybc/gapminder/raw/main/data/gapminder.rdata"))

ui <- fluidPage(
  titlePanel("PDB per Kapita vs. Angka Harapan Hidup"),
  sliderInput(
    inputId = "tahun",
    label = "Tahun",
    min = 1952,
    max = 2007,
    value = 2007,
    step = 5,
    sep = ""
  ),
  plotOutput("diagram_pencar")
)

server <- function(input, output, session) {
  output$diagram_pencar <- renderPlot({
    tahun_int <- input$tahun
    
    gapminder |> 
      filter(year == tahun_int) |> 
      ggplot(
        aes(x = gdpPercap, y = lifeExp)
      ) + 
      geom_point(
        aes(color = continent, size = pop),
        alpha = .6
      ) + 
      scale_size(
        range = c(5, 30),
        guide = "none"
      ) + 
      scale_color_viridis_d(name = "Benua") + 
      theme_minimal(base_size = 18) + 
      theme(
        legend.position = "bottom",
        plot.title = element_text(face = "bold")
      ) + 
      xlim(c(200, 60000)) + 
      ylim(c(20, 90)) + 
      labs(
        x = "PDB per kapita",
        y = "Angka harapan hidup",
        caption = "Data: Jenny Bryan dkk. / Github"
      )
    
  })
}

shinyApp(ui = ui, server = server)

Bagaimana tampilan aplikasi Shiny kita sekarang? Tampilannya ditunjukkan pada Gambar 6.

Gambar 6: Tampilan aplikasi Shiny setelah dilakukan sentuhan akhir

Catatan Akhir

Kita telah mengenal Shiny. Kita secara bersama-sama juga telah membuat aplikasi Shiny sederhana pada Bagian 2 dan memberikan sentuhan akhir pada Bagian 3. Aplikasi tersebut dapat menampilkan visualisasi data secara interaktif. Dengan cara demikian, harapannya statistik tidak hanya menjadi konsumsi statistikawan tetapi juga orang awam.

Apa selanjutnya? Jika kamu tertarik untuk mengembangkan aplikasi Shiny, kamu dapat belajar dari contoh-contohnya. Contoh tersebut dapat kamu lihat di laman galeri Shiny untuk R. Selain itu, kamu juga dapat menjelajah beberapa aplikasi Shiny yang telah aku kembangkan. Have a shiny day!

Penggunaan Kembali