Angka-angka ringkasan bisa menipu: dua dataset dengan mean dan simpangan baku yang sama dapat memiliki bentuk sebaran yang sama sekali berbeda, dan korelasi 0,9 tetap tidak memperlihatkan pencilan yang bersembunyi di pojok data. Grafik menyingkap apa yang disembunyikan angka — sebaran miring, kelompok campuran, tren, lubang nilai — dan karena itu visualisasi adalah langkah pertama exploratory data analysis (EDA) sebelum model apa pun dilatih. Matplotlib adalah pustaka gambar dasar seluruh ekosistem Python: seaborn dibangun di atasnya, pandas memanggilnya lewat .plot(). Chapter ini membahas anatomi gambar, tiga jenis plot inti, dan cara menyimpan gambar dengan benar di lingkungan tanpa tampilan.

Figure dan Axes: Anatomi Sebuah Plot #

Dua istilah membangun seluruh struktur matplotlib. Figure adalah kanvas keseluruhan — satu file gambar yang bisa memuat beberapa sub-gambar. Axes adalah satu bidang gambar dengan sumbu-x dan sumbu-y sendiri; scatter, garis, label, dan judul ditempelkan pada Axes, bukan pada Figure. Pola bakunya:

python
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(x, y)
ax.set_xlabel("Sumbu x")
fig.savefig("gambar.png", dpi=100)

Gaya fig, ax ini disebut antarmuka berorientasi objek dan menjadi standar kode produksi, karena setip Axes bisa dikendalikan eksplisit saat gambar memuat banyak panel. Gaya cepat plt.scatter(...) memang lebih pendek, tetapi membingungkan begitu gambar memuat lebih dari satu Axes.

Scatter Plot untuk Hubungan antar Variabel #

Scatter menjawab pertanyaan paling mendasar EDA: bagaimana dua variabel bergerak bersama? Setiap baris data menjadi satu titik; posisi titik-titik memperlihatkan arah hubungan, kekuatannya, sekaligus pencilan yang menjauh dari kerumunan. File plot-dasar.py menggambar 40 siswa sintetis (jam belajar vs nilai ujian) plus garis tren dari np.polyfit — regresi linear paling sederhana yang akan kita dalami di Section Dasar Machine Learning — lalu mencetak ringkasan numeriknya agar grafik dan angka saling menjelaskan.

python
# Scatter plot + garis tren: hubungan dua variabel dalam satu gambar.

import os

import matplotlib

matplotlib.use("Agg")  # backend tanpa tampilan: aman di server/CI
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)

# Data sintetis 40 siswa: jam belajar vs nilai ujian
jam = rng.uniform(1.0, 10.0, size=40)
nilai = 35.0 + 6.0 * jam + rng.normal(0.0, 6.0, size=40)
nilai = np.clip(nilai, 0, 100)

fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(jam, nilai, alpha=0.7, label="data siswa")

# Garis tren dari regresi linear derajat 1 (np.polyfit)
kemiringan, intersep = np.polyfit(jam, nilai, 1)
x_garis = np.linspace(jam.min(), jam.max(), 100)
ax.plot(x_garis, kemiringan * x_garis + intersep, color="tab:red",
        label=f"tren: y = {kemiringan:.2f}x + {intersep:.2f}")

ax.set_xlabel("Jam belajar per minggu")
ax.set_ylabel("Nilai ujian")
ax.set_title("Hubungan jam belajar dan nilai ujian")
ax.legend()

fig.savefig("contoh-scatter.png", dpi=100)
plt.close(fig)

print("Grafik disimpan ke contoh-scatter.png, lalu file dihapus.")
print(f"Kemiringan tren   : {kemiringan:.3f} poin per jam belajar")
print(f"Intersep tren     : {intersep:.3f}")
print(f"Korelasi Pearson r: {np.corrcoef(jam, nilai)[0, 1]:.3f}")
print(f"Rentang jam       : {jam.min():.2f} - {jam.max():.2f}")
print(f"Rentang nilai     : {nilai.min():.2f} - {nilai.max():.2f}")
print("Pola: nilai naik seiring jam belajar; titik menyebar di sekitar garis tren.")

