Mengapa Visualisasi Data Penting

Visualisasi bukan tentang membuat chart yang cantik. Ini tentang membuat pola yang tak terlihat menjadi terlihat, dan mengubah angka menjadi keputusan.

Konsep Inti Bulan Ini

Data mentah berbicara kepada komputer. Visualisasi berbicara kepada manusia. Tugas Abbas sebagai data analyst adalah menjadi penerjemah antara keduanya: mengambil ribuan baris data, menemukan cerita di dalamnya, dan menyajikannya dalam bentuk visual yang langsung dipahami.

  • Pola tak terlihat dalam tabel langsung terlihat dalam chart. Ribuan baris angka tidak akan pernah mengungkap tren seefektif satu line chart yang tepat. Otak manusia dirancang untuk memproses pola visual jauh lebih cepat dari teks atau angka. Anscombe's Quartet adalah contoh klasik: empat dataset dengan statistik identik (mean, variance, dan korelasi sama persis) tapi pola scatter plot-nya sangat berbeda satu sama lain.
  • Visualisasi adalah alat analisis, bukan hanya alat presentasi. Sebelum membangun model statistik, plot datanya terlebih dahulu. Satu scatter plot sering mengungkap outlier atau pola non-linear yang tidak akan terdeteksi oleh angka korelasi saja. Prinsip "plot first, model second" adalah kebiasaan yang wajib dimiliki analyst profesional.
  • Chart yang salah bisa menyesatkan pembuat keputusan. Y-axis yang tidak mulai dari nol, pie chart dengan 12 irisan, atau 3D chart yang mendistorsi proporsi adalah bentuk misinformasi visual yang sering tidak disengaja. Abbas perlu tahu bukan hanya cara membuat chart, tapi cara membuat chart yang jujur terhadap data.
  • Setiap jenis data punya chart yang paling cocok. Distribusi butuh histogram atau boxplot. Tren butuh line chart. Proporsi butuh bar chart, bukan pie chart. Relasi antar dua variabel numerik butuh scatter plot. Memilih chart yang salah berarti menyembunyikan informasi, bukan mengungkapnya.
  • Python punya ekosistem visualisasi yang lengkap dan saling melengkapi. Matplotlib memberikan kontrol penuh atas setiap piksel. Seaborn menyederhanakan statistical plotting dengan kode minimal. Plotly menghadirkan interaktivitas yang bisa dijelajahi pembaca. Ketiganya perlu dikuasai karena punya use case yang berbeda.
  • Prinsip desain bukan optional, tapi wajib. Warna yang tidak accessible bagi penderita buta warna, label yang terpotong karena layout buruk, legend yang ambigu, semuanya membuat chart tidak berguna meskipun data di baliknya sudah dianalisis dengan benar. Edward Tufte merumuskan ini sebagai "data-ink ratio": setiap tetes tinta harus membawa informasi yang bermakna.
  • Storytelling adalah skill yang terpisah dari kemampuan teknis. Abbas bisa membuat 20 chart yang secara teknis benar, tapi jika tidak ada narasi yang menghubungkan semuanya, pembaca tidak akan tahu apa kesimpulannya. Chart yang bagus punya satu pesan yang jelas, judul yang aktif (bukan sekadar deskriptif), dan anotasi yang mengarahkan mata pembaca ke titik yang paling penting.
  • Interaktivitas mengubah cara orang mengeksplorasi data. Dengan plotly, pembaca bisa hover untuk melihat detail, zoom ke area tertentu, atau menyembunyikan kategori dari legend. Ini membuat satu chart interaktif bisa menggantikan sepuluh chart statis, dan lebih sesuai dengan cara manusia modern mengonsumsi informasi berbasis web.
  • Konteks geografis adalah dimensi penting untuk data Indonesia. Data per provinsi, per kabupaten, atau per kecamatan jauh lebih mudah dipahami ketika divisualisasikan di atas peta. Choropleth map adalah alat wajib bagi data analyst yang bekerja dengan data administrasi Indonesia, mulai dari data BPS hingga data kesehatan Kemenkes.

Minggu 1: Matplotlib Dasar

Fondasi semua visualisasi Python. Matplotlib adalah canvas tempat semua library lain dibangun. Abbas perlu memahaminya dari bawah agar bisa mengontrol setiap detail chart.

Minggu 1

Anatomi, Chart Dasar, dan Kontrol Penuh atas Canvas

Hari 1

Figure, Axes, dan Subplot Anatomy: Memahami Canvas Matplotlib

Sebelum Abbas bisa membuat chart apapun, Abbas perlu memahami hirarki objek matplotlib. Figure adalah seluruh gambar (kanvas kosong). Axes adalah area plot di dalam Figure (tempat data digambar). Artist adalah setiap elemen visual seperti garis, teks, dan titik yang ada di dalam Axes. Satu Figure bisa punya banyak Axes.

1
Eksplorasi dua cara membuat chart. Cara pertama, pyplot-style: plt.plot(x, y) singkat tapi implisit. Cara kedua, object-oriented style: fig, ax = plt.subplots(); ax.plot(x, y) lebih verbose tapi eksplisit dan lebih mudah dikontrol. Pahami perbedaan keduanya, lalu biasakan memakai OO-style.
2
Buat Figure pertama secara manual. Gunakan fig = plt.figure(figsize=(10, 6), dpi=100). Tambahkan Axes secara eksplisit dengan ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]). Perhatikan parameter posisi: [left, bottom, width, height] dalam satuan fraksi 0 sampai 1 dari Figure. Ubah nilainya dan amati efeknya.
3
Buat grid subplot dengan plt.subplots(). Gunakan fig, axes = plt.subplots(2, 3, figsize=(15, 10)) untuk membuat grid 2 baris 3 kolom. Iterasi dengan for ax in axes.flatten() dan isi setiap Axes dengan chart sederhana. Tambahkan plt.tight_layout() agar tidak saling tumpang tindih.
4
Buat layout tidak simetris dengan subplot2grid. Buat layout di mana satu chart besar mengambil seluruh kolom kiri, dan dua chart kecil bertumpuk di kolom kanan. Gunakan ax1 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) untuk chart besar dan ax2 = plt.subplot2grid((2, 2), (0, 1)) untuk yang kecil.
5
Latihan penutup hari 1: Buat satu Figure berisi 3 subplot dalam satu baris. Subplot kiri: scatter plot data acak. Subplot tengah: line chart gelombang sinus. Subplot kanan: bar chart 5 kategori. Tambahkan ax.set_title() untuk setiap subplot dan fig.suptitle() sebagai judul utama Figure. Export dengan plt.savefig('latihan_hari1.png', dpi=150).
import matplotlib.pyplot as plt
import numpy as np

# Object-oriented style: cara yang disarankan untuk proyek nyata
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
fig.suptitle('Tiga Jenis Chart dalam Satu Figure', fontsize=16, fontweight='bold')

np.random.seed(42)
x_scatter = np.random.rand(50)
y_scatter = np.random.rand(50)

# Subplot 1: Scatter plot
axes[0].scatter(x_scatter, y_scatter, alpha=0.7, color='steelblue', s=60)
axes[0].set_title('Scatter Plot')
axes[0].set_xlabel('Variabel X')
axes[0].set_ylabel('Variabel Y')

# Subplot 2: Line chart
t = np.linspace(0, 2 * np.pi, 200)
axes[1].plot(t, np.sin(t), color='coral', linewidth=2.5)
axes[1].set_title('Line Chart')
axes[1].set_xlabel('Waktu (radian)')
axes[1].set_ylabel('Amplitudo')

# Subplot 3: Bar chart
kategori = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei']
nilai = [23, 45, 31, 52, 38]
axes[2].bar(kategori, nilai, color='mediumseagreen', edgecolor='white')
axes[2].set_title('Bar Chart')
axes[2].set_ylabel('Jumlah')

plt.tight_layout()
plt.savefig('latihan_hari1.png', dpi=150, bbox_inches='tight')
plt.show()
Hari 2

Line Chart yang Baik: Labels, Title, Legend, dan DPI

Line chart adalah chart paling sering dibuat dan paling sering dibuat dengan buruk. Hari ini Abbas akan mempelajari semua detail yang membuat line chart menjadi profesional: dari label axis yang informatif, legend yang tidak menutupi data, hingga resolusi yang cukup untuk presentasi cetak.

1
Buat line chart suhu harian dengan semua elemen wajib. Data: suhu harian Jakarta selama 30 hari (Juni 2024). Tambahkan ax.set_xlabel('Tanggal', fontsize=12), ax.set_ylabel('Suhu (Celsius)', fontsize=12), dan ax.set_title('Tren Suhu Jakarta, Juni 2024', fontsize=14, fontweight='bold'). Pastikan setiap chart selalu punya ketiga elemen ini.
2
Kontrol tampilan garis secara detail. Eksperimen dengan kombinasi parameter: linestyle (solid, dashed, dotted, dashdot), marker (o, s, ^, D, *), markersize, color (nama warna, hex code, RGB tuple), dan linewidth. Buat dua garis, satu untuk suhu siang dan satu untuk suhu malam, dengan styling yang kontras tapi harmonis.
3
Tambahkan legend yang tidak mengganggu. Gunakan label= pada setiap ax.plot(), lalu panggil ax.legend(loc='best', framealpha=0.9, edgecolor='lightgray'). Eksperimen dengan posisi: 'upper left', 'lower right'. Untuk legend horizontal, tambahkan ncol=2. Jika legend tetap menutupi data, pindahkan ke luar chart dengan bbox_to_anchor=(1.01, 1).
4
Bersihkan chart dengan kontrol gridlines dan spines. Tambahkan gridlines tipis: ax.grid(True, alpha=0.3, linestyle='--', color='gray'). Hilangkan spine kanan dan atas (konvensi chart modern): ax.spines['right'].set_visible(False) dan ax.spines['top'].set_visible(False). Ini adalah teknik yang digunakan di The Economist dan Financial Times.
5
Export dengan kualitas presentasi dan bandingkan hasilnya. Simpan tiga versi: dpi=72 (web), dpi=150 (layar), dpi=300 (cetak). Lihat perbedaan ukuran file dan ketajaman teks. Selalu gunakan bbox_inches='tight' dan facecolor='white' agar background tidak transparan.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

np.random.seed(7)
hari = pd.date_range(start='2024-06-01', periods=30, freq='D')
suhu_siang  = 32 + np.random.normal(0, 2, 30)
suhu_malam  = 26 + np.random.normal(0, 1.5, 30)

fig, ax = plt.subplots(figsize=(12, 5))

ax.plot(hari, suhu_siang,
        label='Suhu Siang', color='#e74c3c',
        linewidth=2, marker='o', markersize=4)

ax.plot(hari, suhu_malam,
        label='Suhu Malam', color='#3498db',
        linewidth=2, linestyle='--', marker='s', markersize=4)

ax.set_title('Suhu Siang dan Malam Jakarta, Juni 2024',
             fontsize=14, fontweight='bold', pad=15)
ax.set_xlabel('Tanggal', fontsize=11)
ax.set_ylabel('Suhu (Celsius)', fontsize=11)
ax.legend(loc='upper right', framealpha=0.9, edgecolor='lightgray')
ax.grid(True, alpha=0.3, linestyle='--')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

plt.tight_layout()
plt.savefig('suhu_jakarta.png', dpi=300, bbox_inches='tight', facecolor='white')
plt.show()
Konvensi Chart Profesional

Menghilangkan spine kanan dan atas adalah konvensi yang digunakan mayoritas publikasi data journalism terkemuka. Ini membuat chart terlihat lebih modern dan mengurangi visual noise. Jadikan ini kebiasaan di setiap chart yang Abbas buat.

Hari 3

Bar Chart, Grouped Bar, dan Stacked Bar: Kapan Pakai Apa

Bar chart adalah chart yang paling sering disalahgunakan. Tiga variannya punya pesan yang sangat berbeda. Memilih yang salah berarti menyembunyikan atau mendistorsi informasi yang penting bagi pembaca.

