Latar Belakang

Proyek ini merupakan proyek yang terdapat pada DQLAB, dimana merupakan hasil eksplorasi sederhana terhadap data Covid-19 di Indonesia, Data yang digunakan diambil langsung dari API (Application Programming Interface) yang tersedia di covid19.go.id. Sehingga dalam proyek ini akan mempelajari terkait pengambilan data dari API hingga melakukan visualisasi data.

Mengakses API covid.go.id

Rekapitulasi data COVID-19 Indonesia tersedia dalam API publik yang beralamat di ___https://data.covid19.go.id/public/api/update.json___. Salah satu cara untuk mengakses API adalah dengan menggunakan fungsi GET() dari paket httr.

Penulis menggunakan nama rsp sebagai tempat penyimpanan data COVID-19

library(httr)
resp <- GET("https://data.covid19.go.id/public/api/update.json")
status_code(resp)
## [1] 200

pada code sebelumnya ditulis status_code() yang artinya melihat apakah API yang kita akses sudah berhasil atau sebaliknya, dimana status kode nya itu sendiri memiliki beberapa kriteria seperti:

*** 200. Artinya permintaan sukses dipenuhi. *** 404. Artinya berkas yang diminta tidak dapat ditemukan. *** 403. Artinya akses permintaan ditolak. *** 500. Artinya terjadi kesalahan pada server.

Headers API

Setelah permintaan API telah dipenuhi langkah selanjutnya mencoba menjalankan fungsi headers() pada resp untuk mengetahui metadata apa saja yang tersimpan. Apakah isi dari elemen content-type? Kapan terakhir kali informasi diperbaharui?

library(httr)
resp <- GET("https://data.covid19.go.id/public/api/update.json")
headers(resp)
## $server
## [1] "nginx"
## 
## $date
## [1] "Sat, 22 Aug 2020 10:36:46 GMT"
## 
## $`content-type`
## [1] "application/json"
## 
## $`last-modified`
## [1] "Sat, 22 Aug 2020 10:34:56 GMT"
## 
## $`transfer-encoding`
## [1] "chunked"
## 
## $connection
## [1] "keep-alive"
## 
## $vary
## [1] "Accept-Encoding"
## 
## $etag
## [1] "W/\"5f40f4d0-1026c\""
## 
## $`content-encoding`
## [1] "gzip"
## 
## attr(,"class")
## [1] "insensitive" "list"

Mengekstrak isi Respon

Respon API dengan status code 200 menyatakan bahwa permintaan Kita berhasil dipenuhi dan konten yang diminta tersedia untuk diekstrak. Selain itu Kita juga telah mengetahui lewat fungsi headers() bahwa konten yang diminta tersedia dalam bentuk application/json, yaitu berkas JSON.

Selanjutnya Penulis dapat mengekstrak konten tersebut dengan menggunakan fungsi content(). Fungsi content() tersebut secara cerdas akan menyesuaikan output sesuai dengan jenis berkas yang tersedia, dalam hal ini adalah berkas JSON. Penulis Menjalankan fungsi tersebut pada obyek resp dan menambahkan argumen as = "parsed" dan simplifyVector = TRUE yang disimpan sebagai cov_id_raw.

library(httr)
resp <- GET("https://data.covid19.go.id/public/api/update.json")
cov_id_raw <- content(resp, as = "parsed", simplifyVector = TRUE) 

dengan mengamati menggunakan fungsi length() dan names() penulis mengamati ada berapa komponen serta apa saja nama komponen dalam obyek cov_id_raw tersebut! Kemudian ekstraklah komponen ke-2 dan menyimpan dengan nama cov_id_update

length(cov_id_raw)
## [1] 2
names(cov_id_raw)
## [1] "data"   "update"
cov_id_update <- cov_id_raw$update

Melakukan Analisis Data

Sekarang Penulis diminta untuk fokus pada obyek cov_id_update untuk menjawab beberapa pertanyaan berikut:

*** Kapan tanggal pembaharuan data penambahan kasus? *** Berapa jumlah penambahan kasus sembuh? *** Berapa jumlah penambahan kasus meninggal? *** Berapa jumlah total kasus positif hingga saat ini? *** Berapa jumlah total kasus meninggal hingga saat ini?

penulis menggunakan fungsi lapply() untuk melihat names pada cov_id_update secara bersamaan