os.remove("contoh-scatter.png")
print("File contoh-scatter.png dihapus (contoh tetap bersih).")

Output yang Dihasilkan:

text
Grafik disimpan ke contoh-scatter.png, lalu file dihapus.
Kemiringan tren   : 5.608 poin per jam belajar
Intersep tren     : 37.352
Korelasi Pearson r: 0.960
Rentang jam       : 1.39 - 9.78
Rentang nilai     : 40.59 - 95.00
Pola: nilai naik seiring jam belajar; titik menyebar di sekitar garis tren.
File contoh-scatter.png dihapus (contoh tetap bersih).

Mari kita telaah baris-baris kode yang berperan penting:

  1. Baris 7–8 (matplotlib.use("Agg") sebelum pyplot): backend Agg merender gambar ke berkas tanpa membuka jendela — wajib di server, CI, dan lingkungan tanpa tampilan; pemanggilan harus dilakukan sebelum pyplot diimpor.
  2. Baris 14–16 (data sintetis): nilai dibangun dari formula 35 + 6 × jam ditambah derau normal berseed, lalu dibatasi rentang 0–100 dengan np.clip.
  3. Baris 18–19 (subplots dan scatter): satu Figure berukuran 6 × 4 inci memuat satu Axes; 40 titik digambar dengan alpha=0.7 agar titik yang bertumpukan tetap terlihat.
  4. Baris 22–25 (garis tren): np.polyfit(jam, nilai, 1) memperkirakan kemiringan 5,608 dan intersep 37,352; garis digambar pada 100 titik linspace agar mulus, dengan label yang menyertakan persamaannya.
  5. Baris 27–30 (anotasi): set_xlabel, set_ylabel, set_title, dan legend melengkapi gambar — tanpa ketiganya pembaca tidak tahu apa yang dilihatnya.
  6. Baris 32–33 serta 43–44 (simpan dan bersih-bersih): savefig menulis PNG dengan dpi 100, plt.close(fig) melepas memorinya, dan os.remove menghapus berkas agar contoh tidak meninggalkan artefak. Ringkasan numerik menegaskan pesan grafiknya: korelasi 0,960 dengan nilai naik dari 40,59 ke 95,00 seiring jam belajar bertambah.

Histogram untuk Sebaran Satu Variabel #

Histogram membagi rentang nilai menjadi sejumlah wadah (bins) lalu menghitung berapa data yang jatuh ke tiap wadah — bentuk sebaran satu variabel jadi terlihat: lonceng, miring ke kanan, atau dua puncak yang menandakan data campuran. Justru pola dua puncak inilah yang sering tersembunyi dari mean: menggabungkan gaji lulus baru dan senior menghasilkan satu mean yang tidak menggambarkan kelompok mana pun. File histogram-distribusi.py menggambar dua histogram bertumpang tindih dan mencetak statistik keduanya.

python
# Histogram dua kelompok: membandingkan sebaran gaji.

import os

import matplotlib

matplotlib.use("Agg")  # backend tanpa tampilan: aman di server/CI
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)

# Dua kelompok gaji bulanan (juta rupiah) yang dibangkitkan normal
gaji_lulus_baru = rng.normal(loc=6.0, scale=1.0, size=500)
gaji_senior = rng.normal(loc=14.0, scale=2.5, size=500)

fig, ax = plt.subplots(figsize=(6, 4))
ax.hist(gaji_lulus_baru, bins=20, alpha=0.6, label="lulus baru")
ax.hist(gaji_senior, bins=20, alpha=0.6, label="senior")
ax.set_xlabel("Gaji bulanan (juta rupiah)")
ax.set_ylabel("Frekuensi")
ax.set_title("Sebaran gaji dua kelompok")
ax.legend()

fig.savefig("contoh-histogram.png", dpi=100)
plt.close(fig)

print("Histogram disimpan ke contoh-histogram.png, lalu file dihapus.")
print("Statistik gaji lulus baru:")
print(f"  mean={gaji_lulus_baru.mean():.2f}  std={gaji_lulus_baru.std():.2f}  "
      f"min={gaji_lulus_baru.min():.2f}  max={gaji_lulus_baru.max():.2f}")