1
Bar chart sederhana: satu nilai per kategori. Buat bar chart penjualan 5 produk. Gunakan ax.bar() untuk vertikal. Aturan penting: jika label kategori lebih dari 5 karakter atau jumlah kategori lebih dari 6, gunakan ax.barh() untuk horizontal agar label tidak tumpang tindih. Tambahkan ax.bar_label(container, fmt='%d', padding=3) untuk nilai di atas setiap bar.
2
Grouped bar chart: bandingkan beberapa seri per kategori. Kasus: penjualan per produk untuk Q1, Q2, Q3. Posisikan bar dengan manipulasi manual posisi x: x + width * offset. Gunakan grouped bar ketika Abbas ingin membandingkan nilai absolut antar kuartal dalam setiap produk secara berdampingan.
3
Stacked bar chart: lihat komposisi dan total sekaligus. Tumpuk bar menggunakan parameter bottom=. Layer pertama mulai dari 0, layer kedua mulai dari nilai layer pertama, dan seterusnya. Stacked bar digunakan ketika total dan komposisi sama pentingnya untuk dipahami pembaca.
4
100% Stacked bar chart: fokus pada proporsi saja. Normalisasi setiap baris ke persentase sebelum diplot. Berguna ketika total antar kategori sangat berbeda sehingga perbandingan absolut tidak adil, dan Abbas hanya ingin membandingkan komposisi internal masing-masing kategori.
5
Latihan keputusan chart: Diberikan dataset penjualan 4 produk di 3 kota untuk 3 kuartal. Buat keempat varian bar chart dalam satu Figure. Di bawah setiap chart, tambahkan teks anotasi satu kalimat: "Chart ini paling baik untuk menjawab pertanyaan: ..." Tugas ini melatih Abbas berpikir tentang pertanyaan sebelum memilih chart.
import matplotlib.pyplot as plt
import numpy as np

produk = ['Laptop', 'Mouse', 'Keyboard', 'Monitor']
q1 = np.array([120, 340, 210, 85])
q2 = np.array([145, 290, 250, 110])
q3 = np.array([160, 320, 230, 95])

x = np.arange(len(produk))
width = 0.25

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Grouped bar: bandingkan nilai absolut per kuartal
b1 = axes[0].bar(x - width, q1, width, label='Q1', color='#3498db')
b2 = axes[0].bar(x,          q2, width, label='Q2', color='#e67e22')
b3 = axes[0].bar(x + width, q3, width, label='Q3', color='#2ecc71')
axes[0].set_xticks(x)
axes[0].set_xticklabels(produk)
axes[0].set_title('Grouped Bar: Perbandingan Antar Kuartal')
axes[0].legend()
axes[0].spines['right'].set_visible(False)
axes[0].spines['top'].set_visible(False)

# Stacked bar: lihat total dan komposisi
axes[1].bar(produk, q1,           label='Q1', color='#3498db')
axes[1].bar(produk, q2, bottom=q1, label='Q2', color='#e67e22')
axes[1].bar(produk, q3, bottom=q1+q2, label='Q3', color='#2ecc71')
axes[1].set_title('Stacked Bar: Total dan Komposisi')
axes[1].legend()
axes[1].spines['right'].set_visible(False)
axes[1].spines['top'].set_visible(False)

plt.tight_layout()
plt.show()
Aturan Memilih Varian Bar Chart

Gunakan bar biasa untuk satu nilai per kategori. Gunakan grouped bar untuk membandingkan nilai absolut beberapa seri. Gunakan stacked bar ketika total dan komposisi sama penting. Gunakan 100% stacked bar ketika hanya proporsi yang relevan. Jangan gunakan pie chart jika lebih dari 3 kategori, bar chart selalu lebih akurat untuk mata manusia.

Hari 4

Scatter Plot dan Dimensi ke-3 dengan Size dan Color

Scatter plot adalah chart paling powerful untuk analisis eksplorasi (EDA). Dengan menambahkan size sebagai dimensi ke-3 dan color sebagai dimensi ke-4, satu scatter plot bisa menyampaikan empat variabel sekaligus tanpa kehilangan kejelasan.

1
Scatter plot dasar: temukan hubungan antara dua variabel. Plot hubungan jam belajar vs nilai ujian dari 100 siswa dummy. Perhatikan pola yang muncul: linear, non-linear, atau tidak ada pola sama sekali. Tambahkan alpha=0.6 untuk menangani overplotting ketika banyak titik bertumpuk di area yang sama.
2
Tambahkan dimensi ke-3 dengan size (bubble chart). Gunakan parameter s=array_ukuran di ax.scatter(). Misalnya, ukuran titik mewakili jumlah siswa per sekolah. Karena s adalah luas dalam pixel persegi, skala dengan pangkat dua: jika jumlah siswa 400, s=400/5=80. Tambahkan legend manual yang menjelaskan skala ukuran.
3
Tambahkan dimensi ke-4 dengan color mapping kontinu. Gunakan c=array_nilai bersama cmap='RdYlGn' untuk gradien warna merah-kuning-hijau. Tambahkan plt.colorbar(scatter, ax=ax, label='Nama Variabel') sebagai legend warna. Pilih colormap yang tepat: viridis atau plasma untuk data sekuensial, RdBu untuk data diverging yang punya nilai tengah netral.
4
Tambahkan garis tren (regression line) secara manual. Hitung koefisien regresi linear dengan koef = np.polyfit(x, y, 1). Plot hasilnya dengan ax.plot(x_line, np.poly1d(koef)(x_line), 'k--', alpha=0.6, label='Tren'). Hitung koefisien korelasi Pearson dengan np.corrcoef(x, y)[0,1] dan tampilkan nilainya di dalam chart menggunakan ax.text().
5
Latihan: scatter plot IPM vs kemiskinan per kabupaten Indonesia. Download data dari BPS: Indeks Pembangunan Manusia dan persentase penduduk miskin per kabupaten/kota. Buat scatter plot dengan size = jumlah penduduk, color = pulau (Jawa, Sumatera, Kalimantan, Sulawesi, Papua). Identifikasi dan beri label pada 3 kabupaten yang paling outlier menggunakan ax.annotate().
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
n = 120
jam_belajar  = np.random.uniform(1, 10, n)
nilai        = 50 + jam_belajar * 4 + np.random.normal(0, 8, n)
jml_siswa    = np.random.uniform(100, 2000, n)
ipm_sekolah  = np.random.uniform(60, 85, n)

fig, ax = plt.subplots(figsize=(10, 7))

scatter = ax.scatter(
    jam_belajar, nilai,
    s = jml_siswa / 10,    # ukuran = jumlah siswa
    c = ipm_sekolah,         # warna = IPM sekolah
    cmap = 'RdYlGn',
    alpha = 0.75,
    edgecolors = 'white', linewidth = 0.5
)

cbar = plt.colorbar(scatter, ax=ax)
cbar.set_label('IPM Sekolah', fontsize=10)

# Garis tren linear
koef = np.polyfit(jam_belajar, nilai, 1)
x_line = np.linspace(jam_belajar.min(), jam_belajar.max(), 100)
ax.plot(x_line, np.poly1d(koef)(x_line),
        'k--', alpha=0.6, linewidth=1.5, label='Tren Linear')

r = np.corrcoef(jam_belajar, nilai)[0, 1]
ax.text(0.05, 0.95, f'r = {r:.2f}',
        transform=ax.transAxes, fontsize=12, color='#333',
        verticalalignment='top')

ax.set_xlabel('Jam Belajar per Hari', fontsize=12)
ax.set_ylabel('Nilai Ujian', fontsize=12)
ax.set_title('Hubungan Jam Belajar vs Nilai Ujian\n(ukuran titik = jumlah siswa, warna = IPM)',
             fontsize=13)
ax.legend()
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
plt.show()
Hari 5

Latihan Integratif: 5 Chart dari Dataset Nilai Ujian Nasional

Hari ini Abbas mengintegrasikan semua yang sudah dipelajari minggu ini. Target: membuat 5 chart berbeda yang menjawab 5 pertanyaan berbeda dari satu dataset, semuanya dikemas dalam satu Figure rapi yang siap dipresentasikan.

1
Siapkan dataset dan lakukan eksplorasi awal. Gunakan data nilai UN per mata pelajaran, per tahun (2015-2023), per provinsi, dan per jenis sekolah (negeri/swasta). Sebelum satu baris kode visualisasi pun ditulis, lakukan df.info(), df.describe(), df.isnull().sum(), dan df['tahun'].value_counts(). Pahami strukturnya dulu.
2
Chart 1: Line chart tren nilai rata-rata nasional 2015-2023. Satu garis per mata pelajaran: Matematika, Bahasa Indonesia, Bahasa Inggris, IPA. Beri label langsung di ujung setiap garis (bukan di legend) menggunakan ax.text() untuk memudahkan pembaca. Highlight titik penurunan terbesar dengan anotasi panah menggunakan ax.annotate().
3
Chart 2: Horizontal bar chart nilai rata-rata per mata pelajaran. Urutkan dari tertinggi ke terendah dengan sort_values(). Warnai bar Matematika merah karena paling rendah, sisanya abu-abu. Tambahkan label nilai di ujung setiap bar dengan ax.bar_label(). Ini adalah teknik "single-color highlight" yang mengarahkan perhatian pembaca.
4
Chart 3: Scatter plot hubungan nilai UN vs akreditasi sekolah. Kode akreditasi ke angka: A=3, B=2, C=1. Tambahkan jitter horizontal (x + np.random.uniform(-0.1, 0.1, n)) agar titik tidak bertumpuk. Warnai berdasarkan jenis sekolah. Tambahkan garis rata-rata horizontal per kelompok akreditasi.
5
Chart 4 dan 5: Stacked bar per provinsi dan grouped bar negeri vs swasta. Gabungkan semua 5 chart dalam satu Figure dengan layout gridspec: chart 1 lebar penuh di atas, chart 2 dan 3 berdampingan di tengah, chart 4 dan 5 berdampingan di bawah. Export sebagai laporan-un.png dengan dpi=300. Ini adalah format laporan visual siap pakai.
Tantangan Ekstra

Setelah selesai membuat 5 chart, tambahkan anotasi teks pada setiap chart yang menyatakan satu insight utama dalam satu kalimat. Contoh yang benar: "Nilai matematika turun 8 poin sejak 2019." Contoh yang salah: "Grafik ini menunjukkan nilai matematika dari 2015 sampai 2023." Insight bukan deskripsi, insight adalah interpretasi.

Minggu 2: Seaborn untuk Statistik Visual

Seaborn dibangun di atas matplotlib dan dirancang khusus untuk statistical visualization. Dengan kode yang lebih singkat, hasilnya jauh lebih cantik dan informatif secara statistik.

Minggu 2

Distribusi, Korelasi, dan Eksplorasi Data dengan Seaborn

Hari 1

Histogram dan KDE Plot: Memvisualisasikan Distribusi dengan Cantik

Pertanyaan paling mendasar dalam analisis data adalah: "Bagaimana distribusi dataku?" Histogram dan KDE (Kernel Density Estimate) adalah dua cara untuk menjawabnya. Seaborn membuat keduanya terlihat jauh lebih baik dari matplotlib standar dengan hampir nol konfigurasi tambahan.

1
Setup dan kenali data sample seaborn. Jalankan import seaborn as sns; sns.set_theme(style='whitegrid'). Load dataset bawaan: df = sns.load_dataset('tips'). Seaborn punya beberapa dataset bawaan seperti tips, iris, titanic, penguins, dan flights. Eksplorasi dengan df.describe() dan df.dtypes sebelum memvisualisasikan.
2
Histogram dasar dengan sns.histplot(). Plot distribusi kolom total_bill. Eksperimen dengan parameter bins: terlalu sedikit (5) kehilangan detail, terlalu banyak (100) terlalu noisy. Gunakan bins='auto' atau bins=30 sebagai titik awal yang baik. Tambahkan kde=True untuk overlay kurva KDE di atas histogram.
3
KDE plot standalone dengan sns.kdeplot(). Gunakan fill=True untuk mengisi area di bawah kurva. Overlay dua distribusi dalam satu Axes: distribusi tip pada hari weekday vs weekend. Gunakan label= untuk setiap kurva dan alpha=0.5 agar overlap terlihat.
4
Bandingkan distribusi antar kelompok dengan parameter hue. Gunakan sns.histplot(data=df, x='total_bill', hue='time', element='step') untuk melihat distribusi lunch vs dinner secara berdampingan dalam satu histogram. Parameter element='step' membuat histogram bertangga, lebih mudah dibaca ketika ada overlap.
5
Latihan: analisis distribusi nilai siswa per kota. Buat dataset nilai 500 siswa dari 4 kota berbeda. Buat subplot 2x2: kiri atas histogram semua kota, kanan atas KDE per kota, kiri bawah histogram per kota dengan facet, kanan bawah KDE stacked. Tulis observasi singkat di bawah setiap chart tentang apa yang bisa disimpulkan dari distribusinya.
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style='whitegrid', palette='muted')
df = sns.load_dataset('tips')

fig, axes = plt.subplots(1, 2, figsize=(13, 5))

# Histogram + KDE overlay
sns.histplot(data=df, x='total_bill', bins=30, kde=True,
             color='steelblue', ax=axes[0])
axes[0].set_title('Distribusi Total Tagihan (Histogram + KDE)')
axes[0].set_xlabel('Total Tagihan ($)')

# KDE per kelompok: lunch vs dinner
sns.kdeplot(data=df, x='total_bill', hue='time',
            fill=True, alpha=0.4, ax=axes[1])
axes[1].set_title('Distribusi Tagihan: Lunch vs Dinner')
axes[1].set_xlabel('Total Tagihan ($)')

