BAGIAN B | PYQGIS
BAB 14: Mengetuk Pintu QGIS: Memuat, Membaca, dan Menyimpan dengan Skrip
Studi kasus: "Peta saya bisa dibuka lagi besok?" #
Kepala Seksi membuka rapat sepuluh menit lagi. Ia bertanya dua hal. Pertama, berapa luas tiap KPH dalam hektare? Kedua, bisakah peta yang Anda susun hari ini dibuka lagi besok pagi, utuh seperti semula? Dengan klik, Anda bisa menjawabnya. Dengan skrip, jawabannya keluar dalam sekali jalan, dan skrip yang sama bisa dipakai untuk KPH lain. Bab ini membuka pintunya: cara memerintah QGIS dari Python.
Konsep: PyQGIS dalam tiga kalimat #
Bayangkan QGIS sebagai dapur restoran besar yang lengkap. Python adalah daftar pesanan tertulis yang Anda serahkan ke dapur itu. PyQGIS adalah buku menu yang menjelaskan pesanan apa saja yang boleh Anda tulis.
Buku menu itu punya nama resmi: API, yaitu daftar perintah yang disediakan sebuah program untuk dipanggil dari program lain. Hampir semua yang bisa Anda klik di QGIS punya perintah padanan di API-nya. Karena itu, Bab 13 menyarankan kebiasaan membuka dokumentasi API setiap kali Anda bertanya "perintah untuk ini apa?".
Ada tiga istilah lagi yang akan sering muncul. Kelas adalah cetakan, misalnya cetakan "layer vektor". Objek adalah barang jadi yang dicetak dari kelas itu, misalnya layer Batas_KPH yang sudah Anda buka. Metode adalah tombol pada objek itu, ditulis dengan titik dan kurung, misalnya batas.featureCount(). Konsep kelas dan objek dibahas lengkap di Bab 11.

Lima istilah baru Anda sejauh ini:
- PyQGIS: cara Python berbicara dengan QGIS.
- API: daftar perintah resmi sebuah program, seperti buku menu.
- Kelas: cetakan, ditulis dengan awalan
Qgs, misalnyaQgsVectorLayer. - Objek: hasil cetakan dari sebuah kelas, misalnya
batas. - Metode: tombol pada objek, ditulis
objek.nama().
Konsep: proyek, layer, dan fitur #
Sekarang bayangkan sebuah lemari besar bernama proyek. Di dalamnya ada rak-rak yang disebut layer. Satu layer vektor berisi baris-baris yang disebut fitur, sedangkan satu layer raster berisi petak-petak piksel. Skrip PyQGIS membuka lemari itu, mengambil rak yang Anda minta, lalu membaca isinya.

Tiga istilah baru di bagian ini:
- Proyek: wadah semua layer, dilihat dari Python lewat
QgsProject. - Layer: satu data di dalam proyek, vektor (
QgsVectorLayer) atau raster (QgsRasterLayer). - Fitur: satu baris di layer vektor, misalnya satu KPH.
Dua cara menjalankan: di dalam QGIS dan mandiri #
Skrip PyQGIS bisa dijalankan dengan dua cara. Cara pertama: di dalam QGIS. Dapur sudah menyala dan proyek Anda sudah terbuka. Cara kedua: mandiri, tanpa membuka QGIS. Di cara ini skrip harus menyalakan dapurnya sendiri.