lapply(cov_id_update, names)
## $penambahan
## [1] "jumlah_positif"   "jumlah_meninggal" "jumlah_sembuh"    "jumlah_dirawat"  
## [5] "tanggal"          "created"         
## 
## $harian
##  [1] "key_as_string"        "key"                  "doc_count"           
##  [4] "jumlah_meninggal"     "jumlah_sembuh"        "jumlah_positif"      
##  [7] "jumlah_dirawat"       "jumlah_positif_kum"   "jumlah_sembuh_kum"   
## [10] "jumlah_meninggal_kum" "jumlah_dirawat_kum"  
## 
## $total
## [1] "jumlah_positif"   "jumlah_dirawat"   "jumlah_sembuh"    "jumlah_meninggal"
cov_id_update$penambahan$tanggal
## [1] "2020-08-22"
cov_id_update$penambahan$jumlah_sembuh
## [1] 2207
cov_id_update$penambahan$jumlah_meninggal
## [1] 94
cov_id_update$total$jumlah_positif
## [1] 151498
cov_id_update$total$jumlah_meninggal
## [1] 6594

dari hasil tersebut dapt diketahui bahwa penambhaan terbaru terjadi pada tanggal 18-08-2020 dengan update jumlah sebmbuh teraru sebanyak 1848, jumlah meninggal pada update terakhir sebanyak 70 orang, jumlah terupdate pasien positif sebanyak 143043 dan total jumlah meninggal sebanyak 6277 orang.

Melihat perkembangan Covid-19 di Jawa Barat

Penulis telah berhasil menjawab pertanyaan mengenai kondisi COVID-19 di Indonesia dengan menggunakan data yang langsung diambil menggunakan API. Namun bagaimana jika Penulis ingin berfokus dengan data COVID-19 di provinsi tempat menetap saat ini?

covid19.go.id menyediakan data kasus COVID-19 tingkat provinsi di alamat API yang berbeda. Sebagai contoh data mengenai COVID-19 Jawa Barat, tempat tinggal saya sekarang, tersedia di https://data.covid19.go.id/public/api/prov_detail_JAWA_BARAT.json dan dapat diakses menggunakan baris kode berikut:

library(httr)
resp_jabar <- GET("https://data.covid19.go.id/public/api/prov_detail_JAWA_BARAT.json")
cov_jabar_raw <- content(resp_jabar, as = "parsed", simplifyVector = TRUE)

dan menjawab pertanyaan yang sama dengan code sebagai berikut:

names(cov_jabar_raw)
##  [1] "last_date"            "provinsi"             "kasus_total"         
##  [4] "kasus_tanpa_tgl"      "kasus_dengan_tgl"     "meninggal_persen"    
##  [7] "meninggal_tanpa_tgl"  "meninggal_dengan_tgl" "sembuh_persen"       
## [10] "sembuh_tanpa_tgl"     "sembuh_dengan_tgl"    "list_perkembangan"   
## [13] "data"
cov_jabar_raw$kasus_total
## [1] 9081
cov_jabar_raw$meninggal_persen
## [1] 2.775025
cov_jabar_raw$sembuh_persen
## [1] 54.72966

informasi yang didaptkan oleh penulis sudah baik namun belum cukup lengkap untuk menjawab pertanyaan pertanyaan yang lebih spesifik lagi dari waktu kewaktu.

Kabar baiknya adalah informasi tersebut juga disediakan oleh covid19.go.id melalui permintaan API yang telah Penulis buat sebelumnya. Data historis perkembangan COVID-19 tersebut tersimpan dengan nama list_perkembangan. Ekstrak data tersebut dari cov_jabar_raw dan simpan hasilnya sebagai obyek bernama cov_jabar dan Amati struktur cov_jabar menggunakan fungsi str() dan head().