plt.tight_layout()
plt.show()
Kapan Histogram vs KDE

Gunakan histogram ketika Abbas ingin menunjukkan frekuensi aktual dan ukuran sampel penting untuk dipahami. Gunakan KDE ketika Abbas ingin membandingkan bentuk distribusi antar beberapa kelompok karena KDE lebih mudah dibaca ketika ada banyak overlay. Kombinasi keduanya adalah pilihan yang paling informatif.

Hari 2

Boxplot dan Violin Plot: Merangkum Distribusi dalam Satu Chart

Boxplot merangkum distribusi dalam 5 angka: minimum, Q1, median, Q3, dan maximum. Violin plot menggabungkan boxplot dengan KDE sehingga bentuk distribusi penuh terlihat. Keduanya adalah chart wajib untuk membandingkan distribusi antar kelompok kategorikal.

1
Baca boxplot dengan benar. Buat sns.boxplot(data=df, x='day', y='total_bill'). Identifikasi setiap elemen: garis tengah kotak = median, tepi bawah kotak = Q1 (persentil 25), tepi atas kotak = Q3 (persentil 75), whisker bawah = Q1 - 1.5*IQR, whisker atas = Q3 + 1.5*IQR, dan titik-titik di luar whisker = outlier. Latihan membaca tanpa melihat nilai numerik.
2
Violin plot: distribusi penuh, bukan hanya ringkasan. Ganti boxplot dengan sns.violinplot(data=df, x='day', y='total_bill', inner='box'). Parameter inner='box' menampilkan mini boxplot di dalam violin. Bandingkan: boxplot hanya menunjukkan statistik ringkasan, violin plot menunjukkan apakah distribusi bimodal, skewed, atau flat.
3
Gunakan hue untuk split per kategori. Tambahkan parameter hue='sex' pada violin plot. Seaborn otomatis membagi setiap violin menjadi dua sisi (split violin) dengan split=True. Ini cara paling kompak untuk membandingkan distribusi 2D (hari x jenis kelamin) dalam satu chart.
4
Tambahkan titik data aktual dengan stripplot. Overlay sns.stripplot(data=df, x='day', y='total_bill', size=3, alpha=0.4, color='black', jitter=True) di atas violin plot. Ini membuat chart "jujur": pembaca bisa melihat tidak hanya distribusi tapi juga jumlah dan penyebaran titik aktual. Gunakan teknik ini ketika n kecil (kurang dari 200 titik).
5
Latihan: bandingkan distribusi nilai siswa per provinsi. Dengan dataset nilai UN, buat violin plot nilai matematika per provinsi (pilih 8 provinsi). Tambahkan stripplot overlay. Urutkan provinsi berdasarkan median nilai menggunakan order=df.groupby('provinsi')['nilai'].median().sort_values(ascending=False).index. Ini adalah teknik yang membuat chart lebih mudah dibaca karena mata manusia otomatis mencari pola dari kiri ke kanan.
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style='whitegrid')
df = sns.load_dataset('tips')

fig, axes = plt.subplots(1, 2, figsize=(13, 5))

# Violin plot dengan inner boxplot
sns.violinplot(data=df, x='day', y='total_bill',
               inner='box', palette='muted', ax=axes[0])
axes[0].set_title('Distribusi Tagihan per Hari')
axes[0].set_xlabel('Hari')
axes[0].set_ylabel('Total Tagihan ($)')

# Split violin: breakdown per jenis kelamin
sns.violinplot(data=df, x='day', y='total_bill', hue='sex',
               split=True, inner='quart', palette='Set2', ax=axes[1])
# Overlay strip plot untuk titik data aktual
sns.stripplot(data=df, x='day', y='total_bill',
              size=2.5, alpha=0.35, color='black',
              jitter=True, ax=axes[1])
axes[1].set_title('Split Violin: Tagihan per Hari dan Jenis Kelamin')

plt.tight_layout()
plt.show()
Hari 3

Heatmap untuk Korelasi Matrix: Lihat Semua Hubungan Sekaligus

Heatmap korelasi adalah chart yang wajib dibuat di awal setiap proyek analisis. Dengan satu chart, Abbas bisa melihat hubungan antara semua pasangan variabel numerik sekaligus, sebelum memutuskan mana yang perlu didalami lebih lanjut.

1
Hitung korelasi matrix dan buat heatmap dasar. Gunakan corr_matrix = df.select_dtypes('number').corr(). Buat heatmap dengan sns.heatmap(corr_matrix, cmap='coolwarm', center=0). Parameter center=0 memastikan warna netral (putih) ada di korelasi nol, merah untuk korelasi positif kuat, biru untuk negatif kuat.
2
Tambahkan nilai korelasi dengan annot=True. Gunakan sns.heatmap(..., annot=True, fmt='.2f', annot_kws={'size': 9}). Dengan nilai tercetak di setiap sel, pembaca tidak perlu menginterpretasikan warna saja. Ini membuat heatmap berguna sebagai tabel dan sebagai visualisasi sekaligus.
3
Hilangkan redundansi dengan mask segitiga atas. Korelasi matrix simetris: korelasi(A,B) sama dengan korelasi(B,A). Tampilkan hanya segitiga bawah. Gunakan mask = np.triu(np.ones_like(corr_matrix, dtype=bool)) lalu tambahkan parameter mask=mask ke sns.heatmap(). Ini membuat chart lebih bersih dan mudah dibaca.
4
Pilih colormap yang tepat untuk konteks. Untuk korelasi: gunakan 'coolwarm' atau 'RdBu_r' (diverging). Untuk data yang semua positif (misalnya confusion matrix): gunakan 'Blues' atau 'viridis' (sequential). Jangan gunakan 'jet' atau 'rainbow' karena tidak perceptually uniform dan bisa menyesatkan pembaca yang buta warna.
5
Latihan: heatmap korelasi dataset Boston Housing. Load dataset dengan from sklearn.datasets import fetch_california_housing. Buat heatmap korelasi dengan mask segitiga atas, annotasi nilai, dan colormap yang tepat. Identifikasi pasangan variabel dengan korelasi lebih dari 0.7 dan tulis interpretasi: "Variabel X dan Y berkorelasi kuat positif, artinya ketika X naik, Y cenderung naik."
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import fetch_california_housing
import pandas as pd

data = fetch_california_housing()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['MedHouseVal'] = data.target

corr = df.corr()
mask = np.triu(np.ones_like(corr, dtype=bool))

fig, ax = plt.subplots(figsize=(10, 8))

sns.heatmap(
    corr,
    mask     = mask,
    cmap     = 'coolwarm',
    center   = 0,
    annot    = True,
    fmt      = '.2f',
    annot_kws= {'size': 8},
    square   = True,
    linewidths = 0.5,
    linecolor  = 'white',
    ax = ax
)

ax.set_title('Korelasi Matrix: California Housing Dataset',
             fontsize=13, fontweight='bold', pad=15)
plt.tight_layout()
plt.show()
Hari 4

Pair Plot: Lihat Semua Relasi Antar Variabel Sekaligus

Pair plot (atau scatter matrix) adalah versi visual dari korelasi matrix, tapi lebih informatif. Alih-alih hanya angka korelasi, pair plot menampilkan distribusi setiap variabel pada diagonal dan scatter plot untuk setiap pasangan variabel di luar diagonal.

1
Buat pair plot dasar dari dataset iris. Gunakan df = sns.load_dataset('iris') lalu sns.pairplot(df). Perhatikan strukturnya: diagonal berisi histogram setiap variabel, off-diagonal berisi scatter plot pasangan variabel. Dengan 4 variabel, ada 4x4=16 panel. Untuk dataset dengan lebih dari 8 variabel, pilih subset kolom yang relevan.
2
Tambahkan hue untuk membedakan kelas atau kategori. Gunakan sns.pairplot(df, hue='species'). Setiap spesies akan memiliki warna berbeda di semua scatter plot sekaligus. Amati: pasangan variabel mana yang paling baik memisahkan ketiga spesies? Ini adalah pertanyaan kunci dalam pemilihan fitur untuk machine learning.
3
Kontrol panel diagonal dengan diag_kind. Bandingkan diag_kind='hist' (histogram pada diagonal) dengan diag_kind='kde' (KDE pada diagonal). KDE lebih informatif untuk melihat apakah distribusi setiap variabel per kelas terpisah atau overlap. Gunakan juga plot_kws={'alpha': 0.5} untuk mengurangi overplotting.
4
Pair plot parsial: pilih subset kolom yang relevan. Untuk dataset dengan banyak kolom, gunakan sns.pairplot(df, vars=['col_a', 'col_b', 'col_c'], hue='target'). Pilih kolom berdasarkan korelasi matrix yang sudah dibuat kemarin: fokus pada variabel yang punya korelasi tinggi dengan target atau antar sesama.
5
Latihan: pair plot untuk housing dataset. Pilih 5 kolom dari California Housing yang paling berkorelasi dengan harga (berdasarkan heatmap hari kemarin). Buat pair plot dengan hue berdasarkan kategori ocean proximity. Tulis 3 observasi konkret: "Variabel X dan Y punya pola linear yang kuat untuk rumah dekat laut, tapi tidak untuk rumah inland."
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style='ticks')
df = sns.load_dataset('penguins').dropna()

g = sns.pairplot(
    df,
    hue      = 'species',
    diag_kind= 'kde',
    plot_kws = {'alpha': 0.55, 'edgecolors': 'white', 'linewidth': 0.4},
    diag_kws = {'fill': True, 'alpha': 0.4},
    palette  = 'Set2'
)

g.figure.suptitle('Pair Plot: Palmer Penguins Dataset',
                  fontsize=14, fontweight='bold', y=1.01)

plt.tight_layout()
plt.show()
Pair Plot sebagai Alat EDA, Bukan Presentasi

Pair plot sangat berguna untuk eksplorasi data internal (Abbas memahami data), tapi jarang digunakan dalam laporan untuk non-technical audience karena terlalu padat. Gunakan pair plot untuk menemukan mana pasangan variabel yang menarik, lalu buat scatter plot individual yang lebih bersih untuk presentasi.

Hari 5

Latihan: Analisis Visual Dataset Housing Prices

Hari ini Abbas menggabungkan semua teknik seaborn minggu ini untuk menganalisis California Housing Dataset secara menyeluruh. Target: menghasilkan 6 chart yang masing-masing menjawab satu pertanyaan analitis.

1
Pertanyaan 1: Bagaimana distribusi harga rumah? Buat sns.histplot(df['MedHouseVal'], bins=50, kde=True). Identifikasi apakah distribusi normal, skewed kanan, atau bimodal. Tambahkan garis vertikal untuk median dan mean menggunakan ax.axvline(). Interpretasi: distribusi skewed kanan berarti ada sedikit rumah sangat mahal yang menarik mean ke atas.
2
Pertanyaan 2: Variabel mana yang paling berkorelasi dengan harga? Buat heatmap korelasi dengan mask segitiga atas dan annotasi nilai. Highlight baris/kolom MedHouseVal dengan warna berbeda. Urutkan variabel berdasarkan korelasi dengan target menggunakan corr['MedHouseVal'].sort_values().
3
Pertanyaan 3: Apakah pendapatan median berkorelasi dengan harga? Buat scatter plot sns.scatterplot(x='MedInc', y='MedHouseVal', alpha=0.15, data=df). Tambahkan garis regresi dengan sns.regplot(). Scatter yang padat di area tertentu menunjukkan pola yang perlu didalami.
4
Pertanyaan 4: Apakah usia rumah mempengaruhi harga? Buat boxplot sns.boxplot(x=pd.cut(df['HouseAge'], bins=5), y='MedHouseVal') untuk membagi usia rumah menjadi 5 kelompok dan melihat distribusi harga per kelompok. Tambahkan judul yang menyatakan temuan, bukan sekadar deskripsi chart.
5
Gabungkan semua dalam laporan visual. Susun semua chart dalam Figure 3x2 menggunakan plt.subplot2grid. Chart 1 (distribusi harga) lebar penuh di baris pertama. Chart 2-5 mengisi baris kedua dan ketiga. Tambahkan judul utama dan caption singkat di bawah setiap chart. Export sebagai PDF menggunakan plt.savefig('housing_analysis.pdf', format='pdf').
Tantangan: Temukan Anomali

Dalam California Housing Dataset, ada cap artifisial di nilai MedHouseVal = 5.0 (nilai maksimum dataset). Ini bisa dilihat dari histogram yang punya spike tidak wajar di ujung kanan. Buat chart yang menunjukkan anomali ini dengan jelas dan tulis interpretasi singkat mengapa anomali ini penting untuk dipahami sebelum membuat model prediksi.

Minggu 3: Plotly untuk Visualisasi Interaktif