Untuk cara pertama, ikuti langkah di Bab 3. Ringkasnya, menurut Buku I4 Bab 1: pilih Plugins ► Python Console, klik Show Editor, tempel skrip, lalu jalankan dengan Ctrl+Shift+E.
Untuk cara kedua, kerangkanya selalu sama. Anda menyalakan mesin QGIS di awal, menjalankan pekerjaan, lalu mematikannya di akhir. Kerangka ini sudah diuji dengan python-qgis pada QGIS 4.0.2.
from qgis.core import QgsApplication
QgsApplication.setPrefixPath(r"C:/Program Files/QGIS 4.0.2/apps/qgis", True)
app = QgsApplication([], False)
app.initQgis()
# ... tempel isi skrip Anda di sini ...
app.exitQgis()| Baris | Artinya |
|---|---|
QgsApplication.setPrefixPath(...) | Beri tahu Python di mana QGIS terpasang. Jalur ini milik komputer penulis. Di komputer Anda mungkin berbeda, dan di macOS atau Ubuntu pasti berbeda [CEK]. |
QgsApplication([], False) | Buat mesin QGIS. Isian kedua False berarti aplikasi tanpa layar, hanya konsol. Menurut dokumentasi API, True dipakai untuk aplikasi dengan antarmuka. |
app.initQgis() | Nyalakan mesin: muat pembaca data yang dibutuhkan. |
app.exitQgis() | Matikan mesin dan bersihkan memori. |
Kerangka ini hanya untuk cara kedua. Di Konsol Python QGIS, mesinnya sudah menyala, jadi jangan menempelkannya di sana. Pada uji di bab ini, beberapa skrip kecil tetap jalan tanpa kerangka itu. Tetapi Skrip 14.4 macet pada baris pembukaan proyek. Jadi untuk skrip mandiri, selalu pakai kerangka lengkap.
Skrip 14.1: Lima hal Python sebelum masuk QGIS #
Skrip pertama tidak memakai QGIS sama sekali. Ia hanya memanaskan Anda dengan lima hal Python dasar. Karena isinya dibedah di Bab 4 sampai 7, penjelasan di sini sengaja ringkas. Berkas b1_00_python_dasar.py berisi 33 baris, dan di dalamnya tertulis "Skrip 1.0".
Tujuan. Mengingat lima hal Python yang dipakai di seluruh bab setelah ini: variabel, daftar, kamus, perulangan dengan percabangan, dan fungsi.
Bahan. Tidak ada data. Skrip bisa dijalankan di Konsol Python QGIS, atau dengan Python biasa di terminal.
Skrip utuh:
# [SKRIP 1.0: Lima hal Python yang cukup untuk memulai]
# Penulis: Badar Mubarok Yogaswara
# Tidak memakai QGIS sama sekali. Boleh dicoba di Python Console baris demi baris.
# 1. Variabel: kotak bernama yang menyimpan nilai
nama = "KPH Alpha"
luas_ha = 4.0
print(nama, "luasnya", luas_ha, "ha")
# 2. Daftar: kumpulan nilai berurutan. Nomor urut dimulai dari 0, bukan 1.
petak = ["KPH Alpha", "KPH Beta", "KPH Gamma"]
print("Petak pertama:", petak[0])
print("Jumlah petak:", len(petak))
# 3. Kamus: pasangan kunci dan nilai, seperti daftar isi dengan nomor halaman
luas = {"KPH Alpha": 4.0, "KPH Beta": 4.0, "KPH Gamma": 8.0}
print("Luas KPH Gamma:", luas["KPH Gamma"])
# 4. Perulangan for dan percabangan if. Baris yang menjorok ke dalam ikut dalam blok.
total = 0
for nama, ha in luas.items():
total = total + ha
if ha > 5:
print(nama, "termasuk petak besar")
print("Total:", total, "ha")
# 5. Fungsi: resep yang diberi nama supaya bisa dipakai berulang kali
def ke_hektar(meter_persegi):
return meter_persegi / 10000
print("40000 m2 =", ke_hektar(40000), "ha")Penjelasan baris demi baris. Nomor baris mengikuti berkas di atas. Baris komentar (yang diawali #) dilewati Python, jadi tidak ditulis ulang di sini.
| Baris | Tulisan | Artinya |
|---|---|---|
| 6-8 | nama = "KPH Alpha" dan seterusnya | Isi kotak nama dengan teks dan kotak luas_ha dengan angka, lalu print menampilkan keduanya. Dibahas di Bab 4. |
| 11-13 | petak = [...] | Daftar berisi tiga teks. petak[0] mengambil isi pertama, karena nomor urut mulai dari 0. len(petak) menghitung isinya. Dibahas di Bab 5. |
| 16-17 | luas = {...} | Kamus: pasangan kunci dan nilai. luas["KPH Gamma"] mengambil nilai milik kunci itu. Dibahas di Bab 5. |
| 20-25 | for nama, ha in luas.items(): | Ulangi untuk tiap pasangan di kamus. Baris yang menjorok ke dalam ikut diulang. if ha > 5 hanya mencetak KPH yang luasnya lebih dari 5. Dibahas di Bab 6. |
| 29-30 | def ke_hektar(meter_persegi): | Resep bernama. Beri angka meter persegi, ia mengembalikan (return) hasil bagi 10000. Dibahas di Bab 7. |
| 33 | print("40000 m2 =", ke_hektar(40000), "ha") | Panggil resep itu dengan angka 40000. |
Hasil. Layar menampilkan (berdasarkan uji pada QGIS 4.0.2):
KPH Alpha luasnya 4.0 ha
Petak pertama: KPH Alpha
Jumlah petak: 3
Luas KPH Gamma: 8.0
KPH Gamma termasuk petak besar
Total: 16.0 ha
40000 m2 = 4.0 haHasil ini sama dengan hasil uji di Buku I4.
Bagian yang boleh diubah.
- Baris 16, isi kamus. Tambah pasangan baru, misalnya
"KPH Delta": 6.0. - Baris 23, angka 5. Ini batas "besar". Ganti menjadi
7, dan hanya KPH Gamma yang lolos. - Baris 33, angka 40000. Beri angka lain ke resep
ke_hektar.
Jebakan.
- Nama kotak terpakai ulang. Pada baris 6,
namaberisi"KPH Alpha". Pada baris 21, perulangan memakai namanamalagi. Setelah perulangan selesai, isinamamenjadiKPH Gamma. Hasil uji: perintahprint(nama)sesudah perulangan menampilkanKPH Gamma. Pelajarannya: nama kotak yang sama, isi yang tertimpa. - Huruf besar dan kecil.
print(Nama)menghasilkanNameError: name 'Nama' is not defined. Did you mean: 'nama'? - Lupa menjorok. Bila baris di bawah
fortidak dijorokkan, munculIndentationError: expected an indented block after 'for' statement on line 1. - Nama "petak". Isi daftar
petaksebenarnya nama KPH, bukan petak. Itu hanya soal nama. Python tidak peduli.
Latihan variasi. Tambahkan KPH Delta seluas 6.0 hektare ke kamus, lalu jalankan lagi.
Contoh jawaban (sudah diuji), hanya bagian yang berubah:
luas = {"KPH Alpha": 4.0, "KPH Beta": 4.0, "KPH Gamma": 8.0, "KPH Delta": 6.0}Layar menampilkan KPH Gamma termasuk petak besar, lalu KPH Delta termasuk petak besar, lalu Total: 22.0 ha.
Skrip 14.2: Memuat layer dan mengambilnya dengan nama #
Sekarang Anda masuk ke QGIS. Bayangkan rak buku. Anda meletakkan buku di rak (memuat layer), lalu mengambilnya lagi dengan menyebut judulnya (mengambil layer dengan nama). Rak itu adalah proyek.
Tujuan. Memuat satu layer vektor dan satu raster, memeriksa apakah keduanya terbuka, memasukkannya ke proyek, lalu membaca sifat keduanya.
Bahan. Paket data paket-i4, berkas Batas_KPH.gpkg (tiga KPH) dan DSM_Drone.tif (raster tinggi permukaan). Berkas b1_01_muat_layer.py dijalankan dari Editor Skrip QGIS atau dengan kerangka mandiri di atas. Ganti dulu jalur DATA di baris 6 dengan lokasi paket-i4 di komputer Anda.
Skrip ini bekerja dalam enam tahap. Gambar berikut menunjukkan urutannya, lengkap dengan nomor baris.

Skrip utuh:
# [SKRIP 1.1: Memuat layer lewat Python dan mengambilnya kembali dengan nama]
# Penulis: Badar Mubarok Yogaswara
# Jalankan di Plugins > Python Console. Ganti DATA dengan folder paket-i4 di komputer Anda.
from qgis.core import QgsProject, QgsVectorLayer, QgsRasterLayer, QgsWkbTypes
DATA = "D:/Latihan/paket-i4"
HASIL = "D:/Latihan/hasil_i4"
proyek = QgsProject.instance() # proyek yang sedang terbuka
proyek.removeAllMapLayers() # kosongkan dulu agar tidak dobel
# 1. Muat satu layer vektor dan satu raster. Argumen: jalur, nama di panel Layers, penyedia data.
batas = QgsVectorLayer(DATA + "/Batas_KPH.gpkg", "Batas_KPH", "ogr")
dsm = QgsRasterLayer(DATA + "/DSM_Drone.tif", "DSM_Drone", "gdal")
# 2. Periksa dulu: layer yang gagal dibuka tidak memicu galat, hanya isValid() bernilai False.
print("Batas_KPH sah?", batas.isValid())
print("DSM_Drone sah?", dsm.isValid())
# 3. Masukkan ke proyek supaya tampil di panel Layers.
proyek.addMapLayer(batas)
proyek.addMapLayer(dsm)
# 4. Ambil layer dengan namanya. mapLayersByName() mengembalikan DAFTAR, ambil isi pertama.
layer = proyek.mapLayersByName("Batas_KPH")[0]
print("Nama:", layer.name())
print("CRS:", layer.crs().authid())
print("Jenis geometri:", QgsWkbTypes.displayString(layer.wkbType()))
print("Jumlah fitur:", layer.featureCount())
print("Nama field:", [f.name() for f in layer.fields()])
# 5. Sifat sebuah raster
r = proyek.mapLayersByName("DSM_Drone")[0]
print("Raster:", r.width(), "x", r.height(), "piksel,", r.bandCount(), "band")
print("Ukuran piksel (m):", r.rasterUnitsPerPixelX())
print("Jumlah layer di proyek:", len(proyek.mapLayers()))Penjelasan baris demi baris. Skrip ini padat, jadi dipecah menjadi tiga blok. Nomor baris mengikuti berkas di atas.
Blok A: menyiapkan dan membuka (baris 4-14).
| Baris | Tulisan | Artinya |
|---|---|---|
| 4 | from qgis.core import ... | Panggil empat perkakas dari QGIS: QgsProject, QgsVectorLayer, QgsRasterLayer, dan QgsWkbTypes. Cara kerja import dibahas di Bab 8. |
| 6-7 | DATA = ... dan HASIL = ... | Dua kotak berisi jalur folder. Hanya DATA yang dipakai di skrip ini. HASIL sisa dari kerangka yang sama dengan skrip lain. |
| 9 | proyek = QgsProject.instance() | Ambil proyek yang sedang terbuka dan simpan di kotak proyek. Hanya ada satu proyek aktif, jadi instance() selalu mengembalikan objek yang sama. |
| 10 | proyek.removeAllMapLayers() | Keluarkan semua layer dari proyek, supaya tidak dobel. |
| 13 | batas = QgsVectorLayer(...) | Buka layer vektor. Tiga isian: sumber data (folder disambung + dengan nama berkas), nama layer di panel Layers, dan pembaca data "ogr" untuk vektor. |
| 14 | dsm = QgsRasterLayer(...) | Sama, untuk raster. Pembaca datanya "gdal". |
Blok B: memeriksa dan memasukkan (baris 16-22).
| Baris | Tulisan | Artinya |
|---|---|---|
| 17-18 | print("Batas_KPH sah?", batas.isValid()) | Tanya: apakah layer ini terbuka dengan benar? Jawabannya True atau False. |
| 21-22 | proyek.addMapLayer(batas) | Masukkan layer ke proyek supaya tampil di panel Layers. Sebelum baris ini, layer hanya ada di memori skrip. |
Blok C: mengambil dan membaca sifat (baris 24-36).
| Baris | Tulisan | Artinya |
|---|---|---|
| 25 | proyek.mapLayersByName("Batas_KPH")[0] | Cari layer bernama Batas_KPH. Hasilnya daftar, karena bisa ada beberapa layer bernama sama. [0] mengambil yang pertama. |
| 26 | layer.name() | Metode yang mengembalikan nama layer. |
| 27 | layer.crs().authid() | crs() memberi sistem koordinat layer. authid() memberi kodenya, misalnya EPSG:32749 (UTM zona 49S). |
| 28 | QgsWkbTypes.displayString(layer.wkbType()) | Jenis bentuk layer dalam kata, misalnya Polygon. |
| 29 | layer.featureCount() | Jumlah fitur. |
| 30 | [f.name() for f in layer.fields()] | Daftar nama kolom. Cara menulis ini disebut list comprehension, dibahas di Bab 6. |
| 33 | r = proyek.mapLayersByName("DSM_Drone")[0] | Ambil raster dengan cara yang sama. |
| 34-35 | r.width(), r.height(), r.bandCount(), r.rasterUnitsPerPixelX() | Lebar dan tinggi dalam piksel, jumlah band, dan ukuran satu piksel dalam satuan peta. |
| 36 | len(proyek.mapLayers()) | Jumlah layer di proyek. |
Hasil. Layar menampilkan (berdasarkan uji pada QGIS 4.0.2):
Batas_KPH sah? True
DSM_Drone sah? True
Nama: Batas_KPH
CRS: EPSG:32749
Jenis geometri: Polygon
Jumlah fitur: 3
Nama field: ['fid', 'NAMA_KPH']
Raster: 800 x 800 piksel, 1 band
Ukuran piksel (m): 0.5
Jumlah layer di proyek: 2Dari hasil ini Anda tahu: layer batas berisi tiga KPH berbentuk poligon, dan rasternya 800 kali 800 piksel dengan piksel 0,5 meter.
Bagian yang boleh diubah.
- Baris 6, lokasi data. Yang paling sering Anda ubah. Pakai garis miring biasa
/, misalnya"D:/Latihan/paket-i4". - Baris 13-14, nama berkas. Ganti untuk membuka data lain, misalnya
/Sungai.gpkg. - Argumen kedua di baris 13. Ini nama di panel Layers. Bila Anda menggantinya, ganti juga isi
mapLayersByNamedi baris 25 dan 33. - Baris 25-30. Tambah baris
printbaru dengan metode lain, misalnyalayer.source(), yang menampilkan lokasi berkas layer.
Jebakan.
- Jalur salah tidak menimbulkan galat. Pada uji,
Batas_KPH.gpkgdiganti menjadiBatas_KP.gpkg. Python tidak berhenti. Layar menampilkan:
Batas_KPH sah? False
DSM_Drone sah? True
Nama: Batas_KPH
CRS:
Jenis geometri: Unknown
Jumlah fitur: -2
Nama field: []
Raster: 800 x 800 piksel, 1 band
Ukuran piksel (m): 0.5
Jumlah layer di proyek: 2Perhatikan: layer yang tidak terbuka tetap masuk proyek (jumlah layer 2). Jumlah fitur -2 artinya "tidak diketahui". Pelajarannya: selalu baca baris pertama dan kedua hasil. Bila ada False, periksa jalur di baris 6 dulu.
- Mengambil layer yang tidak ada.
proyek.mapLayersByName("Tidak_Ada")menghasilkan daftar kosong[]. Bila Anda lalu menulis[0], munculIndexError: list index out of range. Itu artinya nama yang Anda cari tidak ada di proyek. - Baris 10 mengosongkan proyek Anda.
removeAllMapLayers()mengeluarkan semua layer dari proyek yang sedang terbuka di QGIS. Jalankan skrip ini di proyek kosong, bukan di proyek kerja yang penting. QgsWkbTypes(baris 4 dan 28). Skrip berjalan tanpa galat di QGIS 4.0.2. Apakah nama ini sudah dinyatakan usang di versi tertentu, belum diperiksa [CEK].
Latihan variasi.
- Muat layer
Sungai.gpkg(garis), lalu cetak jenis bentuk, jumlah fitur, dan nama kolomnya. - Dari hasil nomor 1, sebutkan apa beda jenis bentuknya dengan
Batas_KPH.
Contoh jawaban (sudah diuji), ditulis sebagai skrip kecil sendiri:
from qgis.core import QgsProject, QgsVectorLayer, QgsWkbTypes
DATA = "D:/Latihan/paket-i4"
proyek = QgsProject.instance()
sungai = QgsVectorLayer(DATA + "/Sungai.gpkg", "Sungai", "ogr")
proyek.addMapLayer(sungai)
layer = proyek.mapLayersByName("Sungai")[0]
print("Jenis geometri:", QgsWkbTypes.displayString(layer.wkbType()))
print("Jumlah fitur:", layer.featureCount())
print("Nama field:", [f.name() for f in layer.fields()])Layar menampilkan Jenis geometri: LineString, Jumlah fitur: 2, dan Nama field: ['fid', 'NAMA', 'ORDE']. Sungai berbentuk garis, sedangkan batas KPH berbentuk poligon.
Skrip 14.3: Membaca fitur dan atribut, lalu menulis CSV #
Layer vektor itu seperti tabel. Tiap baris adalah satu fitur. Skrip ini membaca tiap baris, menghitung luas, memilih satu KPH dengan ekspresi, lalu menulis hasilnya ke berkas CSV. Ini jawaban untuk pertanyaan pertama Kepala Seksi.
Tujuan. Menghitung luas tiap KPH dalam hektare, memilih KPH tertentu dengan ekspresi, dan menyimpan hasilnya sebagai berkas CSV.
Bahan. Paket data paket-i4, berkas Batas_KPH.gpkg. Berkas b1_02_baca_atribut.py dijalankan seperti Skrip 14.2. Ganti DATA di baris 7 dan HASIL di baris 8 (folder tempat CSV ditulis; skrip membuatnya bila belum ada).

Skrip utuh:
# [SKRIP 1.2: Membaca fitur dan atribut, memilih dengan ekspresi, menulis CSV]
# Penulis: Badar Mubarok Yogaswara
import csv
import os
from qgis.core import QgsProject, QgsVectorLayer
DATA = "D:/Latihan/paket-i4"
HASIL = "D:/Latihan/hasil_i4"
os.makedirs(HASIL, exist_ok=True)
batas = QgsVectorLayer(DATA + "/Batas_KPH.gpkg", "Batas_KPH", "ogr")
QgsProject.instance().addMapLayer(batas)
# 1. Satu fitur = satu baris tabel atribut. getFeatures() membacanya satu per satu.
baris = []
for fitur in batas.getFeatures():
nama = fitur["NAMA_KPH"]
luas_ha = fitur.geometry().area() / 10000 # m2 menjadi hektare (CRS harus berupa meter)
baris.append((nama, round(luas_ha, 2)))
print(nama, round(luas_ha, 2), "ha")
total = sum(luas for _, luas in baris)
print("Total:", total, "ha")
# 2. Memilih fitur dengan ekspresi, sama seperti Select by Expression
batas.selectByExpression('"NAMA_KPH" = \'KPH Beta\'')
print("Terpilih:", batas.selectedFeatureCount(), "fitur")
for fitur in batas.selectedFeatures():
print(" ->", fitur["NAMA_KPH"])
batas.removeSelection()
# 3. Menulis hasil ke berkas CSV
jalur = HASIL + "/luas_kph.csv"
with open(jalur, "w", newline="", encoding="utf-8") as f:
penulis = csv.writer(f)
penulis.writerow(["NAMA_KPH", "LUAS_HA"])
penulis.writerows(baris)
print("CSV tersimpan:", os.path.exists(jalur))Penjelasan baris demi baris. Tiga blok, sesuai komentar di dalam skrip.
Blok A: persiapan (baris 3-12).
| Baris | Tulisan | Artinya |
|---|---|---|
| 3-5 | import csv, import os, from qgis.core ... | Panggil perkakas: csv untuk berkas CSV, os untuk urusan folder, dan dua perkakas QGIS. |
| 9 | os.makedirs(HASIL, exist_ok=True) | Buat folder HASIL. exist_ok=True berarti: bila sudah ada, jangan protes. |
| 11-12 | batas = QgsVectorLayer(...) lalu addMapLayer | Buka layer dan masukkan ke proyek, seperti di Skrip 14.2. |
Blok B: membaca tiap fitur (baris 14-23).
| Baris | Tulisan | Artinya |
|---|---|---|
| 15 | baris = [] | Siapkan daftar kosong untuk menampung hasil. |
| 16 | for fitur in batas.getFeatures(): | Ulangi untuk tiap fitur. getFeatures() membacanya satu per satu. Di tiap putaran, kotak fitur berisi satu KPH. |
| 17 | nama = fitur["NAMA_KPH"] | Ambil isi kolom NAMA_KPH. Nama kolom ditulis di kurung siku dan kutip. |
| 18 | luas_ha = fitur.geometry().area() / 10000 | geometry() mengambil bentuk fitur, area() menghitung luasnya (meter persegi bila CRS berupa meter), dan / 10000 mengubahnya menjadi hektare. |
| 19 | baris.append((nama, round(luas_ha, 2))) | Tambahkan sepasang nilai (nama dan luas, dibulatkan dua desimal) ke daftar. Pasangan seperti ini disebut tuple. |
| 20 | print(nama, round(luas_ha, 2), "ha") | Tampilkan satu baris per KPH. |
| 22-23 | total = sum(luas for _, luas in baris) | Jumlahkan semua luas. Tanda _ berarti "bagian ini tidak dipakai", yaitu nama. |
Blok C: memilih dan menulis (baris 25-38).
| Baris | Tulisan | Artinya |
|---|---|---|
| 26 | batas.selectByExpression('"NAMA_KPH" = \'KPH Beta\'') | Pilih fitur dengan ekspresi, sama seperti Select by Expression di QGIS. Teks ekspresi memakai kutip tunggal, jadi kutip tunggal di dalamnya ditulis \'. |
| 27-29 | selectedFeatureCount() dan selectedFeatures() | Hitung dan baca fitur yang terpilih. |
| 30 | batas.removeSelection() | Hapus pilihan, supaya layer kembali bersih. |
| 33-34 | with open(jalur, "w", ...) as f: | Buka berkas untuk ditulis ("w"). with menutup berkas otomatis. encoding="utf-8" mengatur kode huruf. Dibahas di Bab 9. |
| 35-37 | csv.writer(f), writerow, writerows | Tulis satu baris judul, lalu semua baris data sekaligus. |
| 38 | os.path.exists(jalur) | Buktikan berkasnya benar-benar ada. |
Hasil. Layar menampilkan (berdasarkan uji pada QGIS 4.0.2):
KPH Alpha 4.0 ha
KPH Beta 4.0 ha
KPH Gamma 8.0 ha
Total: 16.0 ha
Terpilih: 1 fitur
-> KPH Beta
CSV tersimpan: TrueBerkas luas_kph.csv di folder HASIL berisi:
NAMA_KPH,LUAS_HA
KPH Alpha,4.0
KPH Beta,4.0
KPH Gamma,8.0Bagian yang boleh diubah.
- Baris 7-8, jalur. Sesuaikan dengan komputer Anda.
- Baris 26, nama KPH. Ganti
KPH Betadengan KPH lain. Baris ini juga bisa diganti ekspresi lain, misalnya'"NAMA_KPH" LIKE \'KPH %\''[CEK]. - Baris 18, pembagi 10000. Mengubah satuan. Hapus pembagi itu dan Anda mendapat meter persegi.
- Baris 19 dan 20, angka 2. Jumlah desimal.
- Baris 33, nama berkas CSV. Ganti sesuai kebutuhan.
Jebakan.
- Nama kolom salah. Pada uji,
fitur["NAMA_KPH"]diganti menjadifitur["NAMA"]. Layar menampilkanKeyError: 'NAMA'. Artinya kolom itu tidak ada. Cek ejaan di daftarNama fieldpada hasil Skrip 14.2. - CRS berderajat. Komentar di baris 18 mengingatkan bahwa CRS harus berupa meter. Pada uji,
Batas_KPHdiubah ke EPSG:4326 (derajat), lalu skrip dijalankan. HasilnyaKPH Alpha 0.0 ha,KPH Beta 0.0 ha, danKPH Gamma 0.0 ha, tanpa galat apa pun. Angka luas tampak wajar, padahal salah. Pastikan CRS-nya metrik sebelum menghitung luas. - Satuan di tulisan. Skrip mencetak "ha" di baris 20 walau Anda sudah menghapus
/ 10000. Tulisan tidak ikut berubah otomatis. - Excel di Windows. Bila nanti nama KPH memuat huruf non-ASCII, Excel mungkin menampilkannya rusak. Cara umumnya adalah
encoding="utf-8-sig"[CEK]. Data latihan ini hanya berisi huruf biasa, jadi tidak terdampak.
Latihan variasi.
- Pilih KPH Gamma, bukan KPH Beta.
- Tampilkan luas dalam meter persegi, lengkap dengan tulisan "m2".
Contoh jawaban (sudah diuji). Untuk nomor 1, ganti baris 26 menjadi:
batas.selectByExpression('"NAMA_KPH" = \'KPH Gamma\'')Layar menampilkan -> KPH Gamma. Untuk nomor 2, ubah tiga baris:
luas_ha = fitur.geometry().area()
print(nama, round(luas_ha, 2), "m2")
print("Total:", total, "m2")Layar menampilkan KPH Alpha 40000.0 m2, KPH Beta 40000.0 m2, KPH Gamma 80000.0 m2, dan Total: 160000.0 m2. Kolom LUAS_HA di CSV juga ikut berisi angka meter persegi, jadi sebaiknya ganti juga judul kolomnya.
Skrip 14.4: Menyimpan proyek dan membukanya lagi #
Sekarang pertanyaan kedua Kepala Seksi: bisakah peta dibuka lagi besok? Skrip ini menyusun proyek dari nol, menyimpannya sebagai berkas .qgz, mengosongkannya, lalu membukanya kembali sebagai bukti isinya utuh.
Tujuan. Menyusun proyek berisi empat layer, mengatur CRS dan judulnya, menyimpannya, lalu membuktikan bahwa berkas itu bisa dibuka lagi.
Bahan. Paket data paket-i4: Batas_KPH.gpkg, Sungai.gpkg, Hotspot_Nasional.gpkg, dan Citra_KPH.tif. Berkas b1_03_simpan_proyek.py dijalankan seperti skrip sebelumnya. Ganti DATA dan HASIL di baris 6-7.

Skrip utuh:
# [SKRIP 1.3: Menyusun proyek lewat Python lalu menyimpan dan membukanya lagi]
# Penulis: Badar Mubarok Yogaswara
import os
from qgis.core import QgsProject, QgsVectorLayer, QgsRasterLayer, QgsCoordinateReferenceSystem
DATA = "D:/Latihan/paket-i4"
HASIL = "D:/Latihan/hasil_i4"
os.makedirs(HASIL, exist_ok=True)
proyek = QgsProject.instance()
proyek.removeAllMapLayers()
proyek.setCrs(QgsCoordinateReferenceSystem("EPSG:32749")) # CRS proyek: UTM zona 49S
proyek.setTitle("KPH Contoh - proyek skrip")
daftar = [
QgsVectorLayer(DATA + "/Batas_KPH.gpkg", "Batas_KPH", "ogr"),
QgsVectorLayer(DATA + "/Sungai.gpkg", "Sungai", "ogr"),
QgsVectorLayer(DATA + "/Hotspot_Nasional.gpkg", "Hotspot_Nasional", "ogr"),
QgsRasterLayer(DATA + "/Citra_KPH.tif", "Citra_KPH", "gdal"),
]
for layer in daftar:
if layer.isValid():
proyek.addMapLayer(layer)
else:
print("GAGAL dimuat:", layer.name())
berkas = HASIL + "/Proyek_KPH.qgz"
print("Tersimpan?", proyek.write(berkas)) # write() mengembalikan True bila berhasil
# Buka kembali dan buktikan isinya utuh
proyek.clear()
print("Setelah dikosongkan:", len(proyek.mapLayers()), "layer")
print("Terbuka?", proyek.read(berkas))
print("Judul:", proyek.title(), "| CRS:", proyek.crs().authid())
print("Layer:", sorted(l.name() for l in proyek.mapLayers().values()))Penjelasan baris demi baris. Hanya hal yang baru yang dijelaskan. Baris import, DATA, dan HASIL sudah dibahas di Skrip 14.2 dan 14.3.
| Baris | Tulisan | Artinya |
|---|---|---|
| 11 | proyek.removeAllMapLayers() | Kosongkan proyek, seperti di Skrip 14.2. |
| 12 | proyek.setCrs(QgsCoordinateReferenceSystem("EPSG:32749")) | Atur CRS proyek ke UTM zona 49S. Ini mengatur proyek, bukan mengubah data tiap layer. |
| 13 | proyek.setTitle("KPH Contoh - proyek skrip") | Beri judul proyek. |
| 15-20 | daftar = [ ... ] | Daftar berisi empat layer: tiga vektor dan satu raster. Daftar boleh berisi objek, bukan hanya teks atau angka. |
| 21-25 | for layer in daftar: lalu if layer.isValid(): | Untuk tiap layer: bila terbuka, masukkan ke proyek (baris 23). Bila tidak, cetak GAGAL dimuat beserta namanya (baris 25). |
| 27-28 | proyek.write(berkas) | Simpan proyek ke berkas .qgz. Metode ini mengembalikan True bila berhasil. |
| 31 | proyek.clear() | Kosongkan seluruh proyek, termasuk judul dan layer. |
| 32 | len(proyek.mapLayers()) | Buktikan proyek kosong: hasilnya 0. |
| 33 | proyek.read(berkas) | Buka kembali berkas yang tadi disimpan. |
| 34-35 | proyek.title(), proyek.crs().authid(), sorted(...) | Cetak judul, kode CRS, dan nama semua layer yang terbaca, diurutkan menurut abjad. .values() mengambil isi kamus layer. |
Hasil. Layar menampilkan (berdasarkan uji pada QGIS 4.0.2):
Tersimpan? True
Setelah dikosongkan: 0 layer
Terbuka? True
Judul: KPH Contoh - proyek skrip | CRS: EPSG:32749
Layer: ['Batas_KPH', 'Citra_KPH', 'Hotspot_Nasional', 'Sungai']Berkas Proyek_KPH.qgz kini ada di folder HASIL. Berkas ini sebenarnya paket terkompresi (zip) yang berisi berkas proyek .qgs. Hasil pemeriksaan: isinya Proyek_KPH.qgs dan satu berkas gaya.
Bagian yang boleh diubah.
- Baris 13, judul. Ganti sesuai proyek Anda.
- Baris 12, kode CRS. Ganti, misalnya, ke
"EPSG:4326". Yang berubah hanya CRS proyek, bukan data. - Baris 15-20, isi daftar. Tambah atau hapus layer.
- Baris 27, nama berkas. Ganti
Proyek_KPH.qgz.
Jebakan.
- Jalur layer salah hanya dilaporkan. Pada uji,
Sungai.gpkgdiganti menjadiSungay.gpkg. Layar menampilkanGAGAL dimuat: Sungai, tetapiTersimpan?tetapTrue. Proyek tersimpan tanpa layer Sungai, dan daftar layer di baris terakhir hanya berisi tiga nama. Selalu baca barisGAGAL dimuat. - Baris 31 mengosongkan proyek Anda. Seperti baris 11,
clear()bekerja pada proyek yang sedang terbuka di QGIS. Jangan jalankan skrip ini di proyek kerja yang belum Anda simpan. - Skrip mandiri tanpa kerangka. Pada uji, skrip ini dijalankan dengan
python-qgistanpa kerangka dari bagian "Dua cara menjalankan". Layar berhenti setelahSetelah dikosongkan: 0 layer, dan tidak selesai sampai dihentikan paksa setelah 60 detik. Dengan kerangka lengkap, skrip selesai normal.
Latihan variasi. Tambahkan layer Poligon_Sawah.gpkg ke proyek, dan simpan dengan nama Proyek_KPH_sawah.qgz.
Contoh jawaban (sudah diuji). Tambahkan satu baris di dalam daftar, dan ganti satu nama berkas:
QgsVectorLayer(DATA + "/Poligon_Sawah.gpkg", "Poligon_Sawah", "ogr"),Pada baris 27, ganti Proyek_KPH.qgz menjadi Proyek_KPH_sawah.qgz. Baris terakhir hasil menjadi Layer: ['Batas_KPH', 'Citra_KPH', 'Hotspot_Nasional', 'Poligon_Sawah', 'Sungai'].
Cek paham #
- Apa beda "kelas" dan "objek"? Beri satu contoh dari bab ini.
- Layer yang jalurnya salah tidak membuat skrip berhenti. Bagaimana Anda tahu layer itu gagal dibuka?
- Mengapa skrip mandiri perlu
QgsApplicationdaninitQgis(), sedangkan skrip di Konsol Python QGIS tidak?
Jawaban.
- Kelas adalah cetakan, objek adalah hasil cetakannya. Contoh:
QgsVectorLayeradalah kelas, danbatasadalah objek dari kelas itu. - Panggil
isValid(). NilaiFalseberarti gagal. Tanda lain: jumlah fitur bernilai -2 dan daftar kolom kosong. - Di Konsol, QGIS sudah menyala. Skrip mandiri tidak punya mesin QGIS, sehingga harus menyalakannya sendiri lalu mematikannya di akhir.
Kesalahan umum #
- Membiarkan jalur contoh.
D:/Latihan/paket-i4adalah jalur milik penulis. Perbaikan: gantiDATAdanHASILsesuai komputer Anda. - Tidak membaca baris
isValid(). Skrip tetap jalan dengan layer kosong dan hasil yang menyesatkan, seperti luas 0.0. Perbaikan: biasakan memeriksaisValid()dan membaca baris pertama hasil. - Menghitung luas pada CRS derajat. Hasilnya salah tanpa peringatan. Perbaikan: pastikan CRS berupa meter, misalnya UTM.
- Menjalankan skrip pembersih di proyek kerja.
removeAllMapLayers()danclear()mengosongkan proyek yang sedang terbuka. Perbaikan: pakai proyek kosong untuk latihan.
Ringkasan dan latihan #
- PyQGIS adalah cara Python berbicara dengan QGIS lewat API. Isinya kelas (cetakan), objek (hasil cetakan), dan metode (tombol).
- Proyek berisi layer. Layer vektor berisi fitur, layer raster berisi piksel.
- Skrip bisa jalan di dalam QGIS atau mandiri. Skrip mandiri harus menyalakan dan mematikan mesin QGIS sendiri.
- Pola dasar: muat layer, cek
isValid(), baca fitur, simpan hasil. proyek.write()menyimpan,proyek.read()membuka lagi.clear()mengosongkan proyek yang terbuka.
Latihan. Gabungkan tiga skrip bab ini. Tulis skrip yang memuat Batas_KPH.gpkg dan Hotspot_Nasional.gpkg, mencetak jumlah fitur keduanya, lalu menyimpan proyek bernama Proyek_Latihan.qgz. Bagian mana dari Skrip 14.2 dan 14.4 yang Anda pinjam?
Tabel perbandingan: dari layar ke skrip #
| Di layar QGIS | Di skrip PyQGIS | Contoh di bab ini |
|---|---|---|
| Plugins ► Python Console | Tempat mengetik skrip | Skrip 14.2 sampai 14.4 |
| Panel Layers | QgsProject.instance().mapLayers() | Jumlah layer di proyek: 2 |
| Satu layer vektor | QgsVectorLayer | batas |
| Satu layer raster | QgsRasterLayer | dsm |
| Satu baris tabel atribut | fitur dari getFeatures() | fitur["NAMA_KPH"] |
| Select by Expression | selectByExpression | Memilih KPH Beta |
| Menyimpan proyek | proyek.write(berkas) | Proyek_KPH.qgz |