cov_jabar <- cov_jabar_raw$list_perkembangan
str(cov_jabar)
## 'data.frame':    174 obs. of  9 variables:
##  $ tanggal                     : num  1.58e+12 1.58e+12 1.58e+12 1.58e+12 1.58e+12 ...
##  $ KASUS                       : int  3 0 1 1 0 1 0 0 0 0 ...
##  $ MENINGGAL                   : int  0 0 1 0 0 0 0 0 0 0 ...
##  $ SEMBUH                      : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ DIRAWAT_OR_ISOLASI          : int  3 0 0 1 0 1 0 0 0 0 ...
##  $ AKUMULASI_KASUS             : int  3 3 4 5 5 6 6 6 6 6 ...
##  $ AKUMULASI_SEMBUH            : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ AKUMULASI_MENINGGAL         : int  0 0 1 1 1 1 1 1 1 1 ...
##  $ AKUMULASI_DIRAWAT_OR_ISOLASI: int  3 3 3 4 4 5 5 5 5 5 ...
head(cov_jabar)
##        tanggal KASUS MENINGGAL SEMBUH DIRAWAT_OR_ISOLASI AKUMULASI_KASUS
## 1 1.583021e+12     3         0      0                  3               3
## 2 1.583107e+12     0         0      0                  0               3
## 3 1.583194e+12     1         1      0                  0               4
## 4 1.583280e+12     1         0      0                  1               5
## 5 1.583366e+12     0         0      0                  0               5
## 6 1.583453e+12     1         0      0                  1               6
##   AKUMULASI_SEMBUH AKUMULASI_MENINGGAL AKUMULASI_DIRAWAT_OR_ISOLASI
## 1                0                   0                            3
## 2                0                   0                            3
## 3                0                   1                            3
## 4                0                   1                            4
## 5                0                   1                            4
## 6                0                   1                            5

Melakukan Preprocessing Data

Setelah mengekstrak dan mengamati cov_jabar, Penulis menemukan beberapa kejanggalan pada data tersebut. Diantaranya adalah kejanggalan data pada kolom tanggal dan format penulisan kolom yang tidak konsisten. Sekarang Penulis akan mencoba melakukan beberapa tahapan untuk menjinakan data tersebut sehingga dapat diolah dan dianalisis dengan lebih mudah.

Sebelum itu, silakan aktifkan paket dplyr yang akan dipergunakan untuk melakukan pengolahan data.

Ada beberapa tahapan yang akan dilakukan untuk menjinakan data cov_jabar, yaitu:

  1. Menghapus kolom “DIRAWAT_OR_ISOLASI” dan “AKUMULASI_DIRAWAT_OR_ISOLASI”
  2. Menghapus semua kolom yang berisi nilai kumulatif
  3. Mengganti nama kolom “KASUS” menjadi “kasus_baru”
  4. Merubah format penulisan kolom berikut menjadi huruf kecil kolom MENINGGAL kolom SEMBUH
  5. Memperbaiki data pada kolom tanggal

Penulis akan menggunakan operator pipe (%>%) untuk merangkai fungsi menjadi sebuah pipeline. dan menyimpan hasil pengolahandengan nama new_cov_jabar.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
new_cov_jabar <-
  cov_jabar %>% 
  select(-contains("DIRAWAT_OR_ISOLASI")) %>% 
  select(-starts_with("AKUMULASI")) %>% 
  rename(
    kasus_baru = KASUS,
    meninggal = MENINGGAL,
    sembuh = SEMBUH
    ) %>% 
  mutate(
    tanggal = as.POSIXct(tanggal / 1000, origin = "1970-01-01"),
    tanggal = as.Date(tanggal)
  )
str(new_cov_jabar)  
## 'data.frame':    174 obs. of  4 variables:
##  $ tanggal   : Date, format: "2020-03-01" "2020-03-02" ...
##  $ kasus_baru: int  3 0 1 1 0 1 0 0 0 0 ...
##  $ meninggal : int  0 0 1 0 0 0 0 0 0 0 ...
##  $ sembuh    : int  0 0 0 0 0 0 0 0 0 0 ...

Grafik Untuk Kasus Sembuh

Selanjutnya Penluis melakukan visusalisai yang sama namun menggunakan Kasus sembuh sebagai sumbu Y

library(ggplot2)
library(hrbrthemes)
ggplot(new_cov_jabar, aes(tanggal, sembuh)) +
  geom_col(fill = "olivedrab2") +
  labs(
    x = NULL,
    y = "Jumlah kasus",
    title = "Kasus Harian Sembuh Dari COVID-19 di Jawa Barat",
    caption = "Sumber data: covid.19.go.id"
  ) +
  theme_ipsum(
    base_size = 13, 
    plot_title_size = 21,
    grid = "Y",
    ticks = TRUE
  ) +
  theme(plot.title.position = "plot")
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

Bagaimana Dengan Pekan ini ?