Plotly mengubah chart statis menjadi pengalaman yang bisa dijelajahi. Pembaca bisa hover, zoom, filter, dan bahkan menyaksikan data berubah seiring waktu lewat animasi.

Minggu 3

Interaktivitas, Peta Choropleth, dan Animasi Data

Hari 1

Plotly Express vs Plotly Graph Objects: Dua Cara, Satu Tujuan

Plotly punya dua API yang beda filosofinya. Plotly Express (px) adalah API tingkat tinggi: satu baris kode untuk chart lengkap, ideal untuk eksplorasi cepat. Plotly Graph Objects (go) adalah API tingkat rendah: kontrol penuh atas setiap elemen, ideal untuk chart yang sangat dikustomisasi. Abbas perlu menguasai keduanya.

1
Instalasi dan setup lingkungan Plotly. Jalankan pip install plotly. Di Jupyter Notebook, render otomatis. Di VS Code, gunakan fig.show(renderer='browser') agar terbuka di browser. Export ke HTML standalone: fig.write_html('chart.html'). Export ke PNG (butuh kaleido): pip install kaleido lalu fig.write_image('chart.png', scale=2).
2
Buat chart identik dengan px dan go, bandingkan kodenya. Scatter plot gapminder dengan px: import plotly.express as px; df = px.data.gapminder(); fig = px.scatter(df[df.year==2007], x='gdpPercap', y='lifeExp', size='pop', color='continent', hover_name='country'). Buat chart yang sama dengan import plotly.graph_objects as go. Perhatikan perbedaan jumlah baris kode.
3
Pahami struktur objek Figure plotly. Jalankan fig.to_dict() untuk melihat struktur JSON di balik setiap Figure. Tiga komponen utama: data (list of traces), layout (pengaturan tampilan), dan frames (untuk animasi). Pahami ini karena semua kustomisasi plotly akhirnya bermuara ke memodifikasi tiga komponen ini.
4
Update layout dengan fig.update_layout(). Setelah membuat chart dengan px, kustomisasi lebih lanjut menggunakan fig.update_layout(title='Judul Baru', title_font_size=18, plot_bgcolor='white', paper_bgcolor='white', font_family='Arial'). Ini adalah cara menggabungkan kemudahan px dengan fleksibilitas go.
5
Eksplorasi fitur interaktivitas bawaan. Buat scatter plot gapminder. Klik item di legend untuk menyembunyikan/menampilkan kontinen. Double-click untuk isolate satu kontinen. Zoom dengan drag. Pan dengan shift+drag. Hover untuk melihat tooltip. Reset dengan double-click. Semua ini sudah built-in tanpa kode tambahan.
import plotly.express as px
import plotly.graph_objects as go

# Cara 1: Plotly Express (singkat, cepat)
df = px.data.gapminder()
df_2007 = df[df['year'] == 2007]

fig_px = px.scatter(
    df_2007,
    x            = 'gdpPercap',
    y            = 'lifeExp',
    size         = 'pop',
    color        = 'continent',
    hover_name   = 'country',
    log_x        = True,
    size_max     = 55,
    title        = 'GDP vs Harapan Hidup (2007)',
    labels       = {'gdpPercap': 'GDP per Kapita (USD, log)',
                    'lifeExp': 'Harapan Hidup (tahun)'}
)
fig_px.update_layout(
    plot_bgcolor  = 'white',
    paper_bgcolor = 'white',
    font_family   = 'Arial'
)
fig_px.show()

# Export ke file HTML standalone
fig_px.write_html('gdp_vs_lifeexp.html', include_plotlyjs='cdn')
Panduan Memilih px vs go

Gunakan Plotly Express untuk eksplorasi cepat dan chart standar (scatter, bar, line, histogram, choropleth). Mulai dengan px, lalu perbaiki dengan update_layout() dan update_traces(). Beralih ke Graph Objects hanya jika px tidak bisa menghasilkan layout yang Abbas butuhkan, misalnya untuk chart yang menggabungkan beberapa tipe trace dalam satu Figure.

Hari 2

Interactive Bar, Line, dan Scatter dengan Hover Info yang Kaya

Interaktivitas plotly bukan sekadar fitur estetika. Hover tooltip yang dirancang dengan baik bisa menggantikan puluhan label statis dan membuat pembaca aktif mengeksplorasi data alih-alih pasif membacanya.

1
Buat bar chart interaktif dengan hover data kaya. Gunakan px.bar(df, x='kota', y='penjualan', hover_data=['margin', 'target', 'growth_pct'], color='status'). Tambahkan hover_name='kota' untuk nama besar di atas tooltip. Perhatikan bahwa dengan plotly, satu bar chart sudah bisa menampilkan 5+ dimensi informasi hanya lewat tooltip.
2
Kustomisasi tooltip dengan hovertemplate. Template default plotly sering terlalu teknis. Ganti dengan: fig.update_traces(hovertemplate='<b>%{x}</b><br>Penjualan: Rp %{y:,.0f}<br>Pertumbuhan: %{customdata[0]:.1f}%'). Tambahkan customdata=df[['growth_pct']].values. Tooltip yang baik langsung menjawab pertanyaan pembaca tanpa perlu membaca axis.
3
Line chart interaktif dengan facet columns. Gunakan px.line(df, x='bulan', y='nilai', color='provinsi', facet_col='mata_pelajaran', facet_col_wrap=2). Facet membagi chart menjadi panel per kategori. Klik item legend untuk highlight/hide provinsi tertentu di semua panel sekaligus karena plotly sinkronisasi legend antar facet.
4
Scatter interaktif dengan size, color, dan symbol sebagai dimensi berbeda. Gunakan px.scatter(df, x='X', y='Y', size='populasi', color='IPM', symbol='pulau', hover_name='provinsi'). Parameter symbol membedakan bentuk marker per kategori, berguna untuk membedakan kelompok tanpa hanya mengandalkan warna (lebih accessible untuk color-blind).
5
Latihan: dashboard penjualan interaktif 3 chart. Buat tiga chart dalam satu layout menggunakan from plotly.subplots import make_subplots; fig = make_subplots(rows=1, cols=3). Chart 1: bar chart penjualan per kota. Chart 2: line chart tren bulanan. Chart 3: scatter plot margin vs penjualan. Export ke HTML: fig.write_html('dashboard.html').
import plotly.express as px
import pandas as pd
import numpy as np

np.random.seed(1)
kota = ['Jakarta', 'Surabaya', 'Bandung', 'Medan', 'Makassar']
df = pd.DataFrame({
    'kota'       : kota,
    'penjualan'  : np.random.randint(800, 3000, 5),
    'target'     : np.random.randint(1000, 2500, 5),
    'growth_pct' : np.random.uniform(-5, 25, 5).round(1),
})
df['status'] = df.apply(lambda r: 'Tercapai' if r.penjualan >= r.target else 'Di Bawah Target', axis=1)

fig = px.bar(
    df.sort_values('penjualan', ascending=False),
    x          = 'kota',
    y          = 'penjualan',
    color      = 'status',
    hover_name = 'kota',
    hover_data = {'target': True, 'growth_pct': ':.1f', 'status': False},
    color_discrete_map = {'Tercapai': '#2ecc71', 'Di Bawah Target': '#e74c3c'},
    title      = 'Penjualan per Kota vs Target',
    labels     = {'penjualan': 'Penjualan (juta Rp)', 'kota': 'Kota'}
)
fig.update_layout(plot_bgcolor='white', paper_bgcolor='white')
fig.write_html('penjualan_kota.html')
fig.show()
Hari 3

Choropleth Map Indonesia: Data per Provinsi di Atas Peta

Choropleth map mewarnai wilayah geografis berdasarkan nilai data. Untuk data Indonesia per provinsi, ini adalah cara visualisasi yang paling intuitif: semua orang langsung tahu wilayah mana yang tinggi dan rendah tanpa perlu membaca tabel.

1
Siapkan GeoJSON Indonesia. Download file GeoJSON batas provinsi Indonesia dari GitHub: url = 'https://raw.githubusercontent.com/superpikar/indonesia-geojson/master/indonesia.geojson'. Load dengan import requests, json; geojson = json.loads(requests.get(url).text). Perhatikan struktur: setiap feature punya properties.state berisi nama provinsi. Nama ini harus cocok persis dengan kolom di DataFrame.
2
Siapkan data per provinsi dan pastikan nama cocok. Buat DataFrame berisi semua 34 provinsi dengan kolom nilai (misalnya IPM, kemiskinan, atau pendidikan). Periksa nama provinsi di GeoJSON dan di DataFrame, sering ada perbedaan ejaan seperti "Daerah Istimewa Yogyakarta" vs "DI Yogyakarta". Standardisasi nama dengan dictionary mapping sebelum lanjut.
3
Buat choropleth dengan px.choropleth_mapbox(). Gunakan mapbox_style='carto-positron' untuk basemap yang bersih. Parameter kunci: geojson=geojson, locations='nama_provinsi', featureidkey='properties.state', color='nilai', color_continuous_scale='RdYlGn'. Set zoom=4 dan center={"lat": -2.5, "lon": 118} untuk posisi awal Indonesia.
4
Kustomisasi hover tooltip dengan informasi kontekstual. Tambahkan hover_data={'nilai': True, 'rank': True, 'kategori': True}. Update hovertemplate agar tooltip menampilkan nama provinsi besar, nilai dengan format yang tepat, dan rank nasional. Tooltip yang baik membuat peta bisa berdiri sendiri sebagai alat eksplorasi.
5
Latihan: peta IPM per provinsi Indonesia tahun 2023. Download data IPM dari BPS (bps.go.id, tersedia sebagai CSV). Buat choropleth dengan colorscale yang tepat. Tambahkan judul aktif: "Provinsi Papua Masih Punya IPM Terendah di Indonesia (2023)". Export sebagai HTML dan bagikan ke teman untuk diminta feedback: apakah pesannya langsung dipahami?
import plotly.express as px
import pandas as pd
import requests, json

# Load GeoJSON Indonesia
url = 'https://raw.githubusercontent.com/superpikar/indonesia-geojson/master/indonesia.geojson'
geojson = json.loads(requests.get(url).text)

# Data IPM per provinsi (contoh - gunakan data BPS asli)
df = pd.DataFrame({
    'provinsi': ['Aceh', 'Sumatera Utara', 'Riau', 'Jawa Barat',
                 'Jawa Tengah', 'DI Yogyakarta', 'Jawa Timur', 'Bali',
                 'Kalimantan Timur', 'Papua'],
    'ipm'     : [72.6, 73.8, 73.5, 73.0,
                 73.3, 82.5, 73.4, 79.9,
                 78.2, 61.4]
})

fig = px.choropleth_mapbox(
    df,
    geojson          = geojson,
    locations        = 'provinsi',
    featureidkey     = 'properties.state',
    color            = 'ipm',
    color_continuous_scale = 'RdYlGn',
    range_color      = (60, 85),
    mapbox_style     = 'carto-positron',
    zoom             = 3.8,
    center           = {'lat': -2.5, 'lon': 118},
    opacity          = 0.8,
    hover_name       = 'provinsi',
    hover_data       = {'ipm': ':.1f'},
    title            = 'Indeks Pembangunan Manusia per Provinsi, 2023'
)
fig.update_layout(margin={'r':0, 't':40, 'l':0, 'b':0})
fig.write_html('ipm_indonesia.html')
fig.show()
Hari 4

Animated Chart: Visualisasikan Data yang Berubah dari Waktu ke Waktu

Animasi mengungkap dimensi yang tidak bisa ditangkap oleh chart statis: perubahan seiring waktu. Hans Rosling mempopulerkan ini di TED Talk-nya dengan bubble chart yang bergerak. Plotly membuat teknik yang sama bisa direproduksi Abbas dalam hitungan baris kode.

1
Animated bubble chart: GDP vs harapan hidup dari 1952-2007. Gunakan dataset gapminder bawaan plotly. Tambahkan animation_frame='year' dan animation_group='country' ke px.scatter(). Parameter animation_group memastikan setiap titik (negara) bergerak secara smooth dari satu frame ke frame berikutnya, bukan melompat tiba-tiba.
2
Kontrol kecepatan dan tampilan animasi. Setelah membuat animated chart, atur kecepatan dengan fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 800. Tambahkan slider tahun yang otomatis muncul. Pembaca bisa klik play untuk otomatis, atau drag slider untuk manual. Ini membuat animasi jauh lebih berguna dari GIF statis.
3
Animated bar chart race: nilai per provinsi per tahun. Gunakan px.bar(df, x='nilai', y='provinsi', animation_frame='tahun', orientation='h', range_x=[0, 100]). Bar chart race adalah format yang viral di media sosial karena menunjukkan perubahan ranking secara dramatis. Pastikan sumbu x punya range tetap (range_x) agar perbandingan antar frame adil.
4
Animated choropleth: peta yang berubah per tahun. Tambahkan animation_frame='tahun' ke px.choropleth_mapbox(). Ini menggabungkan peta dan animasi dalam satu chart. Gunakan untuk menunjukkan bagaimana distribusi kemiskinan atau IPM per provinsi berubah dari 2010 ke 2023.
5
Export animasi ke file yang bisa dibagikan. Export ke HTML: fig.write_html('animasi.html', include_plotlyjs='cdn'). File ini bisa dibuka di browser manapun tanpa perlu instalasi Python. Untuk embed di web, gunakan include_plotlyjs='cdn' agar ukuran file tetap kecil. Untuk dibagikan offline, gunakan include_plotlyjs=True.
import plotly.express as px

