Modul 3 Dan 4
Modul 3 Dan 4
Translasi
Translasi pada dasarnya adalah perpindahan. Translasi geometri adalah memindah bentuk
geometri (terhadap koordinat vertexnya) sejauh x’ dan y’ dari posisi awal (x, y). Untuk
implementasi di p5.js, menggunakan fungsi translate(x, y) yang fungsi tersebut
memindah atau menggeser koordinat (0, 0) sejauh x’ dan y’ yang dimasukkan dalam
fungsi translate(). Contoh : translate(30, 20) akan menggeser (0, 0) ke (30, 20).
[ 41 ]
Fungsi translate() ini kumulatif yang berarti jika setelah translate(30, 20) dijalankan
lagi translate(15, 20), maka (0,0) akan berpindah ke (30+15, 20+20) atau (45, 40).
Nilai negatif juga diizinkan dalam pemakaian fungsi translate() ini. Contoh implementasi:
//Segi empat di koordinat asli (0,0)
rect(0, 0, 250, 250);
translate(width/2, height/2);
rect(-200,-200, 100,100);
Rotasi
Rotasi adalah perputaran. Rotasi geometri adalah memutar bentuk geometri (terhadap
koordinat vertexnya) sebanyak sudut θ° yang diinginkan dengan acuan pusat rotasi (x, y).
Untuk implementasi di p5.js, menggunakan fungsi rotate(sudut dalam radians) yang
fungsi tersebut memutar sebuah benda dengan acuan rotasi (0,0) sejauh sudut θ° searah
jarum jam. Contoh: rotate(PI/4) atau rotate(radians(45)) akan memutar benda
berdasar (0,0) sejauh 45°.
Fungsi ini bersifat kumulatif. Menjalankan rotate(radians(45)) dua kali akan memutar
benda sejauh 90°. Nilai negatif diizinkan di fungsi ini dengan hasil rotasi berlawanan arah
jarum jam. Digabungkan dengan translate juga bisa membuat
Contoh implementasi sebuah elips (merah) dan hasil rotasinya (biru) sebanyak 45° dengan
pusat rotasi (0, 0).
function setup(){
createCanvas( 500, 500 );
background( 255 );
}
[ 42 ]
function draw(){
noFill();
stroke(255,0,0);
strokeWeight(3);
ellipse(300, 100, 400, 200);
strokeWeight(10);
point(300, 100);
strokeWeight(3);
line(0,0, 300, 100);
//rotasi geometri
rotate( PI/4 );
stroke(0,0,255);
strokeWeight(3);
ellipse(300, 100, 400, 200);
strokeWeight(10);
point(300, 100);
strokeWeight(3);
line(0,0, 300, 100);
}
Yang perlu diingat bahwa pusat rotasi adalah (0, 0). Sehingga untuk memutar benda di
tempat koordinatnya, kita bisa memindahkan terlebih dahulu pusat (0, 0) ke koordinat
benda dan melakukan rotasi benda dengan menggabung translate() dan rotate().
Contoh implementasi berdasarkan contoh sebelumnya:
//rotasi geometri
translate(300,100);
rotate( PI/4 );
stroke(0,0,255);
strokeWeight(3);
ellipse(0, 0, 400, 200);
strokeWeight(10);
point(0, 0);
Dengan teknik ini, bisa dilihat bahwa dalam pembentukan benda yang dirotasi di
koordinatnya, di setel ke (0, 0) agar berotasi di tempatnya.
Skala
Skala adalah pengaturan besar kecilnya bentuk geometri (terhadap koordinat vertexnya)
berdasarkan scaling factor (faktor pengali). Untuk implementasi di p5.js menggunakan
fungsi scale() yang fungsi tersebut mengalikan setiap koordinat (x, y) dengan faktor
pengali persentase decimal (dengan 1.0 sama dengan 100%). Contoh: scale(2.0) berarti
membesarkan benda 200%, sementara scale(0.7) mengecilkan benda sebesar 30% atau
menjadi 70%.
[ 43 ]
dijadikan faktor pengali yang menyebabkan koordinat menjadi negatif atau sebaliknya.
Contoh implementasi:
function setup(){
createCanvas( 500, 200 );
background( 255 );
}
function draw(){
noFill();
stroke(255,0,0);
rect(10, 10, 50, 50);
stroke(0,0,255);
rect(150, 10, 50, 50);
//skala geometri
scale( 2.0 );
stroke(255,0,0);
rect(10, 10, 50, 50);//kotak merah diskala
stroke(0,0,255);
rect(150, 10, 50, 50);//kotak biru diskala
}
Bisa dilihat bahwa kotak merah dan biru sebelum di skala, koordinat berada di tempat awal:
(10, 10) dan (150, 10). Setelah di skala 200% (2 kali lipat), koordinat kotak merah bergeser
ke (20, 20), sementara kotak biru bergeser ke (300, 20). Selain itu tebal garis keduanya juga
menjadi lebih tebal dua kali lipat.
Perlu diingat lagi bahwa yang mengalami transformasi skala adalah bidang koordinatnya,
sehingga pergeseran karena skala di contoh implementasi disebabkan bidang koordinat
yang berukuran 200%.
Refleksi
Refleksi pada dasarnya transformasi yang membuat sebuah benda bisa mengalami
pertukaran koordinat positif dan negatifnya –seperti cermin yang merefleksikan bayangan
benda.
Refleksi geometri adalah bentuk khusus dari transformasi skala; yaitu dengan nilai yang
sudah tetap untuk x dan y: (1) atau (-1). Terdapat beberapa bentuk refleksi geometri yang
bisa dipakai:
• Refleksi terhadap sumbu x : scale(1, -1)
• Refleksi terhadap sumbu y : scale(-1, 1)
• Refleksi terhadap (0,0) : scale(-1, -1)
Dengan menggunakan transformasi refleksi ini, kita bisa mendapatkan efek cermin (mirror)
horizontal atau vertikal terhadap sebuah benda. Contoh implementasi refleksi sumbu Y
untuk menghasilkan efek flip horizontal sebuah citra:
function setup(){
createCanvas( 720, 360 );
[ 44 ]
background( 255 );
foto = loadImage("olah-citra.jpg");
foto.resize(360,360);
}
function draw(){
image(foto,0,0);
scale(-1,1);//refleksi terhadap sumbu y
image(foto,-720,0);//tampilkan di koordinat asli (720,0)
stroke(#ffffff);
strokeWeight(2);
line(-360,0,-360,360);//garis pemisah
}
Bisa dilihat bahwa terdapat konsekuensi jika memakai teknik refleksi ini. Karena yang
ditransformasi adalah bidang koordinatnya, dengan scale(-1, 1), bidang koordinat x
menjadi terbalik: x negatif mengarah ke kanan, dan x positif mengarah ke kiri. Sehingga
fungsi image yang menampilkan ke arah x positif, menjadi menampilkan kearah sebaliknya
dengan acuan koordinat dari pojok kanan atas; karena itu image ke-2 ditempatkan di
koordinat (-720,0)
Shear (Skew)
Shear atau geser geometri pada dasarnya adalah menggeser vertex di salah satu sisi bentuk
sejauh nilai penggeserannya (x, y), dengan satu sisi tetap di tempat yang sama.
Penggeseran yang dilakukan juga bisa dilakukan dengan parameter sudut penggeseran. Ini
yang diimplementasikan di p5.js.
Terdapat dua jenis shear sebagai fungsi di p5.js: shearX() dan shearY(). Kedua fungsi
tersebut memiliki satu parameter sudut dalam radians yang digunakan untuk menentukan
penggeseran yang dilakukan. Contoh implementasi penggeseran sumbu x atau y dengan
interaksi untuk menaikkan atau menurunkan sudut penggeseran:
[ 45 ]
let sudutX = 0;
let sudutY = 0;
function setup(){
createCanvas(600,400);
background(255);
}
function draw(){
background(255);
noStroke();
fill(255,0,0,150);
rect(100,100,200,200);
shearY( radians(sudutY) );
shearX( radians(sudutX) );
fill(0,0,255,150);
rect(100,100,200,200);
}
function keyPressed(){
if( keyCode == UP_ARROW ){ sudutY+=5; }
if( keyCode == DOWN_ARROW ){ sudutY-=5; }
if( keyCode == LEFT_ARROW ){ sudutX-=5; }
if( keyCode == RIGHT_ARROW ){ sudutX+=5; }
}
Dari contoh implementasi, fungsi shear di p5.js menggeser berdasarkan sudut yang
ditentukan (dalam radians). Grid sebagai latar belakang untuk menunjukkan seberapa
besar perubahan yang terjadi terhadap bidang koordinat karena fungsi shear.
Bisa dilihat bahwa terjadi penggeseran koordinat pembentukannya juga, sehingga dalam
menggunakan fungsi shear harus berhati-hati karena terdapat penggeseran yang tidak
linear –sulit untuk dihitung karena berdasarkan sudut. Agar tidak terjadi penggesaran
koordinat, kita bisa menggabungkan dan membatasi transformasi geometri yang
dijalankan.
[ 46 ]
Stack Transformasi Geometri
Dalam menjalankan transformasi geometri di p5.js, kita harus memperhatikan letak kapan
transformasi itu dijalankan. Karena selain berpengaruh ke bidang koordinat, setelah
dijalankan, maka bagian dibawahnya juga terkena transformasi –walau pun tidak
diperlukan. Untuk mengatasi masalah ini, digunakan matrix stack untuk transformasi
geometri.
Contoh implementasi untuk fungsi translate() dan rotate() yang sudah dibahas, kali ini
dengan matrix stack:
function setup(){
createCanvas(600,400);
}
function draw(){
background(255);
noStroke();
fill(255,0,0,150);
ellipse(300,200,400,200);
push ();
translate(300,200);
rotate( radians(60) );
fill(0,0,255,150);
ellipse(0,0,400,200);
pop();
fill(0,150);
rect(0,0,100,100);//tidak ada transformasi lagi
}
[ 47 ]
Dari contoh bisa dilihat bahwa segiempat yang dibentuk dengan fungsi rect() sudah tidak
terpengaruh oleh translate() dan rotate() yang dijalankan di dalam stack.
Selain untuk membatasi proses transformasi, kita juga bisa menggunakan matrix stack ini
untuk melakukan transformasi gabungan dengan aman tanpa harus khawatir berimbas ke
bawahnya. Misalkan untuk melakukan transformasi skala tanpa benda terpindah dari
koordinat asalnya, kita gabungkan penggunaan translate() dan scale():
...
function draw(){
background(255);
noFill();
stroke(255,0,0);
strokeWeight(2);
rect(50, 50, 100, 100);
push();
translate(50,50);
scale( 2.0 );
rect(0, 0, 100, 100);
pop();
stroke(0,0,255);
strokeWeight(2);
rect(350, 50, 100, 100);//kotak biru tidak terskala
}
Bisa dilihat bahwa kotak biru yang terbentuk setelahnya tidak terkena dampak skala. Juga
perhatikan bahwa koordinat pembentukan rect() setelah skala adalah (0,0); yaitu hasil
dari koordinat asli (100,100) dikurangi sejauh apa di translasi, yaitu (100,100).
Kita juga bisa menggunakan teknik ini untuk contoh shear sebelumnya:
…
push();
translate(100,100);
shearY( radians(sudutY) );
shearX( radians(sudutX) );
[ 48 ]
Animasi Gerakan di p5.js
Di p5.js, dengan memanfaatkan transformasi geometri kita bisa membuat animasi gerakan
benda: gerakan linear (linear motion), dan gerakan bersudut (angular motion). Cara
implementasinya dengan memanfaatkan fungsi draw() dan millis(). Tapi sebelum itu
kita pahami dulu tentang framerate.
Framerate
Fungsi draw() pada dasarnya adalah menjalankan kode program di dalamnya sebanyak
sekian kali per detiknya –atau dalam kata lain menggambar sekian frame per detik (frame
per second). Frame per Second (fps) adalah satuan penayangan grafik. Misalkan 60 fps
berarti terjadi penggambaran/pembuatan frame sebanyak 60 kali dalam satu detik.
Di p5.js kita bisa menyetel frame rate dengan fungsi frameRate(n) dengan n adalah nilai
fps yang diinginkan. Nilai defaultnya adalah 60. Untuk mengecek fps yang sedang berjalan
kita bisa menggunakan variabel frameRate. Nilai setelan fps yang kita jadikan acuan dalam
membuat animasi gerakan.
Gerakan Linear
Untuk membuat gerakan linear, pada dasarnya kita memanipulasi koordinat x dan y dari
sebuah benda di p5.js. Setidaknya ada dua cara untuk membuat gerakan linear: dengan
variabel koordinat, atau dengan translate().
Variabel Koordinat
Untuk cara ini, kita bisa membuat variabel koordinat x dan y di luar setup() dan draw().
Menginisialisasi di setup(), kemudian digunakan di draw(). Misalkan:
let x, y;
function setup(){
createCanvas(400,300);
background(255);
x = 50;
y = 50;
}
function draw(){
background(255);
x = x + 5;
fill(0,0,255,150);
rect(x,y,100,100);
}
Dengan fps 60, jika terdapat kode program x = x + 5 di dalam draw, maka itu berarti nilai x
ditambahkan 60 x 5 = 300 per detiknya –karena dijalankan 60 kali per detik. Sehingga jika
ingin menggerakkan 1 pixel per detik, kita harus menambahkan x dengan 1/60 (atau
0,016667). Cara ini praktis, namun jika ingin menggerakkan dengan timing yang lebih
[ 49 ]
akurat akan sulit. Untuk timing yang lebih akurat, kita bisa gunakan millis() digabung
dengan translate().
function draw(){
background(255);
push();
translate(millis()*0.001*100,0);
fill(0,0,255,150);
rect(50,50,100,100);
pop();
}
Kode program itu menghasilkan gerakan ke kanan sejauh 100 pixel per detik. Bedanya
dengan yang sebelumnya sekarang kita bisa lebih mudah mengatur timing gerakan. Misal
kita ingin membuat segiempat bergerak ke kanan 50 pixel per detik, kita tinggal mengganti
nilai 100 menjadi 50 di translate(millis()*0.001*50,0).
Gerakan Bersudut
Untuk gerakan bersudut, kita memanfaatkan fungsi rotate() dan millis() secara
bersamaan. Dengan ini kita juga bisa lebih mengendalikan t iming rotasi dari suatu benda.
Misalkan berdasarkan kode program sebelumnya, kita buat sebuah segiempat berputar
pada porosnya 15 derajat per detiknya:
function setup(){…}
function draw(){
background(255);
push ();
translate(width/2,height/2);
rotate(millis()*0.001*radians(15));
fill(0,0,255,150);
rectMode(CENTER);
rect(0,0,100,100);
pop();
}
Perlu diingat bahwa fungsi rotate() memanfaatkan fungsi radians() untuk mendapatkan
nilai sudut dengan benar.
[ 50 ]
Animasi Gerakan Kompleks
Dengan memanfaatkan kombinasi transformasi geometri kita bisa membuat animasi yang
lebih kompleks.
Rotasi Planet
Misalkan untuk membuat animasi rotasi dan revolusi planet bumi yang mengitari matahari,
dan terdapat bulan yang mengitari bumi; kita bisa menggabungkan translate(),
rotate() dan millis(), dan juga membuat matrix stack di dalam matrix stack. Contoh
implementasi:
function setup(){
createCanvas(700,700);
background(255);
}
function draw(){
background(255);
push ();
translate(width/2,height/2);
strokeWeight(3);
//matahari di tengah layar
fill('#FF7C00');
ellipse(0,0,200,200);
//bumi mengitari matahari
rotate(millis()*0.001*radians(10));
fill('#0081FF');
ellipse(250,0,100,100);
//bulan mengitari bumi
push();
translate(250, 0);//memindah pusat rotasi ke bumi
rotate(millis()*0.001*radians(60));
fill('#8E8E8E');
ellipse(100,0,50,50);
pop();
pop();
}
Terdapat matrix stack ke-2 yang berada di dalam matrix stack pertama. Fungsinya adalah
agar membatasi gerakan bulan mengitari bumi hanya terjadi terhadap bulan.
Tapi perlu diingat bahwa jika terdapat rotate() sebelumnya, yang berada di bawahnya
juga terkena rotasi (karena akumulatif); dalam hal ini rotasi bumi 10° juga mengenai bulan.
Cobalah untuk mengganti nilai rotasi bulan menjadi -10°; maka bulan akan berhenti
mengitari bumi karena rotasi bumi 10° dikurangi dengan -10° adalah 0.
Hal ini perlu diperhatikan jika misal ingin bumi berotasi 10°, dan bulan 60°; maka bulan
harus disetel rotasi 50° karena sudah mendapat rotasi 10° dari rotate() untuk bumi.
Collision Detection
Dengan memakai prinsip dasar gerakan linear, kita juga bisa membuat animasi pantulan
benda atau ketika benda menabrak. Dalam bidang simulasi (game misalnya) disebut
[ 51 ]
collision detection. Simulasi yang sederhana adalah benda memantul jika sampai pinggir
jendela aplikasi.
Algoritma sederhana untuk membuat benda memantul adalah gerakkan benda dengan
variabel kecepatan, ketika sampai tepian, kecepatan tersebut nilainya dibuat negatif
sehingga arah benda berubah. Contohnya adalah sebagai berikut:
let x, y;
let vx, vy;
let ukuran;
function setup(){
createCanvas(600,300);
background(255);
x = 50; y = 50;
vx = 5; vy = 5;
ukuran = 50;
}
function draw(){
background(255);
x = x + vx;
y = y + vy;
strokeWeight(3);
fill('#5FD823');
ellipse(x, y, ukuran, ukuran);
//cek tepi
if(x < ukuran/2 || x > width-ukuran/2){ vx = vx * -1; }
if(y < ukuran/2 || y > height-ukuran/2){ vy = vy * -1; }
}
Dalam program tersebut menggunakan variabel koordinat x dan y, kecepatan bola vx dan
vy, serta variabel ukuran. Dalam mendeteksi tepi, kita harus memperhatikan bentuk dari
benda. Untuk lingkaran, secara visual benda sudah mencapai tepi ketika koordinat benda
setengah dari ukuran lingkaran (jari-jari). Karena itu di cek ketika koordinat ukuran/2 ketika
di tepi minimal dan maksimal.
[ 52 ]
TUGAS PRAKTIKUM MODUL 3 – TRANSFORMASI & ANIMASI
1. Berdasarkan contoh pertama dari animasi gerakan kompleks, buatlah sebuah aplikasi
p5.js yang menunjukkan matahari, bumi, dan bulan dalam bentuk persegi empat.
Namun masing-masing juga berotasi terhadap porosnya sendiri; dengan arah rotasi
bumi berbeda dengan matahari dan bulan.
Contoh luaran:
2. Berdasarkan contoh kedua dari animasi gerakan kompleks, buatlah sebuah aplikasi
p5.js yang menunjukkan persegi empat yang berputar pada porosnya 180° per detik,
dan bergerak memantul dalam jendela aplikasi.
Contoh luaran:
[ 53 ]
Halaman ini sengaja dikosongkan
[ 54 ]
Modul 4
Visualisasi Data
Modul ini membahas tentang bagaimana membaca data dari file, dan melakukan visualisasi
data dengan menggunakan p5.js. Visualisasi data adalah proses merepresentasikan ulang
data yang kita miliki dalam bentuk visual.
Membaca File
Agar lebih mudah melakukan visualisasi data, akan lebih praktis jika kita bisa membaca file
dari sistem komputer atau asset di online editor, sehingga kita tidak perlu menuliskan ulang
data yang akan di-visualkan. Data yang akan dipakai diunggah dahulu ke online editor atau
ditempatkan di folder yang bisa diakses oleh web di lokal..
Untuk membaca file yang diperlukan untuk visualisasi data, ada beberapa cara di p5.js:
loadStrings() dan loadTable().
Jika dibaca dengan loadStrings() dan dimasukkan ke dalam array, maka isi array
berdasarkan indeksnya akan menjadi seperti berikut:
[0] "Komputer grafik dan visualisasi data"
[1] "praktikum Modul 4 - Visualisasi Data"
[2] "Membaca isi tulisan dari file"
[3] "sebagai String dengan loadString()"
[4] "dengan setiap baris menjadi komponen array"
Untuk membaca file seperti itu (dengan setiap baris merupakan baris baru), kita bisa
langsung membuat array tipe String untuk menyimpan data, dan menggunakan
loadStrings() untuk langsung membacanya. Untuk membaca file di p5.js, sebaiknya
dilakukan di dalam fungsi preload() dan kemudian dipakai di dalam setup() atau draw().
[ 55 ]
Bentuk lain file yang bisa dibaca bisa berupa data-data angka seperti berikut:
Untuk membaca data seperti itu dan memasukkannya sebagai komponen, kita harus
memprosesnya terlebih dahulu. Langkah-langkahnya adalah sebagai berikut:
1. Membaca isi file sebagai string
2. Memecah string untuk mendapatkan data angka
3. Menyimpan data angka ke dalam array
Untuk membaca isi file sebagai string, kita bisa menggunakan loadString() secara
langsung seperti pada contoh pertama:
teksAngka = loadStrings("contoh-loadstring-angka.txt");
Array data akan berisi string sesuai isi file di komponen pertama (index 0):
[0] "46,78,98,65,25,14,56,41,35,84"
Untuk memecahnya agar setiap angka bisa sebagai nilai setiap komponen array, kita
gunakan fungsi split(value, delimiter).
Fungsi ini digunakan untuk memecah String berdasarkan delimiter (pemisah). Delimiter
bisa berupa koma (“,”), spasi(“ “), titik koma (“;”), atau lainnya tergantung dari format
data yang dipakai. Untuk data di atas digunakan koma, sehingga kita setel parameter
delimiter dengan koma. Kita bisa langsung memakai array String yang sama:
[ 56 ]
teksAngka = split(teksAngka[0], ",");
atau dengan mengakses langsung komponen array data dan langsung melakukan konversi.
Misal ketika ingin mengakses komponen indeks 0 sebagai bilangan asli: float(data[0]).
Cara lain untuk membaca data adalah membacanya sebagai tabel.
[ 57 ]
2018 10 22 0 0 30.31 0.00
2018 10 23 0 0 30.16 0.00
2018 10 24 0 0 30.16 0.00
2018 10 25 0 0 30.12 0.00
2018 10 26 0 0 29.82 0.00
2018 10 27 0 0 30.57 0.00
2018 10 28 0 0 30.54 0.00
2018 10 29 0 0 29.47 0.00
2018 10 30 0 0 30.40 0.00
Format CSV banyak dipakai karena sederhana dan bisa untuk menyimpan data dengan
jumlah yang cukup besar. Kita bisa memakai cara sebelumnya untuk membaca data yang
ada, namun akan cukup merepotkan karena dalam file CSV terdapat “header”, dan hal
lainnya. Untuk membaca file langsung sebagai tabel terdapat fungsi loadTable() di p5.js.
Fungsi itu yang akan kita pakai.
Untuk menangani data yang sudah berbentuk tabel, di p5.js kita bisa langsung
menggunakan tipe data p5.Table (https://p5js.org/reference/#/p5.Table). Untuk
memakainya, kita definisikan terlebih dahulu seperti variabel biasa. Misalkan tabel
bernama cuaca: let tabelCuaca;
Parameter “header” digunakan jika file csv atau tsv yang digunakan memiliki header di
baris pertama. Jika tidak ada header maka tidak usah ditulis. Setelah memuat file csv
tersebut, maka tabel data sudah memiliki data di dalamnya.
Untuk mengakses data di dalamnya, tipe data Table sudah memiliki berbagai method yang
bisa dipakai. Kita juga bisa menambah field baru (kolom), atau menambah data baru jika
dibutuhkan. Misalkan untuk mengakses data suhu rata-rata dan tanggal (hari) dari data
yang dicontohkan:
let tabelCuaca, baris;
let hari, suhu;
function preload(){
tabelCuaca = loadTable("prakiraan-cuaca-surabaya.csv",
"csv","header");
}
function setup(){
createCanvas(400,400);
baris = tabelCuaca.getRows();
[ 58 ]
for(let i in baris){
hari = baris[i].getNum("Hari");
suhu = baris[i].getNum("Suhu Rata-rata");
print(“Suhu rata-rata pada tgl "+ hari + " adalah "+
suhu +" derajat celsius");
}
}
function draw(){
background(220);
}
Dalam perulangan di atas terdapat perulangan for(let i in baris) yang berfungsi untuk
secara berulang mengakses setiap baris sebagai objek p5.TableRow dengan nama baris,
dari semua baris dari tabel cuaca (tabelCuaca.getRows()).
Jadi untuk mendapatkan data di dalam objek Table, kita bisa menentukan mengaksesnya
sebagai tipe data apa. Dalam kasus di atas “Hari” adalah tipe integer karena data yang
ada hanya bilangan bulat, dan “Suhu Rata-rata” dimuat sebagai tipe float karena
membutuhkan angka desimal. Jika mau atau dibutuhkan, kita bisa mengakses data dalam
tabel sebagai String, misalkan untuk “Hari” dan “Suhu Rata-rata” sebagai String:
hari = baris[i].getString("Hari");
suhu = baris[i].getString("Suhu Rata-rata");
Karena sebagai String, jika ingin diolah maka harus dikonversi dahulu. Juga perlu
diperhatikan: jika terdapat bilangan yang terdapat nilai desimal tapi diakses sebagai
integer, maka nilainya akan dibulatkan.
Untuk mengakses baris (row) atau kolom (column) dari tipe data p5.Table, indeks dimulai
dari 0 seperti array. Untuk mengakses baris, kita gunakan indeks mulai dari nol, sementara
untuk mengakses kolom bisa digunakan indeks atau nama kolom. Nama kolom adalah field
dari header tabel yang dibuat. Dari contoh misalkan “Tahun”, atau “Hari”.
Misalkan untuk mendapatkan suhu rata-rata dari hari ke-16 dari data contoh, kita bisa
mengaksesnya sebagai baris pertama (indeks 0) dan kolom ke-6 (indeks 5) dengan menulis
tabelCuaca.getRow(0).get(5);
Kita juga bisa menuliskan nama kolom sebagai pengganti indeks kolom:
tabelCuaca.getRow(0).get("Suhu Rata-rata");
[ 59 ]
Setelah mengetahui cara membaca data dari file, selanjutnya adalah mulai melakukan
proses visualisasi data.
Memetakan Nilai
Dalam proses visualisasi data, kita perlu untuk memetakan nilai dahulu. Memetakan nilai
disini berarti menerjemahkan dari satu rentang nilai, ke rentang nilai yang lain. Contoh
paling sederhana pemetaan nilai: bilangan desimal 0.5 yang bisa dipetakan sebagai 50%
dalam persen. Itu berarti nilai 0.5 dalam rentang 0.0 – 1.0 di petakan ke rentang 0 – 100
sebagai nilai 50. Untuk memetakan nilai di p5.js kita bisa menggunakan fungsi map().
Dengan sintaks sebagai berikut:
map(value, start1, stop1, start2, stop2);
Untuk kasus 0.5 menjadi 50%, dengan fungsi map() di p5.js bisa dituliskan sebagai
map(0.5, 0, 1, 0, 100); yang berarti nilai antara 0 s.d 1 dipetakan ke 0 s.d 100.
Untuk visualisasi data, sebagai contoh untuk menampilkan data suhu rata-rata di atas
(data-temperatur.txt) per hari sebagai sebuah grafik batang, yang ditampilkan di dalam
jendela aplikasi berukuran 300 x 300, maka kita harus petakan terlebih dahulu.
Yang perlu dipetakan adalah “tinggi” dari grafik batang; yaitu dengan memetakan nilai suhu
sebagai tinggi dari segiempat untuk membentuk grafik –untuk menggambarkan naik
turunnya suhu dengan tepat.
[ 60 ]
Untuk memetakan, kita harus tahu rentang nilai yang akan dipakai. Dimulai dari rentang
nilai asal yaitu nilai suhu. Dengan rata-rata nilai berada di sekitar 30, kita bisa membuatnya
batas bawah suhu adalah 0, dan batas atas adalah 40.
Kemudian untuk rentang nilai tujuan, karena berurusan dengan tinggi, maka tinggi jendela
aplikasi (300) bisa dijadikan patokan batas atas rentang nilai tujuan. Sementara batas
bawah bisa disetel menjadi nol.
Maka pemetaannya di p5.js: map(suhu,0,40,0,300) dengan suhu adalah nilai suhu yang
dipetakan. Fungsi itu dipakai sebagai tinggi dari grafik. Setelah itu kita bisa mulai membuat
grafiknya.
Untuk kasus yang telah dicontohkan, kita buat dulu kerangka awal aplikasi dengan ukuran
jendela aplikasi 300 x 300:
function setup(){
createCanvas(300,300);
background(255);
}
function draw(){
background(255);
}
Setelah itu kita mulai dari membaca data yang telah ditunjukkan sebelumnya:
data-temperatur.txt dengan isian data:
30.31,30.19,29.71,29.61,30.46,29.51,30.31,30.16,30.16,30.12,29.82,30.57,30
.54,29.47,30.40
Kita muat file tersebut dan membaca isinya sebagai array tipe String dengan
loadStrings(), kemudian kita konversi ke dalam array tipe float untuk menyimpan nilai
suhu dalam sebuah array. Berikut tambahannya ke dalam kode awal:
let data = [];
let suhu = [];
function preload(){
data = loadStrings("data-temperatur.txt");
}
function setup(){
...
data = split(data[0],",");
for(let i in data){
suhu[i] = parseFloat(data[i]);
}
}
[ 61 ]
Setelah menyimpan data suhu sebagai array, selanjutnya adalah membuat grafik batang
dengan fungsi rect(). Perlu diperhatikan bahwa kita perlu juga menghitung koordinat
penempatan grafik batang setelah sebelumnya kita menentukan tingginya dengan fungsi
map().
Untuk koordinat penempatan grafik batang, kita bisa menghitung lebar dari grafik batang
yang akan kita pakai. Dari data, terdapat 15 nilai suhu, sehingga jumlah grafik batang yang
dibuat adalah 15. Nilai tersebut bisa kita dapatkan dengan mengakses nilai panjang dari
array suhu: suhu.length.
Dengan lebar jendela aplikasi 300 pixel, maka kita bisa membuat lebar setiap grafik batang
adalah: 300/15 = 20 pixel agar semua grafik batang muat di dalam jendela aplikasi. Kita
bisa menuliskan lebar setiap grafik batang dengan: width/suhu.length.
Setelah mendapatkan lebar dari grafik batang, untuk penempatannya kita bisa
menggunakan perulangan. Penentuan koordinat x didapatkan dengan mengalikan
pengulang (i) dengan lebar grafik batang: i*width/suhu.length. Untuk koordinat y
sendiri nilainya selalu 0 karena grafik batang berada di alas yang sama. Untuk lebar dan
tinggi sudah kita dapatkan sebelumnya.
Kita tuliskan perulangan untuk menampilkan grafik batang sebagai berikut:
function draw(){
…
for(let i = 0; i < suhu.length; i++){
rect(i*width/suhu.length,0,
width/suhu.length,map(suhu[i],0,40,0,height));
}
}
[ 62 ]
Yang pertama mengubah semua nilai koordinat y menjadi height-y. Dengan mengambil
nilai tinggi jendela aplikasi dikurangi dengan nilai koordinat y, maka grafik yang ditampilkan
akan terbalik secara vertical. Sehingga arah visualisasi data sesuai dengan yang diinginkan.
Tapi cara ini memiliki kelemahan kita harus memastikan satu-satu setiap bagian program
yang menggunakan koordinat y sudah diubah –sehingga rentan ada yang terlewat.
Cara kedua adalah memanipulasi kondisi koordinat di
p5.js dengan fungsi transformasi geometri. Caranya
dengan memindah (0,0) ke (height,0), kemudian
dilakukan refleksi geometri terhadap sumbu x: (1, -1).
Implementasinya sebagai berikut:
function draw(){
background(255);
translate(0,height);
scale(1,-1);
…
}
Cara ini akan membuat semua bagian di bawah transformasi akan berperilaku sebagaimana
koordinat kartesius di matematika: sumbu y positif mengarah ke atas. Dengan ini semua
visualisasi data akan memiliki arah yang sesuai dan lebih mudah karena tidak perlu
memastikan satu-satu koordinat y dalam kode program.
Penyesuaian Rentang Pemetaan
Masalah kedua adalah perbedaan tinggi grafik batang yang tidak signifikan sehingga
perbedaan nilai yang divisualisasi tidak terlalu jelas. Masalah ini terletak pada pemetaan
rentang nilai suhu (0 – 40) ke rentang tinggi grafik (0 – 300).
Rentang nilai suhu dari 0 ke 40 terlalu lebar, sehingga perbedaan kecil dalam desimal tidak
terlalu terlihat. Solusinya adalah mempersempit rentang tersebut agar perbedaan kecil
bisa lebih terlihat. Kita bisa melihat data yang ada. Misal jika suhu di Surabaya, maka kita
bisa menaikkan batas bawah ke nilai 25, dan nilai atas tetap di 40.
Perbedaannya sudah terlihat tapi belum signifikan. Tapi masih terdapat masalah bagian
atas grafik yang terlalu “kosong” karena data maksimal ada di kisaran 30 – 31, sementara
rentang atas adalah 40. Sehingga kita kecilkan rentang atas menjadi 31 sesuai data.
Dari grafik terlihat perbedaan tinggi grafik sudah cukup terlihat. Tapi ternyata grafik
menjadi terlalu tinggi; karena rentang bawah 25 menyebabkan grafik meninggi dengan nilai
data berkisar antara nilai 29 s.d 31. Kita bisa naikkan lagi rentang bawah menjadi 29 agar
grafik yang dihasilkan bisa lebih tepat. Hasilnya adalah pemetaan suhu dalam bentuk grafik
batang dengan naik turunnya suhu sudah bisa terlihat dengan jelas. Berikut perbandingan
implementasi pemetaan berbagai rentang nilai untuk tinggi grafik dengan x adalah nilai
suhu.
[ 63 ]
Hasil (kiri) map(x,25,40,0,300), map(x,25,31,0,300) (tengah), dan map(x,29,31,0,300) (kanan)
Perlu diingat bahwa penentuan rentang nilai yang dipetakan bisa dilihat dari karakteristik
data yang ada. Kasus di atas dengan melihat batas bawah dan batas atas nilai data yang
ada.
Color Coding dalam Visualisasi Data
Color coding pada dasarnya adalah pemberian warna dalam grafik visualisasi data yang bisa
membantu manusia dalam memahami isi dari visualisasi data yang dilakukan. Misalkan
untuk suhu kita bisa membuat warna biru jika semakin mendekati nol, dan merah gelap
jika semakin mendekati 100 derajat. Dengan warna manusia bisa langsung mengerti dan
memahami data yang ada.
Untuk contoh yang kita pakai, karena suhunya berkisar di rentang nilai yang kecil, kita tidak
perlu sampai membuat dua warna. Tapi pemberian warna monokrom bisa tetap
membantu orang lain dalam memahami visualisasi data yang kita buat.
Misalkan kita ingin memberi warna dalam greyscale untuk grafik batang kita untuk
menunjukkan semakin tinggi suhunya, semakin gelap warna grafik batangnya; dan
sebaliknya, semakin rendah suhunya semakin cerah warnanya. Kita bisa melakukan ini
dengan memetakan nilai suhu ke rentang nilai warna RGB (0 – 255).
Karena kondisinya semakin tinggi suhu, semakin gelap
warna, maka pemetaan yang dilakukan dari rentang
nilai suhu 29 s.d 31, ke rentang nilai RGB secara terbalik
(255 – 0). Kita gunakan fungsi map sebagai berikut yang
disisipkan ke dalam perulangan karena kita ingin
menentukan warna setiap grafik batang:
function draw(){
…
for(let i in suhu){
fill(map(suhu[i],29,31,255,0));
rect(i*width/suhu.length,0,
width/suhu.length,map(suhu[i], 29,31,0,height));
}
}
[ 64 ]
Pemetaan ke rentang terbalik dari (29,31) ke (255,0) dimungkinkan. Dengan ini didapatkan
hubungan semakin tinggi suhu, semakin rendah nilai RGB warna. Kita juga bisa memberi
warna monokrom misalkan monokrom merah dengan memodifikasi bagian fill()
menjadi fill(map(suhu[i],29,31,255,0),0,0).
Grafik batang dengan warna monokrom merah (kiri), hijau (tengah), dan biru (kanan)
Untuk warna lain seperti monokrom biru atau hijau juga bisa dilakukan seperti contoh di
atas. Kita juga bisa memberi stroke(255) agar grafik batang bisa lebih nyaman dilihat
dengan garis yang mengelilingi berwarna putih. Jika warna grafik batangterlalu gelap, kita
bisa menaikkan batas nilai rentang (255,0) dari 0. Misalkan kita buat menjadi (255,50)
agar warna yang dihasilkan tidak terlalu gelap. Hasil pengubahannya bisa dilihat sebagai
berikut:
Setelah berhasil membuat grafik batang, sekarang kita coba membuat bentuk grafik lainnya
seperti grafik garis.
Grafik Garis
Untuk membuat grafik garis. Secara umum proses dasarnya sama dengan membuat grafik
batang, tapi perlu memperhatikan bagaimana sebuah garis dibentuk. Di p5.js, garis
membutuhkan dua titik: (x1, y1) dan (x2, y2), berbeda dengan bentuk segiempat yang
hanya membutuhkan satu titik koordinat untuk pembuatannya. Sehingga dalam
pembuatan grafik garis harus memodifikasi perulangan yang ada.
[ 65 ]
Untuk membuat grafik garis, kita bisa memulai dari implementasi grafik batang
sebelumnya:
let data = [];
let suhu = [];
function preload(){
data = loadStrings("data-temperatur.txt");
}
function setup(){
createCanvas (300,300);
background(255);
data = split(data[0],",");
for(let i in data){
suhu[i] = parseFloat(data[i]);
}
}
function draw(){
background(255);
translate(0, height);
scale(1, -1);
for(let i in suhu){
stroke(255);
fill(map(suhu[i],29,31,255,0));
rect(i*width/suhu.length, 0,
width/suhu.length, map(suhu[i],29,31,0,300));
}
}
Yang perlu kita ubah dan tambahkan adalah bagian yang membentuk grafik batang yaitu
pada bagian perulangan untuk membentuk grafik batang, kita tambahkan kode untuk
membentuk grafik garis.
Telah dijelaskan untuk membentuk garis membutuhkan dua titik yang di-implementasikan
dengan fungsi line(x1,y1,x2,y2) di p5.js. Titik pertama dan kedua adalah (x,y) dari nilai
suhu yang divisualisasi. Posisi x dari titik
ditentukan sama seperti ketika membentuk
grafik batang (i*width/suhu.length), dan
posisi y ditentukan dengan pemetaan nilai
suhu yang ada (map(suhu[i],
29,31,0,height)).
[ 66 ]
suhu.length-1 karena jika tidak dikurangi satu maka akan terjadi array index out of
bounds. Sehingga kita bisa tambahkan perulangan untuk membuat grafik garis sebagai
berikut:
…
function draw(){
…
stroke(0);
for(int i=0; i < suhu.length-1; i++){
strokeWeight(2);
line(i*width/suhu.length, //Koordinat x1
map(suhu[i], 29,31,0,height), //Koordinat y1
(i+1)*width/suhu.length, //Koordinat x2
map(suhu[i+1], 29,31,0,height)); //Koordinat y2
}
}
[ 67 ]
Yang pertama agar grafik garis yang dibuat lebih jelas, kita bisa menambahkan titik di setiap
titik pembentuk garis. Kita bisa memberikan titik dengan fungsi point(x,y) di p5.js. Untuk
menambahkan titik, kita perlu memasukkan di
perulangan yang telah kita buat. Koordinat x dan y
sama dengan x1 dan y1 dari garis yang dibentuk.
Setelah itu untuk implementasinya kita buat
perulangan terpisah:
…
for(let i=0; i < suhu.length; i++){
strokeWeight(8);
point(i*width/suhu.length +
0.5*(width/suhu.length),
map(suhu[i], 29,31,0,height));
…
Agar data yang divisualisasi bisa lebih terlihat lebih lenggang, kita bisa melebarkan ukuran
jendela. Karena proses visualisasi data kita sudah menggunakan lebar jendela aplikasi
sebagai parameter, maka kita bisa langsung mengubah langsung lebarnya. Misalkan dari
300 menjadi 600, maka hasilnya menjadi sebagai berikut:
Setelah itu kita juga bisa menambahkan informasi teks dari data suhu yang sudah kita miliki.
Kita tampilkan di atas titik-titik garis yang sudah kita buat sebelumnya. Untuk
menambahkan informasi teks, kita gunakan fungsi text() di p5.js.
Kita bisa menyisipkan kode program untuk menambahkan teks di perulangan untuk titik
sebelumnya. Untuk teks kita setel alignment dengan textAlign(CENTER,CENTER) agar
posisi teks di tampilkan di tengah koordinat acuan teks; yaitu dengan x dan y seperti pada
koordinat titik. Maka kode program yang kita tambahkan:
for(let i=0; i < suhu.length; i++){
…
textAlign(CENTER,CENTER);
textSize(15);
fill(0);
strokeWeight(1);
text(suhu[i], i*width/suhu.length+0.5*(width/suhu.length),
map(suhu[i], 29,31,0,height));
…
[ 68 ]
Dengan hasilnya adalah sebagai berikut:
Bisa dilihat bahwa kita berhasil menambahkan teks, namun posisi dan penayangannya
terbalik. Ini disebabkan kode program yang digunakan di awal untuk membalik arah
visualisasi data, yaitu translate(0,height) dan scale(1,-1).
Untuk membaliknya kita bisa melakukan kembali transformasi geometri untuk membalik
arah dari teks dengan memindahkan (0,0) ke koordinat teks dan melakukan transformasi
refleksi balik terhadap sumbu x. Implementasinya:
…
for(let i=0; i < suhu.length; i++){
…
push ();
translate((i*width/suhu.length)+0.5*(width/suhu.length),
map(suhu[i],29,31,0,height));
scale(1,-1);
textAlign(CENTER,CENTER);
textSize(15);
fill(0);
text(suhu[i],0,0);
pop ();
…
Hasil dari penambahan di atas akan membuat teks menjadi berbalik seperti semula. Namun
posisi dari teks masih di tengah-tengah titik sehingga bertumpuk dan sulit untuk dilihat.
Kita bisa menggesernya dengan memodifikasi koordinat y dari fungsi text(); yaitu dengan
mengurangi sejumlah sekian. Karena ukuran teks disetel 15, maka kita kurangi koordinat
sebesar 20:
text(suhu[i],0,-20);
[ 69 ]
Untuk membuat teks hanya menampilkan dua angka di belakang koma, kita bisa
menggunakan fungsi nf() (https://p5js.org/reference/#/p5/nf) untuk menentukan format
String yang ditampilkan –termasuk oleh fungsi text(). Kita ubah menjadi sebagai berikut:
text(nf(suhu[i],0,2),0,-20);
Hasil kode program tersebut akan menempatkan kotak di atas garis, di bawah teks sehingga
bisa lebih mudah dibaca. Tapi kita bisa mengubah sedikit koordinat y dari kotak jika dirasa
posisi vertikal terlalu naik terhadap teks. Misal kita geser menjadi -18 menjadi rect(0,-
18,50,20). Maka hasilnya akan menjadi seperti berikut:
[ 70 ]
Dengan demikian grafik garis yang kita buat sudah menampilkan informasi yang diperlukan.
Kita juga bisa tampakkan lagi grafik batang sehingga hasil akhir menjadi sebagai berikut:
[ 71 ]
TUGAS PRAKTIKUM MODUL 4 – VISUALISASI DATA
Buatlah visualisasi data dengan cara seperti yang telah dijelaskan sebelumnya:
1. Grafik Batang
2. Grafik Garis – dengan titik dan kotak berisi teks
Ketentuan dari aplikasi yang dibuat:
a) Jendela aplikasi berukuran 1200 x 600
b) Warna dari grafik batang gunakan pemetaan terhadap warna R dan G
c) Contoh hasil luaran aplikasi:
[ 72 ]