Selanjutnya penulis akna melihat bagaimana perkembangan Covid pada Pekan ini atau pekan terbaru terakhir update data dengan mengekstrak waktu setiap pekannya yaitu week() yang dimana dapt mengetahui apakah pekan lalu lebih baik dari pada pekan sekarang atau sebaliknya.

library(dplyr)
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
## 
##     date
cov_jabar_pekanan <- new_cov_jabar %>% 
  count(
    tahun = year(tanggal),
    pekan_ke = week(tanggal),
    wt = kasus_baru,
    name = "jumlah"
  )

glimpse(cov_jabar_pekanan)
## Rows: 26
## Columns: 3
## $ tahun    <dbl> 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020...
## $ pekan_ke <dbl> 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,...
## $ jumlah   <int> 4, 2, 18, 45, 129, 185, 217, 238, 227, 338, 243, 151, 427,...

untuk membuat grafik berwarna penulis dapat menambahkan fill = lebih_baik pada bar chart agar tampilan lebih menarik

library(ggplot2)
library(hrbrthemes)

ggplot(cov_jabar_pekanan, aes(pekan_ke, jumlah)) +
geom_col(show.legend = FALSE) +
scale_x_continuous(breaks = 9:29, expand = c(0, 0)) +
scale_fill_manual(values = c("TRUE" = "seagreen3", "FALSE" = "salmon")) +
labs(
  x = NULL,
  y = "Jumlah kasus",
  title = "Kasus Pekanan Positif COVID-19 di Jawa Barat",
  subtitle = "Kolom hijau menunjukan penambahan kasus baru lebih sedikit dibandingkan satu pekan sebelumnya",
  caption = "Sumber data: covid.19.go.id"
  ) +
theme_ipsum(
  base_size = 13,
  plot_title_size = 21,
  grid = "Y",
  ticks = TRUE
  ) +
theme(plot.title.position = "plot")
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

selanjutnya jika penulis ingin melihat pola dinamika yang terjadi di data covid-19 dapat meggunakan kode berikut:

library(dplyr)
cov_jabar_akumulasi <- 
  new_cov_jabar %>% 
  transmute(
    tanggal,
    akumulasi_aktif = cumsum(kasus_baru) - cumsum(sembuh) - cumsum(meninggal),
    akumulasi_sembuh = cumsum(sembuh),
    akumulasi_meninggal = cumsum(meninggal)
  )

tail(cov_jabar_akumulasi)
##        tanggal akumulasi_aktif akumulasi_sembuh akumulasi_meninggal
## 169 2020-08-16            3685             4662                 232
## 170 2020-08-17            3684             4707                 233
## 171 2020-08-18            3713             4723                 233
## 172 2020-08-19            3765             4771                 237
## 173 2020-08-20            3893             4842                 239
## 174 2020-08-21            3860             4965                 247

penulis juga dapat menggunakan line chart unutk melihat bagaimana perkembangan dari waktu kewaktu

library(ggplot2)
ggplot(data = cov_jabar_akumulasi, aes(x = tanggal, y = akumulasi_aktif)) +
  geom_line()

### Transformasi Data

akan menggunakan fungsi gather() dari paket tidyr untuk mentransformasi data cov_jabar_akumulasi. Data tersebut akan dirubah dari yang semula berformat wide menjadi format long. AKtifkanlah paket tidyr terlebih dahulu dan lengkapilah baris kode berikut untuk melakukan pivot data dan menyimpannya pada cov_jabar_akumulasi_pivot.

library(dplyr)
library(tidyr)

dim(cov_jabar_akumulasi)
## [1] 174   4
cov_jabar_akumulasi_pivot <- 
  cov_jabar_akumulasi %>% 
  gather(
    key = "kategori",
    value = "jumlah",
    -tanggal
  ) %>% 
  mutate(
    kategori = sub(pattern = "akumulasi_", replacement = "", kategori)
  )

dim(cov_jabar_akumulasi_pivot)
## [1] 522   3
glimpse(cov_jabar_akumulasi_pivot)
## Rows: 522
## Columns: 3
## $ tanggal  <date> 2020-03-01, 2020-03-02, 2020-03-03, 2020-03-04, 2020-03-0...
## $ kategori <chr> "aktif", "aktif", "aktif", "aktif", "aktif", "aktif", "akt...
## $ jumlah   <int> 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 18, 21, 27...