df = px.data.gapminder()

fig = px.scatter(
    df,
    x              = 'gdpPercap',
    y              = 'lifeExp',
    size           = 'pop',
    color          = 'continent',
    hover_name     = 'country',
    animation_frame= 'year',
    animation_group= 'country',
    log_x          = True,
    size_max       = 55,
    range_x        = [100, 100000],
    range_y        = [25, 90],
    title          = 'GDP per Kapita vs Harapan Hidup, 1952-2007',
    labels         = {
        'gdpPercap': 'GDP per Kapita (USD, log scale)',
        'lifeExp'  : 'Harapan Hidup (tahun)',
        'pop'      : 'Populasi'
    }
)

# Percepat animasi menjadi 500ms per frame
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 500
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 400

fig.update_layout(plot_bgcolor='white', paper_bgcolor='white')
fig.write_html('gapminder_animasi.html', include_plotlyjs='cdn')
fig.show()
Hari 5

Latihan: Dashboard Mini Interaktif, Pendidikan per Provinsi Indonesia

Hari ini Abbas membangun dashboard mini yang menggabungkan semua teknik plotly minggu ini: bar chart interaktif, choropleth map, dan scatter plot, semuanya dalam satu file HTML yang siap dibagikan.

1
Siapkan dataset pendidikan per provinsi. Kumpulkan 3-4 indikator dari BPS: Angka Partisipasi Murni (APM) SD, SMP, SMA, dan Angka Melek Huruf per provinsi. Pastikan data sudah bersih: tidak ada missing value, nama provinsi konsisten dengan GeoJSON, format numerik. Simpan sebagai satu DataFrame yang akan dipakai semua chart.
2
Chart 1: Horizontal bar chart APM SMA per provinsi, diurutkan. Buat dengan px.bar(..., orientation='h'). Urutkan dari tertinggi ke terendah. Warnai bar berdasarkan wilayah geografis (Jawa, Sumatera, dll). Tambahkan garis rata-rata nasional sebagai referensi dengan fig.add_vline(x=rata_rata, line_dash='dash', line_color='gray').
3
Chart 2: Choropleth map angka melek huruf per provinsi. Gunakan GeoJSON Indonesia. Pilih colorscale yang intuitif: hijau untuk melek huruf tinggi, merah untuk rendah ('RdYlGn'). Set range colorscale ke 85-100 agar perbedaan antar provinsi terlihat jelas (jangan gunakan range otomatis yang akan membuat perbedaan kecil terlihat besar).
4
Chart 3: Scatter plot APM vs IPM, bubbles = populasi usia sekolah. Gunakan px.scatter() dengan size, color, dan hover_name. Tambahkan garis tren menggunakan px.scatter(..., trendline='ols') yang otomatis menghitung dan memplot regresi linear. Perhatikan provinsi mana yang di atas atau di bawah tren nasional.
5
Gabungkan tiga chart dalam satu HTML menggunakan subplots. Gunakan make_subplots(rows=2, cols=2, specs=[[{'type': 'bar'}, {'type': 'mapbox'}], [{'type': 'scatter', 'colspan': 2}, None]]) untuk layout: bar dan peta di atas, scatter lebar penuh di bawah. Tambahkan judul utama dashboard. Export ke dashboard_pendidikan.html dan pastikan semua interaktivitas berfungsi di browser.
Tantangan: Tambahkan Dropdown Filter

Coba tambahkan dropdown filter menggunakan fig.update_layout(updatemenus=[dict(buttons=[...])]) untuk memilih indikator yang ditampilkan di choropleth: APM SD, APM SMP, APM SMA, atau Melek Huruf. Ini mengubah satu peta statis menjadi alat eksplorasi yang bisa menjawab beberapa pertanyaan sekaligus.

Minggu 4: Prinsip Desain Visualisasi

Teknis sudah dikuasai. Minggu ini Abbas naik level: belajar mengapa chart yang secara teknis benar masih bisa gagal berkomunikasi, dan bagaimana merancang visualisasi yang benar-benar mengubah cara orang melihat data.

Minggu 4

Tufte, Warna, Storytelling, dan Proyek Visual Akhir

Hari 1

Chart Junk vs Data-Ink Ratio: Prinsip Tufte untuk Chart yang Jujur

Edward Tufte, profesor statistik di Yale, merumuskan prinsip yang mengubah cara dunia melihat visualisasi data. Inti ajarannya sederhana: setiap piksel dalam chart harus membawa informasi. Semua yang tidak membawa informasi adalah "chart junk" yang perlu dihilangkan.

1
Hitung data-ink ratio secara konseptual. Data-ink ratio = (tinta untuk data) / (total tinta dalam chart). Ratio ideal mendekati 1.0. Buka 5 chart dari Google Images dengan query "infographic Indonesia 2023". Untuk setiap chart, identifikasi berapa persen "tinta" yang benar-benar menyampaikan data (garis, bar, titik) vs yang dekoratif (background gambar, shadow, efek 3D, border tebal).
2
Identifikasi dan eliminasi chart junk yang paling umum. Buat daftar elemen yang hampir selalu bisa dihilangkan: (a) 3D effect pada bar chart, (b) shadow dan glow pada elemen chart, (c) background image atau gradient, (d) gridlines tebal dan gelap, (e) border kotak di sekitar chart, (f) legend yang redundan ketika label sudah ada langsung di chart, (g) warna yang berbeda pada bar chart yang hanya punya satu kategori.
3
Praktik before-after: bersihkan chart yang buruk. Ambil satu chart dengan banyak chart junk. Reproduksi di matplotlib, lalu buat versi "after" yang bersih dengan menghilangkan semua elemen dekoratif. Bandingkan keduanya berdampingan. Dalam hampir semua kasus, versi yang lebih bersih lebih mudah dibaca dan lebih profesional.
4
Kenali chart yang secara aktif menyesatkan. Pelajari tiga jenis chart yang sering menyesatkan: (a) Y-axis yang tidak mulai dari nol pada bar chart sehingga perbedaan kecil terlihat dramatis, (b) pie chart dengan banyak irisan tipis yang tidak bisa dibedakan, (c) dual Y-axis yang bisa membuat dua tren tidak berhubungan terlihat seolah berkorelasi. Buat contoh masing-masing dan jelaskan mengapa menyesatkan.
5
Latihan audit chart Indonesia. Cari 5 chart dari laporan resmi pemerintah atau media berita Indonesia. Beri nilai 1-10 untuk setiap chart berdasarkan data-ink ratio (1 = banyak junk, 10 = sangat bersih). Tulis satu saran spesifik perbaikan untuk setiap chart. Ini melatih Abbas mengembangkan "mata kritis" terhadap visualisasi.
Kutipan Tufte yang Perlu Diingat

"The interior decoration of graphics generates a lot of ink that does not tell the viewer anything new. The purpose of decoration varies: to make the graphic appear more scientific and precise, to enliven the display, to give the designer an opportunity to exercise artistic skills. Regardless of purpose, decoration can turn bores into disasters." Terjemahan bebas: dekorasi berlebihan bukan hanya tidak berguna, tapi aktif merusak komunikasi data.

Hari 2

Pemilihan Warna yang Accessible dan Bermakna

Warna adalah dimensi yang paling sering disalahgunakan dalam visualisasi. Pemilihan warna yang buruk bisa membuat chart tidak bisa dibaca oleh penderita buta warna (8% pria) atau membuat pesan yang salah karena asosiasi warna yang tidak sesuai konteks.

1
Pahami tiga jenis palette warna dan kapan menggunakannya. Sequential (Blues, Greens, viridis): untuk data yang berurutan dari rendah ke tinggi, seperti kemiskinan atau IPM. Diverging (RdBu, coolwarm): untuk data yang punya titik tengah bermakna, seperti pertumbuhan (positif/negatif) atau korelasi (-1 sampai +1). Qualitative (Set1, tab10): untuk kategori yang tidak punya urutan, seperti provinsi atau jenis produk.
2
Gunakan ColorBrewer untuk palette yang sudah diuji. Kunjungi colorbrewer2.org. Pilih jumlah kelas, pilih tipe (sequential/diverging/qualitative), dan aktifkan filter "colorblind safe" serta "print friendly". Salin kode hex ke matplotlib: colors = ['#1b9e77', '#d95f02', '#7570b3']. ColorBrewer adalah standar de facto untuk kartografi dan visualisasi data ilmiah.
3
Simulasikan buta warna pada chart Abbas. Export chart sebagai PNG, lalu upload ke coblis.com (Color Blindness Simulator). Cek apakah chart masih bisa dibaca dengan deuteranopia (paling umum, tidak bisa membedakan merah-hijau) dan protanopia. Jika tidak, ganti palette. Alternatif: gunakan cmap='viridis' yang dirancang agar perceptually uniform dan aman untuk semua jenis buta warna.
4
Gunakan warna sebagai alat emphasis, bukan dekorasi. Prinsip: satu warna highlight untuk satu pesan. Buat bar chart di mana semua bar abu-abu kecuali satu bar yang ingin Abbas soroti berwarna biru atau merah. Teknik ini, yang disebut "single color highlight", membuat mata pembaca langsung tertuju ke elemen yang paling penting tanpa perlu membaca teks penjelasan.
5
Praktik: redesign chart dengan warna yang lebih baik. Ambil salah satu chart dari minggu 1 atau 2 yang menggunakan warna default matplotlib (biru, oranye, hijau yang terlalu saturasi). Redesign menggunakan palette ColorBrewer yang sesuai konteks. Gunakan hanya 2-3 warna maksimal per chart. Bandingkan hasilnya dan dokumentasikan alasan setiap pilihan warna.
Aturan Warna yang Paling Praktis

Untuk categorical data: maksimal 7 warna, karena mata manusia kesulitan membedakan lebih dari itu. Untuk data ordinal: selalu gunakan palette sequential (satu hue, gradasi gelap-terang). Untuk data dengan nilai positif dan negatif: selalu gunakan diverging palette dengan warna netral di tengah. Dan selalu: hindari merah-hijau sebagai satu-satunya pembeda, karena itu adalah kombinasi yang paling sering tidak bisa dibedakan oleh penderita buta warna.

Hari 3

Storytelling dengan Data: Chart yang Punya Pesan, Bukan Sekadar Gambar

Seorang analyst yang baik menemukan insight. Seorang analyst yang hebat mengkomunikasikan insight tersebut sehingga orang lain mengambil keputusan. Perbedaannya ada di storytelling. Chart yang hanya menampilkan data adalah chart yang gagal separuh tugasnya.

1
Ubah judul deskriptif menjadi judul yang berpesan. Judul deskriptif: "Grafik Penjualan Kuartal 1-4 Tahun 2023" hanya mendeskripsikan isi chart. Judul yang berpesan: "Penjualan Q4 Melonjak 34% karena Kampanye Harbolnas" langsung menyampaikan insight. Ambil 5 chart dari minggu sebelumnya dan ubah judulnya dari deskriptif menjadi berpesan. Ini adalah perubahan paling berdampak yang bisa Abbas lakukan pada sebuah chart.
2
Gunakan anotasi untuk mengarahkan perhatian pembaca. Tambahkan ax.annotate('Penurunan akibat pandemi', xy=(titik_x, titik_y), xytext=(offset_x, offset_y), arrowprops=dict(arrowstyle='->', color='gray')). Anotasi adalah pengganti narasi lisan dalam presentasi tatap muka. Setiap chart yang akan dilihat tanpa penjelasan verbal harus punya anotasi yang menjelaskan momen paling penting.
3
Pelajari framework "Context, Complication, Resolution" (CCR). Setiap laporan visual yang baik mengikuti struktur: (a) Context: ini kondisi normalnya, (b) Complication: ada sesuatu yang berubah atau mengejutkan, (c) Resolution: ini implikasinya atau rekomendasi yang harus diambil. Buat 3 chart yang masing-masing mewakili satu fase CCR menggunakan data pendidikan atau ekonomi Indonesia.
4
Highlight satu angka kunci per slide atau per chart. Teknik dari Cole Nussbaumer Knaflic: pilih satu angka atau satu titik yang paling penting, buat ia jauh lebih besar atau lebih berwarna dari yang lain. Pembaca yang hanya melihat chart 3 detik harus tetap mendapatkan pesan utama. Buat versi "executive summary" dari satu chart dengan satu angka besar di tengah dan konteks minimal di sekeliling.
5
Latihan: ceritakan satu narasi dengan tiga chart yang terhubung. Pilih topik: "Mengapa nilai matematika siswa Indonesia turun sejak 2019?" Buat tiga chart: Chart 1 menunjukkan tren penurunan (Context + Complication). Chart 2 menunjukkan variabel yang berkorelasi dengan penurunan (analisis penyebab). Chart 3 menunjukkan provinsi yang berhasil mempertahankan nilai dan apa yang berbeda (Resolution). Tiga chart ini harus bisa menceritakan satu cerita yang utuh.
Perbedaan Data Analyst Biasa vs Analyst yang Berdampak