print("Statistik gaji senior:")
print(f"  mean={gaji_senior.mean():.2f}  std={gaji_senior.std():.2f}  "
      f"min={gaji_senior.min():.2f}  max={gaji_senior.max():.2f}")
print("Pola: dua lonceng terpisah; kelompok senior lebih tinggi dan lebih lebar sebarannya.")

os.remove("contoh-histogram.png")
print("File contoh-histogram.png dihapus (contoh tetap bersih).")

Output yang Dihasilkan:

text
Histogram disimpan ke contoh-histogram.png, lalu file dihapus.
Statistik gaji lulus baru:
  mean=5.99  std=0.96  min=3.43  max=8.91
Statistik gaji senior:
  mean=13.89  std=2.54  min=4.88  max=21.95
Pola: dua lonceng terpisah; kelompok senior lebih tinggi dan lebih lebar sebarannya.
File contoh-histogram.png dihapus (contoh tetap bersih).

Bedah kode di atas baris demi baris:

  1. Baris 14–15 (dua populasi): kelompok lulus baru N(6, 1) dan senior N(14, 2,5) masing-masing 500 sampel dari generator berseed yang sama.
  2. Baris 18–19 (ax.hist dua kali): dua histogram digambar pada Axes yang sama dengan alpha=0.6 agar wilayah bertumpang tindih tetap terbaca; bins=20 membagi rentang menjadi 20 wadah.
  3. Baris 20–23 (anotasi): sumbu-x bernama gaji, sumbu-y frekuensi, dan legend membedakan warna kedua kelompok.
  4. Baris 25–26 serta 37–38 (simpan dan hapus): pola yang sama seperti scatter — savefig, close, lalu os.remove di akhir berkas.
  5. Baris 29–35 (statistik pendamping): mean 5,99 dan 13,89 dengan simpangan baku 0,96 dan 2,54 — grafik memperlihatkan dua lonceng yang terpisah tegas, angka memastikan jarak dan lebar masing-masing.

Label, Judul, dan Legend #

Grafik tanpa anotasi adalah teka-teki: sumbu tanpa satuan tidak bisa ditafsirkan, dan dua garis tanpa legend tidak bisa dibedakan. Kebiasaan minimum yang layak dibentuk sejak sekarang: set_xlabel dan set_ylabel selalu menyertakan satuan (misalnya “Gaji bulanan (juta rupiah)”), set_title menyimpulkan temuan, dan legend() muncul setiap kali gambar memuat lebih dari satu seri. Ketiganya adalah metode pada Axes, konsisten dengan gaya berorientasi objek yang kita pakai sejak awal.

Menyimpan Gambar: savefig, Bukan plt.show #

Perbedaan paling praktis dengan tutorial lama: plt.show() membuka jendela interaktif dan memblokir skrip sampai jendela ditutup — wajar di laptop pribadi, tetapi bencana di server, notebook tanpa tampilan, atau pipeline CI yang tampak menggantung tanpa pesan galat. Di lingkungan tersebut backend Agg bekerja tanpa jendela, dan hasil karya disimpan dengan fig.savefig("nama.png", dpi=100); format ditentukan ekstensi berkas (png, pdf, svg). Tutup selalu Figure dengan plt.close(fig) setelah menyimpannya, terutama saat menggambar ratusan gambar dalam loop, karena setiap Figure yang terlupa tetap memakan memori.

Jenis plotPertanyaan yang dijawabContoh pemakaian di ML
ScatterBagaimana dua variabel bergerak bersama?Fitur vs target, residual vs prediksi
HistogramBagaimana sebaran satu variabel?Kemiringan fitur, keseimbangan kelas
LineBagaimana nilai berubah berurutan?Kurva pembelajaran, loss per epoch
BarBagaimana perbandingan antar kategori?Jumlah sampel per kelas, kepentingan fitur

Dengan tiga fondasi matematika dan tiga pustaka inti di tangan, kita siap memasuki sisi praktis proyek machine learning. Langkah pertamanya menyiapkan lingkungan kerja yang benar — mulai dari Chapter Menginstal Python untuk Machine Learning di Section Persiapan Lingkungan.

Referensi Resmi #