Bar Chart Race

Bar Chart Race memberikan tampilan data yang lebih enerjik karena masing-masing kelompok data seolah bersaing menjadi nomor satu. Sebagai makhluk yang menyukai kompetisi, tidak mengherankan jika kita menyukai jenis visualisasi data yang melagakan satu dengan lainnya.

Kode Lima Detik

import calendar
import pandas as pd
import bar_chart_race as bcr

pd.options.display.float_format = '{:,.2f}'.format

df = pd.read_csv('sirup2020.csv',\
                 sep='\t',\
                 usecols=['id', 'paket', 'nilai', 'jenis', 'metode', 'pemilihan', 'instansi', 'satker', 'lokasi'],\
                 dtype={'id': 'int32', 'paket': 'string', 'nilai': 'float64', 'jenis': 'category', 'metode': 'category', 'pemilihan': 'category', 'instansi': 'category', 'satker': 'category', 'lokasi': 'category'})
df['bulan'] = df['pemilihan'].str.extract('(^[a-zA-Z]+)')

grouped = df[['nilai', 'bulan', 'instansi']].groupby(['bulan', 'instansi'], as_index=False).sum()

top10 = grouped.sort_values('nilai', ascending=False).groupby('bulan').head(10)
top10['nilai2'] = top10['nilai'] / 1000000

def nama(instansi):
    ret = ''
    
    if 'Pekerjaan Umum dan Perumahan Rakyat' in instansi:
        ret = 'K PUPR'
    elif 'Pertahanan' in instansi:
        ret = 'K Pertahanan'
    elif 'Perhubungan' in instansi:
        ret = 'K Perhubungan'
    elif 'Pendidikan dan Kebudayaan' in instansi:
        ret = 'K Dikbud'        
    elif 'Kementerian Keuangan' in instansi:
        ret = 'K Keuangan'
    elif 'Kementerian Agama' in instansi:
        ret = 'K Agama'
    elif 'Kementerian Kesehatan' in instansi:
        ret = 'K Kesehatan'
    elif 'Kementerian Pertanian' in instansi:
        ret = 'K Pertanian'
    elif 'Kementerian Energi' in instansi:
        ret = 'K ESDM'
    elif 'Kementerian Agraria' in instansi:
        ret = 'K Agraria'
    elif 'Kementerian Hukum Dan Hak Asasi Manusia RI' in instansi:
        ret = 'K Kumham'
    elif 'Fasilitas Kesehatan Swasta Provider Jaminan Kesehatan Nasional' in instansi:
        ret = 'JKN'
    elif 'Kepolisian Negara Republik Indonesia' in instansi:
        ret = 'Polri'
    elif 'Lembaga Kebijakan Pengadaan Barang/Jasa Pemerintah' in instansi:
        ret = 'LKPP'
    elif 'Dewan Perwakilan Rakyat' in instansi:
        ret = 'DPR'
    elif 'Mahkamah Agung' in instansi:
        ret = 'MA'
    elif 'Lembaga Ilmu Pengetahuan' in instansi:
        ret = 'LIPI'
    elif 'Komisi Pemberantasan' in instansi:
        ret = 'KPK'
    elif 'Pemerintah Daerah Provinsi' in instansi:
        ret = instansi.replace('Pemerintah Daerah Provinsi', 'Pemprov')
    elif 'Pemerintah Daerah Kabupaten' in instansi:
        ret = instansi.replace('Pemerintah Daerah Kabupaten', 'Pemkab')
    elif 'Pemerintah Daerah Kota' in instansi:
        ret = instansi.replace('Pemerintah Daerah Kota', 'Pemkot')
    else:
        ret = instansi
                
    return ret
top10['instansi2'] = top10['instansi'].apply(nama)
top10['bulan2'] = pd.to_datetime(top10['bulan'], format='%B').dt.month

df_formatted = top10.pivot(index='bulan2', columns='instansi2', values='nilai2')
df_formatted.fillna(0, inplace=True)

data = pd.DataFrame(df_formatted.to_records())
data['bulan'] = data['bulan2'].apply(lambda x: calendar.month_abbr[x])
data.set_index('bulan', inplace=True)

bcr.bar_chart_race(data.iloc[:, 1:], n_bars=10, steps_per_period=172, period_length=5000)

Latar Belakang

Visualisasi sebagai media mengkomunikasikan “opini” kita akan data sudah makin beragam. Jaman now data yang disodorkan pada kita bukan hanya berbentuk pie chart, yang kadang sulit dicerna berapa proporsi yang berusaha disampaikan, saja. Ada banyak ragam berbeda seperti bar chart, line chart dan macam lainnya.