Analyst biasa menjawab pertanyaan yang ditanya. Analyst yang berdampak menjawab pertanyaan yang belum ditanya, mengemas jawabannya dalam narasi yang jelas, dan membuat pembuat keputusan mudah bertindak berdasarkan temuannya. Storytelling adalah skill yang membedakan keduanya, dan seperti semua skill, bisa dipelajari dan dilatih.

Hari 4

Kapan Tabel Lebih Baik dari Chart

Salah satu kesalahan analyst junior yang paling umum adalah memaksa semua data menjadi chart. Ada situasi di mana tabel adalah cara yang lebih jelas dan lebih jujur untuk menyampaikan informasi. Abbas perlu tahu kapan harus berhenti menggambar chart.

1
Kenali situasi di mana tabel lebih unggul dari chart. Tabel lebih baik ketika: (a) pembaca perlu mencari nilai spesifik satu entitas, bukan melihat pola keseluruhan, (b) data punya banyak dimensi yang tidak bisa dipetakan ke koordinat X-Y tanpa kehilangan informasi, (c) presisi numerik penting dan nilai eksak harus bisa dibaca, (d) pembaca akan membandingkan nilai non-adjacent (misalnya baris 1 vs baris 15). Chart lebih baik untuk pola dan tren; tabel lebih baik untuk lookup dan referensi.
2
Buat tabel yang bisa dibaca dengan cepat menggunakan pandas Styler. Gunakan df.style.background_gradient(cmap='Blues', subset=['nilai']) untuk memberi warna gradasi pada kolom numerik. Tambahkan .bar(subset=['persen'], color='steelblue') untuk mini bar chart di dalam sel tabel. Hasilnya adalah "heatmap table" yang mempertahankan kemudahan lookup tabel tapi menambahkan konteks visual.
3
Sparkline: mini chart di dalam tabel. Konsep sparkline (dicetuskan Tufte) adalah chart miniatur, lebar sekitar 1-2 cm, yang diembed di dalam sel tabel. Di Python, bisa dibuat dengan matplotlib figure kecil yang disimpan sebagai base64 image dan dimasukkan ke HTML tabel. Ini adalah cara terbaik menggabungkan kelebihan tabel (lookup) dan chart (tren).
4
Latihan keputusan untuk 5 skenario bisnis nyata. Untuk setiap skenario, putuskan: tabel atau chart? (a) Perbandingan harga 50 produk untuk referensi pembelian. (b) Tren penjualan 12 bulan terakhir untuk rapat manajemen. (c) Daftar 10 karyawan terbaik beserta skor dan departemen. (d) Distribusi nilai ujian 500 siswa untuk presentasi ke dinas pendidikan. (e) Perbandingan APM pendidikan 34 provinsi untuk laporan kinerja. Tulis alasan untuk setiap keputusan.
5
Buat framework keputusan pribadi Abbas. Setelah latihan di atas, buat flowchart sederhana atau checklist: pertanyaan apa yang Abbas tanyakan kepada diri sendiri sebelum memilih tabel atau chart. Simpan ini sebagai referensi untuk digunakan di setiap proyek berikutnya. Keputusan yang baik dimulai dari pertanyaan yang tepat, bukan dari "chart apa yang ingin Abbas buat."
import pandas as pd
import numpy as np

# Tabel dengan conditional formatting menggunakan pandas Styler
np.random.seed(3)
provinsi = ['DI Yogyakarta', 'DKI Jakarta', 'Bali', 'Jawa Timur',
            'Jawa Tengah', 'Sumatera Barat', 'Kalimantan Timur', 'Papua']

df = pd.DataFrame({
    'Provinsi'   : provinsi,
    'APM SD (%)' : np.random.uniform(85, 99, 8).round(1),
    'APM SMP (%)': np.random.uniform(70, 95, 8).round(1),
    'APM SMA (%)': np.random.uniform(55, 90, 8).round(1),
    'IPM'        : np.random.uniform(62, 83, 8).round(1),
})

styled = (
    df.style
    .background_gradient(cmap='Blues', subset=['APM SD (%)', 'APM SMP (%)', 'APM SMA (%)'])
    .background_gradient(cmap='YlOrRd', subset=['IPM'])
    .format({'APM SD (%)': '{:.1f}', 'APM SMP (%)': '{:.1f}',
             'APM SMA (%)': '{:.1f}', 'IPM': '{:.1f}'})
    .set_caption('Indikator Pendidikan per Provinsi (2023)')
)
styled.to_html('tabel_pendidikan.html')
Hari 5

Mini Project: Laporan Visual 10 Chart tentang Data Publik Indonesia

Ini adalah proyek paling penting Bulan 6. Abbas membuat laporan visual yang siap dipresentasikan kepada audience non-teknis: menggunakan semua prinsip yang sudah dipelajari dari Minggu 1 hingga hari ini. Bukan sekadar kumpulan chart, tapi sebuah cerita yang utuh.

1
Pilih topik dan kumpulkan data publik Indonesia. Rekomendasi topik: (a) "Potret Kesenjangan Pendidikan Indonesia 2023" menggunakan data BPS dan Kemdikbud, (b) "Perkembangan Ekonomi Digital Indonesia 2018-2023" menggunakan data Kominfo dan Bank Indonesia, atau (c) "Kesehatan Masyarakat Pasca-Pandemi: Apa yang Berubah?" menggunakan data Kemenkes. Pilih topik yang Abbas benar-benar ingin pahami, bukan hanya yang datanya mudah.
2
Rancang struktur naratif sebelum membuat satu chart pun. Tulis outline dalam bentuk 10 kalimat, masing-masing adalah insight yang akan ditampilkan oleh satu chart. Contoh: "1. Angka buta huruf turun 60% dalam 20 tahun. 2. Tapi kesenjangan antar provinsi masih sangat lebar. 3. Papua punya angka buta huruf 12x lebih tinggi dari DI Yogyakarta..." dan seterusnya. Outline ini adalah "script" laporan visual Abbas.
3
Buat 10 chart dengan standar kualitas penuh. Setiap chart harus memenuhi: (a) judul aktif yang menyatakan insight, (b) label axis dengan satuan yang jelas, (c) palette warna yang sesuai konteks dan accessible, (d) tidak ada chart junk, (e) anotasi untuk momen paling penting, (f) sumber data di sudut bawah kanan. Gunakan kombinasi matplotlib, seaborn, dan plotly sesuai jenis chart.
4
Susun semua chart dalam laporan HTML yang rapi. Buat file HTML dengan struktur: judul laporan, 2-3 kalimat executive summary, lalu 10 chart masing-masing dengan judul dan paragraf singkat (2-3 kalimat) yang menjelaskan konteks dan implikasi. Untuk chart plotly, embed langsung sebagai HTML interaktif. Untuk chart matplotlib/seaborn, export ke PNG dan embed sebagai gambar.
5
Review dan iterasi: tunjukkan ke seseorang yang non-teknis. Minta seseorang yang bukan data analyst untuk membaca laporan selama 5 menit. Minta mereka menceritakan 3 hal yang mereka pelajari dari laporan tersebut. Jika mereka tidak bisa, itu adalah feedback yang jujur: chart terlalu teknis, judul tidak cukup jelas, atau narasi tidak cukup membantu. Iterasi berdasarkan feedback ini sebelum dianggap selesai.
Standar Kelulusan Proyek Akhir

Laporan visual Abbas dianggap berhasil jika memenuhi tiga kriteria: (1) Seseorang yang belum pernah melihat datanya bisa memahami semua chart tanpa penjelasan verbal. (2) Setiap chart punya satu pesan yang jelas dan tidak ambigu. (3) Setelah membaca seluruh laporan, pembaca tahu apa yang harus dilakukan atau dipikirkan selanjutnya. Jika salah satu dari tiga kriteria ini tidak terpenuhi, laporan masih belum selesai.

Referensi Buku

Empat buku yang membentuk fondasi pemikiran tentang visualisasi data. Abbas tidak perlu membaca semua dalam satu bulan, tapi setidaknya baca satu secara penuh dan tiga sisanya sebagai referensi.

SWD

Storytelling with Data

Cole Nussbaumer Knaflic

2015, Wiley

Buku paling praktis tentang bagaimana mengkomunikasikan data kepada audience bisnis. Knaflic bekerja di Google sebelum menulis ini, dan setiap prinsip di buku ini langsung bisa diterapkan. Fokus pada: memilih chart yang tepat, menghilangkan clutter, menggunakan warna sebagai emphasis, dan merancang narasi yang efektif. Wajib dibaca penuh oleh Abbas karena ini adalah "missing manual" yang tidak diajarkan di kursus teknis manapun.

Storytelling Desain Business Wajib Baca
VDQI

The Visual Display of Quantitative Information

Edward R. Tufte

1983, Graphics Press

Buku klasik yang mendefinisikan standar untuk visualisasi data ilmiah dan analitis. Tufte memperkenalkan konsep data-ink ratio, chart junk, dan sparkline yang masih relevan hingga hari ini. Buku ini lebih tentang filosofi dan prinsip daripada teknis, tapi membacanya akan mengubah cara Abbas melihat setiap chart yang pernah ada. Tersedia di perpustakaan digital, atau beli edisi cetak karena desain fisik bukunya sendiri adalah demonstrasi prinsipnya.

Prinsip Klasik Akademik Filosofi
FDV

Fundamentals of Data Visualization

Claus O. Wilke

2019, O'Reilly (Gratis online)

Buku terlengkap dan paling komprehensif tentang prinsip visualisasi yang tersedia gratis di clauswilke.com/dataviz. Wilke adalah profesor biologi komputasi di UT Austin. Buku ini mencakup hampir setiap jenis chart yang pernah ada, kapan menggunakannya, dan kapan menghindarinya. Sangat berguna sebagai referensi ketika Abbas menghadapi pertanyaan "chart apa yang paling cocok untuk data jenis ini?" Bisa dibaca per bab sesuai kebutuhan.

Referensi Gratis Komprehensif Ilmiah
DVH

Data Visualisation: A Handbook for Data Driven Design

Andy Kirk

2016, SAGE Publications

Buku yang paling berorientasi pada proses desain. Kirk mengajarkan cara berpikir sistematis tentang visualisasi: mulai dari mendefinisikan tujuan, memilih data yang relevan, merancang visual, hingga mengevaluasi hasilnya. Sangat berguna untuk Abbas ketika mengerjakan proyek besar yang perlu alur kerja yang terstruktur. Juga mencakup banyak case study dari berbagai industri yang membuat prinsip-prinsipnya lebih konkret dan mudah dipahami.

Proses Desain Case Study Praktis Industri

Tools dan Ekosistem Visualisasi

Python bukan satu-satunya cara. Abbas perlu tahu tools apa saja yang ada di ekosistem, kapan menggunakan masing-masing, dan mana yang paling sesuai untuk konteks yang berbeda.

Py

Matplotlib

Python Library

Fondasi semua visualisasi Python. Memberikan kontrol penuh atas setiap piksel. Semua library visualisasi Python lain dibangun di atas matplotlib atau terinspirasi olehnya. Lambat untuk eksplorasi cepat tapi tak tertandingi untuk chart yang sangat dikustomisasi.

Terbaik untuk: Chart yang butuh kontrol presisi tinggi, publikasi ilmiah, chart yang tidak bisa dibuat library lain
Instalasi: pip install matplotlib
Dokumentasi: matplotlib.org/stable/gallery
Static High Control Publication
Sb

Seaborn

Python Library

Statistical data visualization berbasis matplotlib. Satu baris kode menghasilkan chart yang butuh 20 baris di matplotlib mentah. Default style seaborn jauh lebih baik dari matplotlib. Ideal untuk EDA (Exploratory Data Analysis) karena sangat mudah membuat chart statistik seperti boxplot, violin, heatmap, dan pair plot.

Terbaik untuk: EDA, statistical charts, distribusi, korelasi, perbandingan antar kelompok
Instalasi: pip install seaborn
Dokumentasi: seaborn.pydata.org/examples
Statistical EDA Fast Prototyping
Px

Plotly

Python Library

