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.
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.
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
- https://www.dexplo.org/bar_chart_race/
- https://public.tableau.com/en-us/s/blog/2020/02/creating-animated-data-visualizations-tableau-public
Cover Image by Gerd Altmann from Pixabay