Selain bergantung pada jenis data yang disajikan, pilihan tersebut juga bergantung pada harapan kita tentang bagaimana audiensi akan menerjemahkan visualisasi data dihadapannya. Hal tersebut bisa dicapai karena masing-masing jenis visualisasi akan memberikan nuansa yang berbeda.

Visualisasi interaktif misalnya, memungkinkan pengguna untuk mengeksplorasi data dan mendapatkan pengetahuan yang lebih kaya.

Di sisi lain visualisasi animatif membantu pengguna untuk melihat dan memahami data saat terjadi perubahan.

Pada tulisan ini kita akan membuat sebuah visualisasi animatif berupa Bar Chart Race yang akan “menceritakan” sepuluh entitas pemerintah dengan rencana pengadaan terbesar pada periode Januari – Desember 2020.

Data yang digunakan adakah data rencana pengadaan tahun 2020 dari SiRUP yang diunduh pada 3 Juni 2020.

Teknologi yang digunakan adalah Python dengan bantuan library pandas dan Bar Chart Race. Kode ditulis pada Jupyter Lab.


Langkah Kerja

Instalasi library

Jika belum pernah melakukan instalasi library Bar Chart Race, kita dapat menggunakan kode di bawah ini pada cell notebook.

!pip install bar_chart_race

Selain itu perlu juga dilakukan instalasi ffmpeg (untuk menyimpan animasi dalam bentuk mp4/m4v/mov) dan ImageMagick (jika ingin menyimpan sebagai gif).

Load library

import calendar
import pandas as pd
import bar_chart_race as bcr

pd.options.display.float_format = '{:,.2f}'.format

Load data

df = pd.read_csv('sirup2020.csv',\
                 sep='\t',\
                 usecols=['id', 'paket', 'nilai', 'jenis', 'metode', 'pemilihan', 'instansi', 'satker', 'lokasi'],\
                 dtype={'id': 'int32', 'paket': 'string', 'nilai': 'float64', 'jenis': 'category', 'metode': 'category', 'pemilihan': 'category', 'instansi': 'category', 'satker': 'category', 'lokasi': 'category'})

Tambah kolom bulan

Kita akan membagi data berdasarkan bulan. Karena informasi tersebut belum tersedia, kita akan mengekstraksi kolom pemilihan untuk mendapatkan kolom bulan.

df['bulan'] = df['pemilihan'].str.extract('(^[a-zA-Z]+)')

Kelompokkan data berdasar bulan dan instansi

Untuk mendapatkan total rencana pengadaan per instansi pada suatu bulan, kita perlu mengelompokkan data berdasarkan kolom bulan dan instansi kemudian menjumlahkan kolom nilai.

grouped = df[['nilai', 'bulan', 'instansi']].groupby(['bulan', 'instansi'], as_index=False).sum()

Sepuluh instansi teratas

Selanjutnya adalah mengambil sepuluh instansi dengan rencana pengadaan tertinggi pada tiap bulannya.

top10 = grouped.sort_values('nilai', ascending=False).groupby('bulan').head(10)

Kolom nilai dalam juta

Perlu dibuat kolom nilai dalam jutaan agar saat data dianimasikan, angka tidak terlalu banyak sehingga malah mengganggu alih-alih informatif.

top10['nilai2'] = top10['nilai'] / 1000000

Persingkat nama instansi

Data terakhir mengandung 43 instansi yang berbeda.

top10['instansi'].unique()

Nama instansi perlu dipersingkat, lagi-lagi agar saat dianimasikan informasi tersebut tidak sampai mengganggu. Fungsi apply diberdayakan untuk mencapai hal tersebut.