Library visualisasi interaktif berbasis web (WebGL dan SVG). Output adalah chart HTML yang bisa dibuka di browser manapun tanpa Python. Mendukung 40+ jenis chart termasuk choropleth map, 3D scatter, animated chart, dan treemap. Plotly Express menyederhanakan API untuk kasus umum; Graph Objects memberikan kontrol penuh.

Terbaik untuk: Dashboard interaktif, presentasi web, peta, animasi, chart yang perlu di-explore pembaca
Instalasi: pip install plotly kaleido
Dokumentasi: plotly.com/python
Interactive Web Maps Animation
Ta

Tableau Public

No-Code BI Tool (Gratis)

Versi gratis Tableau Desktop dengan satu pembatasan: semua visualisasi harus dipublikasikan ke public.tableau.com. Drag-and-drop interface yang intuitif membuat chart profesional tanpa satu baris kode. Sangat berguna untuk presentasi ke stakeholder non-teknis. Pelajari ini untuk portfolio: banyak perusahaan Indonesia menggunakan Tableau untuk laporan BI.

Terbaik untuk: Dashboard bisnis, laporan untuk eksekutif, visualisasi tanpa coding, portfolio publik
Akses: public.tableau.com (daftar gratis)
Latihan: Rebuild satu chart dari Minggu 1 di Tableau
No-Code Dashboard Portfolio Gratis
Lo

Looker Studio

Google BI Tool (Gratis)

Formerly Google Data Studio. Tool BI gratis dari Google yang terintegrasi sempurna dengan Google Sheets, BigQuery, Google Analytics, dan YouTube Analytics. Sangat populer di perusahaan Indonesia yang menggunakan ekosistem Google Workspace. Bisa embed laporan interaktif ke website atau dibagikan sebagai link. Cocok untuk laporan rutin yang datanya update otomatis dari Google Sheets.

Terbaik untuk: Laporan yang datanya dari Google Sheets atau BigQuery, laporan rutin yang auto-refresh
Akses: lookerstudio.google.com (login Google)
Latihan: Buat satu dashboard dari data Google Sheets
Google Ecosystem Auto-refresh Gratis Shareable
Dw

Datawrapper

Browser-based Chart Maker (Freemium)

Tool yang digunakan oleh journalist data di New York Times, Der Spiegel, dan banyak newsroom terkemuka. Antarmuka 4 langkah yang sangat sederhana: upload data, pilih chart, sesuaikan tampilan, publish. Menghasilkan chart SVG yang sangat bersih dan responsive. Gratis untuk penggunaan publik. Sangat bagus untuk belajar prinsip desain karena default Datawrapper sudah mengikuti best practice jurnalisme data.

Terbaik untuk: Chart singkat untuk artikel atau media sosial, belajar desain chart yang bersih, embed di website
Akses: datawrapper.de (daftar gratis)
Latihan: Buat choropleth Indonesia dari data BPS tanpa satu baris kode
Journalism No-Code SVG Responsive
Strategi Belajar Tools yang Efektif untuk Abbas

Jangan mencoba menguasai semua tool sekaligus. Prioritaskan dalam urutan ini: (1) Kuasai matplotlib dan seaborn hingga bisa membuat chart apapun dari memori. (2) Kuasai plotly untuk interaktivitas dan peta. (3) Eksplorasi Tableau Public dan Looker Studio untuk memahami cara kerja BI tool. (4) Coba Datawrapper untuk satu proyek dan perhatikan bagaimana default pilihan desainnya mengajarkan prinsip yang lebih baik dari yang Abbas sadari. Setiap tool membuka cara berpikir baru tentang data.

Tips Praktis dan Jebakan Pemula

Delapan pelajaran yang biasanya hanya ditemukan setelah berkali-kali membuat chart yang salah. Abbas bisa mempersingkat kurva belajar itu dengan membaca dan mempraktikkan ini sekarang.

Tip 1: Selalu Panggil plt.style.use() Sebelum Kode Lain

Urutan pemanggilan style sangat penting. Panggil plt.style.use('seaborn-v0_8-whitegrid') atau sns.set_theme(style='whitegrid', palette='muted') di bagian paling atas notebook, sebelum membuat Figure apapun. Kalau dipanggil di tengah, hanya chart setelahnya yang terpengaruh, dan ini menyebabkan inkonsistensi visual yang sulit dilacak. Buat satu sel inisialisasi khusus di setiap notebook yang berisi semua import dan konfigurasi style sekaligus.

Jebakan 1: Pie Chart untuk Lebih dari 5 Kategori

Pie chart hanya bekerja ketika kategori berjumlah 3-5 dan perbedaan ukurannya signifikan. Untuk 6 kategori ke atas, mata manusia tidak bisa membandingkan sudut lingkaran dengan akurat. Solusinya selalu bar chart horizontal yang diurutkan dari terbesar ke terkecil. Abbas akan sering melihat pie chart dengan 10+ slice dalam laporan pemerintah atau media, dan itu hampir selalu pilihan yang salah secara komunikatif.

Tip 2: Gunakan Warna sebagai Lapisan Informasi, Bukan Dekorasi

Setiap warna yang berbeda dalam chart menyampaikan pesan: "ini berbeda dari yang lain." Kalau Abbas mewarnai 12 bar dengan 12 warna berbeda hanya karena terlihat menarik, pembaca akan mencari pola yang tidak ada. Aturan praktis: gunakan satu warna untuk semua bar, lalu gunakan warna aksen yang berbeda hanya untuk bar yang ingin disorot. Teknik ini disebut "pre-attentive attribute" dan sangat efektif untuk mengarahkan perhatian pembaca ke insight utama.

Jebakan 2: Y-Axis Tidak Dimulai dari Nol

Untuk bar chart dan area chart, sumbu Y yang tidak dimulai dari nol secara visual melebih-lebihkan perbedaan. Perbedaan 2% bisa terlihat seperti 300% kalau Y-axis dimulai dari 97. Matplotlib defaultnya tidak memotong axis, tapi kalau Abbas pernah mengimpor data dari Excel atau memakai library lain, cek selalu dengan ax.get_ylim(). Pengecualian: line chart yang menunjukkan tren kecil pada nilai besar (misalnya harga saham) boleh tidak dimulai dari nol, tapi harus diberi label yang sangat jelas.

Tip 3: Palette Warna Ramah Buta Warna Sejak Awal

8% pria mengalami buta warna merah-hijau. Artinya dari 25 orang yang melihat laporan Abbas, kemungkinan 2 orang tidak bisa membedakan kategori kalau Abbas memakai palette default. Gunakan palette yang sudah teruji: sns.color_palette('colorblind') untuk categorical, 'viridis' atau 'plasma' untuk sequential, dan 'RdBu' untuk diverging. Cara cek chart Abbas: screenshot, lalu pakai situs coblis.com untuk simulasi berbagai jenis buta warna.

Tip 4: Figure Size dan DPI untuk Tujuan yang Berbeda

Ukuran Figure bukan hanya estetika, tapi menentukan apakah teks bisa dibaca. Untuk notebook eksplorasi: figsize=(10, 6) sudah cukup. Untuk presentasi layar lebar: figsize=(16, 9) atau (20, 8). Untuk laporan PDF atau print: gunakan dpi=300 saat menyimpan. Untuk embed di web: dpi=150 sudah cukup tajam. Aturan cepat: kalau teks di chart terasa terlalu kecil, naikkan figsize dulu sebelum menaikkan fontsize, karena menaikkan fontsize saja akan membuat teks "memakan" area data.

Jebakan 3: Dual Y-Axis yang Menyesatkan

Dual Y-axis (dua sumbu vertikal berbeda di kiri dan kanan) hampir selalu berbahaya karena skala yang berbeda memungkinkan manipulasi visual: hubungan antara dua garis bisa dibuat tampak berkorelasi atau tidak berkorelasi hanya dengan mengubah skala salah satu sumbu. Kalau Abbas perlu menampilkan dua metrik berbeda unit dalam satu chart, lebih baik buat dua subplot yang berdampingan dengan sumbu X yang disejajarkan. Ini lebih jujur dan lebih mudah dibaca.

Tip 5: Annotate Outlier, Jangan Hapus atau Sembunyikan

Ketika menemukan titik data yang jauh dari kelompok utama di scatter plot, jangan hapus atau sembunyikan. Outlier sering kali adalah insight terpenting dalam dataset. Yang perlu dilakukan: tambahkan anotasi dengan ax.annotate() untuk menjelaskan outlier tersebut. Contoh: titik data yang jauh bisa menunjukkan provinsi dengan kondisi khusus, bulan dengan event luar biasa, atau kesalahan input yang perlu dikonfirmasi ke sumber data. Setiap outlier adalah pertanyaan yang belum terjawab.

Tip 6: Simpan Chart dalam Format yang Tepat

Gunakan plt.savefig() dengan format yang sesuai tujuan: .png untuk presentasi dan web (raster, file lebih kecil), .svg untuk laporan yang perlu diperbesar tanpa blur (vector, bisa diedit di Inkscape/Illustrator), .pdf untuk dokumen akademik atau laporan formal. Selalu tambahkan bbox_inches='tight' agar label di pinggir tidak terpotong. Simpan sebelum memanggil plt.show(), karena setelah show() buffer figure dikosongkan dan savefig() akan menghasilkan file kosong.

Latihan Tambahan: Dataset Nyata Indonesia

Lima latihan menggunakan data publik Indonesia dari BPS, Kemendikbud, dan Kemenkes. Latihan ini lebih menantang dari yang ada di minggu 1-4 karena data asli tidak pernah serapi data tutorial.

Sumber Data yang Dipakai

Semua dataset bisa diunduh gratis dari: bps.go.id (statistik nasional), data.go.id (portal data terbuka pemerintah), dan databoks.katadata.co.id (data sudah dikurasi, format CSV lebih bersih). Untuk latihan ini, Abbas akan membuat data simulasi yang mencerminkan karakteristik data asli Indonesia, sehingga bisa langsung dikerjakan tanpa perlu mendaftar atau mengunduh file.

Latihan A

Dashboard Indeks Pembangunan Manusia (IPM) 34 Provinsi

IPM adalah indeks gabungan dari harapan hidup, pendidikan, dan pendapatan. Data ini punya karakteristik menarik: ada gap besar antara DKI Jakarta dan Papua, dan trennya bergerak lambat dari tahun ke tahun. Latihan ini melatih kemampuan membuat multi-chart dashboard sekaligus membaca pola regional.

1
Buat Figure dengan 2x2 subplot. Subplot kiri atas: horizontal bar chart 34 provinsi diurutkan berdasarkan IPM 2023. Subplot kanan atas: scatter plot IPM vs pengeluaran per kapita. Subplot kiri bawah: line chart tren IPM 2019-2023 untuk 5 provinsi teratas dan 5 terbawah. Subplot kanan bawah: map choropleth menggunakan plotly untuk warna provinsi berdasarkan nilai IPM.
2
Tambahkan anotasi untuk outlier: provinsi dengan IPM tertinggi (DKI Jakarta) dan terendah (Papua Pegunungan). Gunakan warna aksen merah untuk 5 provinsi terendah dan hijau untuk 5 tertinggi, sisanya abu-abu netral.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

sns.set_theme(style='whitegrid', palette='muted')

# Data IPM simulasi 10 provinsi (representatif)
data_ipm = {
    'provinsi': [
        'DKI Jakarta', 'DI Yogyakarta', 'Kalimantan Timur',
        'Bali', 'Riau', 'Sulawesi Utara', 'Jawa Tengah',
        'NTT', 'Maluku', 'Papua'
    ],
    'ipm_2023': [82.46, 80.22, 77.44, 77.21, 73.52,
               73.81, 72.69, 65.28, 69.47, 61.39],
    'ipm_2019': [80.76, 79.99, 75.83, 75.38, 72.71,
               72.20, 71.73, 63.97, 68.19, 60.06],
    'pengeluaran_juta': [19.2, 17.8, 15.6, 14.9, 13.8,
                         12.4, 11.9, 8.7, 9.2, 7.4]
}
df = pd.DataFrame(data_ipm).sort_values('ipm_2023', ascending=True)

# Tentukan warna: 2 terendah merah, 2 tertinggi hijau, sisanya abu-abu
colors = []
for i, val in enumerate(df['ipm_2023']):
    if i < 2:
        colors.append('#e74c3c')
    elif i >= len(df) - 2:
        colors.append('#27ae60')
    else:
        colors.append('#bdc3c7')

fig, axes = plt.subplots(1, 2, figsize=(16, 6))
fig.suptitle('Indeks Pembangunan Manusia (IPM) Indonesia 2023',
             fontsize=15, fontweight='bold', y=1.02)