def nama(instansi):
    ret = ''
    
    if 'Pekerjaan Umum dan Perumahan Rakyat' in instansi:
        ret = 'K PUPR'
    elif 'Pertahanan' in instansi:
        ret = 'K Pertahanan'
    elif 'Perhubungan' in instansi:
        ret = 'K Perhubungan'
    elif 'Pendidikan dan Kebudayaan' in instansi:
        ret = 'K Dikbud'        
    elif 'Kementerian Keuangan' in instansi:
        ret = 'K Keuangan'
    elif 'Kementerian Agama' in instansi:
        ret = 'K Agama'
    elif 'Kementerian Kesehatan' in instansi:
        ret = 'K Kesehatan'
    elif 'Kementerian Pertanian' in instansi:
        ret = 'K Pertanian'
    elif 'Kementerian Energi' in instansi:
        ret = 'K ESDM'
    elif 'Kementerian Agraria' in instansi:
        ret = 'K Agraria'
    elif 'Kementerian Hukum Dan Hak Asasi Manusia RI' in instansi:
        ret = 'K Kumham'
    elif 'Fasilitas Kesehatan Swasta Provider Jaminan Kesehatan Nasional' in instansi:
        ret = 'JKN'
    elif 'Kepolisian Negara Republik Indonesia' in instansi:
        ret = 'Polri'
    elif 'Lembaga Kebijakan Pengadaan Barang/Jasa Pemerintah' in instansi:
        ret = 'LKPP'
    elif 'Dewan Perwakilan Rakyat' in instansi:
        ret = 'DPR'
    elif 'Mahkamah Agung' in instansi:
        ret = 'MA'
    elif 'Lembaga Ilmu Pengetahuan' in instansi:
        ret = 'LIPI'
    elif 'Komisi Pemberantasan' in instansi:
        ret = 'KPK'
    elif 'Pemerintah Daerah Provinsi' in instansi:
        ret = instansi.replace('Pemerintah Daerah Provinsi', 'Pemprov')
    elif 'Pemerintah Daerah Kabupaten' in instansi:
        ret = instansi.replace('Pemerintah Daerah Kabupaten', 'Pemkab')
    elif 'Pemerintah Daerah Kota' in instansi:
        ret = instansi.replace('Pemerintah Daerah Kota', 'Pemkot')
    else:
        ret = instansi
                
    return ret

top10['instansi2'] = top10['instansi'].apply(nama)

Bulan dalam angka

Data akan dianimasikan urut dari Januari hingga Desember namun seperti terlihat di atas, data yang kita miliki belum sesuai urutan. Karenanya perlu ditambahkan kolom berisi bulan dalam angka agar dapat dapat diurutkan berdasarkan kolom tersebut.

top10['bulan2'] = pd.to_datetime(top10['bulan'], format='%B').dt.month

Data sesuai format Bar Chart Race

Library Bar Chart Race mensyaratkan data dalam format tertentu, contohnya seperti ini.

Data terakhir perlu di-pivot kemudian diubah menjadi dataframe yang sesuai dengan format disyaratkan.

df_formatted = top10.pivot(index='bulan2', columns='instansi2', values='nilai2')
df_formatted.fillna(0, inplace=True)
data = pd.DataFrame(df_formatted.to_records())

Pada kode di atas kita selipkan fungsi fillna untuk mengisi nilai kosong (null/na/none) dengan angka 0.

Kolom nama bulan

Pada proses sebelumnya kolom nama bulan tidak digunakan saat mem-pivot data. Karena animasi akan menampilkan informasi bulan, kolom angka bulan akan digunakan untuk membuat kolom nama bulan. Kolom nama bulan tersebut dijadikan index pada data.

data['bulan'] = data['bulan2'].apply(lambda x: calendar.month_abbr[x])
data.set_index('bulan', inplace=True)

Sampai di sini data sudah sesuai dengan format yang disyaratkan dan telah siap untuk dianimasikan.

Animasikan data

bcr.bar_chart_race(data.iloc[:, 1:], n_bars=10, steps_per_period=172, period_length=5000)

Parameter yang digunakan adalah n_bars, steps_per_period dan period_length. Nilai yang digunakan pada masing-masing parameter dapat dicoba sendiri untuk mendapatkan animasi yang sesuai dengan keinginan. Deskripsi singkat parameter di atas berdasarkan data yang digunakan adalah.

  • n_bars: jumlah bar (instansi) yang akan ditampilkan. Pada kode di atas ditampilkan hanya 10 instansi teratas pada tiap periode.
  • steps_per_period: banyaknya langkah dalam satu periode (bulan). Nilai 172 adalah 43 (instansi) dikali 4.
  • period_length: waktu (dalam milisekon) untuk menganimasikan tiap periode. Nilai 5000 menunjukkan 5 detik untuk tiap bulannya.

Library Bar Chart Race menyediakan cukup banyak parameter untuk dicoba, sila merujuk pada dokumentasi untuk mengetahui selengkapnya.


Simpulan

Data dapat ditampilkan dalam bentuk tabel, gambar statis atau animasi. Sebagai ilustrasi, data rencana pengadaan tahun 2020 dapat ditampilkan menggunakan ketiga bentuk tersebut.

Sepuluh Rencana Pengadaan Terbesar bulan Januari 2020
Sepuluh Rencana Pengadaan Terbesar bulan Februari 2020

Masing-masing memberikan pengalaman yang berbeda, karena itu pemilihannya bergantung dari apa yang ingin kita sampaikan kepada audiensi.

Omong-omong apa visualisasi favorit Anda?


Referensi


Cover Image by Gerd Altmann from Pixabay

Leave a Reply

Your email address will not be published. Required fields are marked *