# Panel kiri: horizontal bar
bars = axes[0].barh(df['provinsi'], df['ipm_2023'], color=colors, edgecolor='white')
axes[0].set_xlabel('Nilai IPM')
axes[0].set_title('Ranking IPM per Provinsi')
axes[0].set_xlim(55, 88)
for bar, val in zip(bars, df['ipm_2023']):
    axes[0].text(val + 0.3, bar.get_y() + bar.get_height()/2,
               f'{val:.1f}', va='center', fontsize=9)

# Panel kanan: scatter IPM vs pengeluaran
axes[1].scatter(df['pengeluaran_juta'], df['ipm_2023'],
               s=120, color='steelblue', alpha=0.8, zorder=5)
for _, row in df.iterrows():
    axes[1].annotate(row['provinsi'],
                     xy=(row['pengeluaran_juta'], row['ipm_2023']),
                     xytext=(4, 2), textcoords='offset points', fontsize=7.5)
# Garis tren
z = np.polyfit(df['pengeluaran_juta'], df['ipm_2023'], 1)
p = np.poly1d(z)
x_line = np.linspace(df['pengeluaran_juta'].min(), df['pengeluaran_juta'].max(), 100)
axes[1].plot(x_line, p(x_line), '--', color='coral', alpha=0.7, linewidth=1.5)
axes[1].set_xlabel('Pengeluaran Per Kapita (Juta Rp/tahun)')
axes[1].set_ylabel('Nilai IPM')
axes[1].set_title('Korelasi IPM dengan Pengeluaran Per Kapita')

plt.tight_layout()
plt.savefig('latihan_ipm.png', dpi=150, bbox_inches='tight')
plt.show()
Latihan B

Tren Pengguna Internet Indonesia 2015-2023 dengan Plotly Interaktif

Data penetrasi internet Indonesia punya narasi yang kuat: pertumbuhan masif di mobile, percepatan saat pandemi 2020, dan gap antara Jawa dan luar Jawa. Latihan ini melatih kemampuan menceritakan tren multi-dimensi dengan Plotly.

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd

tahun = [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023]
penetrasi_nasional = [22.0, 25.4, 32.3, 39.9, 47.7, 53.7, 62.1, 66.5, 78.2]
penetrasi_jawa     = [31.2, 36.1, 44.7, 53.2, 60.4, 67.9, 74.3, 79.1, 87.4]
penetrasi_luar     = [14.1, 16.8, 22.4, 28.7, 36.3, 41.2, 51.7, 56.3, 70.1]

fig = make_subplots(
    rows=1, cols=2,
    subplot_titles=('Penetrasi Internet (%) per Wilayah', 'Pertambahan Pengguna per Tahun (%)')
)

# Panel kiri: tren penetrasi
for label, data, color in [
    ('Nasional', penetrasi_nasional, '#2980b9'),
    ('Jawa',     penetrasi_jawa,     '#27ae60'),
    ('Luar Jawa', penetrasi_luar,    '#e67e22')
]:
    fig.add_trace(go.Scatter(
        x=tahun, y=data, name=label,
        line=dict(color=color, width=2.5),
        mode='lines+markers',
        hovertemplate='%{y:.1f}%<br>Tahun %{x}<extra>' + label + '</extra>'
    ), row=1, col=1)

# Anotasi: momen pandemi
fig.add_vline(x=2020, line_dash='dot', line_color='gray',
             annotation_text='Pandemi COVID-19', row=1, col=1)

# Panel kanan: pertumbuhan YoY
yoy = [0] + [round((penetrasi_nasional[i] - penetrasi_nasional[i-1]) /
               penetrasi_nasional[i-1] * 100, 1) for i in range(1, len(tahun))]
bar_colors = ['#e74c3c' if v < 10 else '#27ae60' for v in yoy]
fig.add_trace(go.Bar(
    x=tahun[1:], y=yoy[1:],
    marker_color=bar_colors[1:],
    name='Pertumbuhan YoY',
    showlegend=False,
    hovertemplate='+%{y:.1f}% dari tahun lalu<extra></extra>'
), row=1, col=2)

fig.update_layout(
    title_text='Penetrasi Internet Indonesia 2015-2023',
    title_font_size=16,
    height=450,
    hovermode='x unified',
    template='plotly_white'
)
fig.write_html('latihan_internet.html')
fig.show()
Yang Harus Diperhatikan Abbas di Hasil Chart Ini

Cari tahun dengan pertumbuhan YoY tertinggi. Apakah itu 2020 (pandemi) atau tahun lain? Kalau bukan 2020, pikirkan mengapa. Ini melatih kebiasaan "membaca chart, bukan hanya membuat chart." Data analyst yang baik selalu punya hipotesis sebelum melihat hasil visualisasi, lalu mencatat apakah hasil mendukung atau menolak hipotesis tersebut.

Latihan C

Heatmap Korelasi Indikator Kesehatan Antar Provinsi

Seaborn heatmap adalah salah satu alat paling efektif untuk melihat pola korelasi antar banyak variabel sekaligus. Latihan ini menggunakan data indikator kesehatan provinsi dan melatih kemampuan membaca pola dari matriks korelasi.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

np.random.seed(2024)
n = 34  # 34 provinsi

# Simulasi data kesehatan dengan korelasi yang realistis
harapan_hidup   = 65 + np.random.randn(n) * 4
angka_stunting  = 28 - harapan_hidup * 0.3 + np.random.randn(n) * 3
akses_air_bersih = 70 + harapan_hidup * 0.5 + np.random.randn(n) * 5
fasilitas_nakes  = 50 + harapan_hidup * 0.4 + np.random.randn(n) * 6
angka_kemiskinan = 25 - harapan_hidup * 0.4 + np.random.randn(n) * 4

df = pd.DataFrame({
    'Harapan Hidup'   : harapan_hidup,
    'Stunting (%)'    : angka_stunting,
    'Air Bersih (%)'  : akses_air_bersih,
    'Nakes per 1000'  : fasilitas_nakes,
    'Kemiskinan (%)'  : angka_kemiskinan
})

corr = df.corr()

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Heatmap dengan mask: tampilkan hanya segitiga bawah
mask = np.triu(np.ones_like(corr, dtype=bool), k=1)
sns.heatmap(
    corr, ax=axes[0], mask=mask,
    annot=True, fmt='.2f', cmap='RdBu_r',
    vmin=-1, vmax=1, center=0,
    square=True, linewidths=0.5,
    cbar_kws={'shrink': 0.8}
)
axes[0].set_title('Korelasi Antar Indikator Kesehatan')

# Scatter: hubungan paling kuat dari heatmap
axes[1].scatter(df['Kemiskinan (%)'], df['Stunting (%)'],
               alpha=0.7, s=80, color='steelblue')
z = np.polyfit(df['Kemiskinan (%)'], df['Stunting (%)'], 1)
p = np.poly1d(z)
x_fit = np.linspace(df['Kemiskinan (%)'].min(),
                    df['Kemiskinan (%)'].max(), 100)
axes[1].plot(x_fit, p(x_fit), 'r--', alpha=0.8)
axes[1].set_xlabel('Tingkat Kemiskinan (%)')
axes[1].set_ylabel('Angka Stunting (%)')
axes[1].set_title('Kemiskinan vs Stunting: Pasangan Korelasi Terkuat')

plt.tight_layout()
plt.savefig('latihan_kesehatan.png', dpi=150, bbox_inches='tight')
plt.show()
Korelasi Bukan Kausalitas: Penting untuk Data Indonesia

Heatmap menunjukkan bahwa kemiskinan berkorelasi dengan stunting. Ini tidak berarti kemiskinan secara langsung menyebabkan stunting. Keduanya mungkin sama-sama disebabkan faktor ketiga seperti akses layanan kesehatan atau tingkat pendidikan ibu. Abbas harus selalu menambahkan catatan "r = [nilai]" dan menulis frasa "berkorelasi dengan", bukan "menyebabkan", saat mendeskripsikan temuan dari heatmap korelasi.

Latihan D

Animasi Perubahan Ekspor Komoditas Indonesia 2010-2023

Plotly Express memiliki parameter animation_frame yang memungkinkan Abbas membuat chart animasi dengan satu baris tambahan. Latihan ini melatih kemampuan memvisualisasikan perubahan komposisi data dari waktu ke waktu.

import plotly.express as px
import pandas as pd
import numpy as np

np.random.seed(42)
tahun_list  = list(range(2010, 2024))
komoditas   = ['Batu Bara', 'Minyak Sawit', 'Nikel',
               'Karet', 'Kopi', 'Tekstil']

# Tren berbeda tiap komoditas: nikel naik, batu bara turun, sawit stabil
tren_base = {
    'Batu Bara'   : [28, 30, 27, 24, 22, 20, 19, 21, 22, 24, 26, 30, 28, 23],
    'Minyak Sawit': [22, 23, 24, 23, 24, 24, 25, 26, 27, 26, 28, 30, 27, 26],
    'Nikel'       : [4,  5,  6,  7,  8,  9,  10, 12, 13, 15, 17, 20, 22, 25],
    'Karet'       : [12, 11, 10, 9,  9,  8,  8,  7,  7,  7,  6,  6,  6,  6],
    'Kopi'        : [5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  7,  7,  7,  7],
    'Tekstil'     : [10, 10, 10, 9,  9,  9,  8,  8,  8,  7,  7,  7,  6,  6]
}

rows = []
for i, tahun in enumerate(tahun_list):
    for kom in komoditas:
        rows.append({
            'tahun'    : tahun,
            'komoditas': kom,
            'nilai_miliar_usd': tren_base[kom][i] + np.random.randn() * 1.5
        })
df = pd.DataFrame(rows)

fig = px.bar(
    df, x='komoditas', y='nilai_miliar_usd',
    color='komoditas',
    animation_frame='tahun',
    range_y=[0, 35],
    color_discrete_sequence=px.colors.qualitative.Set2,
    title='Nilai Ekspor Komoditas Utama Indonesia (Miliar USD)',
    labels={'nilai_miliar_usd': 'Nilai (Miliar USD)', 'komoditas': 'Komoditas'}
)
fig.update_layout(
    template='plotly_white',
    showlegend=False,
    height=480
)
fig.write_html('latihan_ekspor.html')
fig.show()
Tantangan Lanjutan untuk Latihan D

Setelah membuat animasi bar, buat juga versi line chart yang menampilkan semua tahun sekaligus tanpa animasi, dengan tiap komoditas sebagai satu garis berbeda warna. Bandingkan: kapan animasi lebih efektif dari static chart, dan kapan sebaliknya? Animasi bagus untuk presentasi lisan, static chart lebih baik untuk laporan tertulis karena pembaca bisa membandingkan semua titik sekaligus tanpa harus mengingat frame sebelumnya.

Latihan E

Proyek Mini: Satu Halaman Dashboard Pendidikan Indonesia

Latihan terakhir ini mengintegrasikan semua yang sudah dipelajari: matplotlib untuk chart statis, seaborn untuk distribusi statistik, dan plotly untuk satu chart interaktif. Hasilnya adalah satu halaman HTML yang bisa dibagikan.

1
Pilih satu topik pendidikan dari pilihan berikut: (a) Angka partisipasi sekolah SMP vs SMA per provinsi, (b) Rasio guru per murid di sekolah negeri vs swasta, (c) Nilai rata-rata PISA Indonesia dibanding negara ASEAN 2006-2022. Pilih yang paling Abbas minati karena rasa ingin tahu menghasilkan pertanyaan yang lebih baik.
2
Buat minimal 3 chart yang saling terhubung dalam satu narasi. Chart 1: kondisi keseluruhan (overview). Chart 2: breakdown yang mengungkap ketimpangan atau variasi. Chart 3: tren dari waktu ke waktu. Setiap chart harus memiliki judul berpesan, bukan judul deskriptif.
3
Export ke HTML menggunakan Plotly untuk chart interaktif dan PNG untuk chart statis. Gabungkan dalam satu file HTML sederhana dengan <img> tag untuk PNG dan <iframe> untuk HTML Plotly. Tambahkan satu paragraf teks yang menjelaskan "pesan utama" dari keseluruhan dashboard dalam 3-4 kalimat.
4
Self-review menggunakan checklist ini sebelum selesai: Apakah setiap sumbu punya label dan satuan yang jelas? Apakah judul setiap chart berpesan (bukan hanya deskriptif)? Apakah palette warna konsisten di semua chart? Apakah chart bisa dibaca oleh seseorang yang buta warna merah-hijau? Apakah ada outlier yang belum dianotasi?
Standar Kelulusan Latihan E

Dashboard Abbas dianggap selesai kalau seseorang yang belum pernah melihat data tersebut bisa membaca keseluruhan dashboard dalam 2 menit dan langsung memahami: (1) apa yang sedang diukur, (2) apa temuan utamanya, dan (3) apa yang menarik atau mengejutkan dari data tersebut. Kalau orang tersebut masih perlu bertanya, artinya ada chart atau label yang perlu diperbaiki.