ทำไมโปรแกรมเมอร์ถึงต้องปวดหัวกับเรื่องช่องว่าง (Dead Space)
เวลาเราเขียนโปรแกรมเพื่อวาดภาพหรือกราฟิก เรามักจะตั้งค่าขนาดพื้นที่ไว้ล่วงหน้าเพื่อให้ทุกอย่างออกมาดูดีเหมือนกันหมด แต่บ่อยครั้งที่ผลลัพธ์กลับไม่เป็นไปตามที่เราสั่ง ทั้งที่เช็กค่า Config (การตั้งค่าโปรแกรม) แล้วว่าถูกต้องทุกอย่าง ปัญหานี้สร้างความน่ารำคาญให้กับนักพัฒนาซอฟต์แวร์มือใหม่และมือเก๋ามานักต่อนัก
สมมติว่าคุณกำลังวาดแผนที่ลงบนเฟรมวิดีโอ 15 ตอน คุณตั้งค่าความกว้างและความสูงไว้ชัดเจนเพื่อให้มันพอดีกับหน้าจอโทรศัพท์ แต่พอรันโค้ดออกมาจริง พื้นที่ด้านข้างกลับมีช่องว่างโหว่ขึ้นมาดื้อๆ ทั้งที่ในโค้ดระบุขนาดไว้เป๊ะๆ ปรากฏการณ์นี้เราเรียกว่า Ghost Layout (การจัดวางที่ผิดพลาดโดยไม่รู้สาเหตุ) ซึ่งมักเกิดจากคำสั่งที่เราเรียกใช้ไปแอบแก้ไขค่าที่เราตั้งไว้เอง
การเข้าใจเรื่องนี้สำคัญมากสำหรับคนที่กำลังหัดเขียนโค้ด เพราะมันสอนให้เราอย่าเชื่อใจแค่ค่าที่เราตั้งไว้ในไฟล์คอนฟิกเพียงอย่างเดียว แต่ต้องมองลึกลงไปถึงวิธีการทำงานของ Library (ชุดคำสั่งที่คนอื่นเขียนไว้ให้เราเรียกใช้) ที่เราเลือกมาใช้ด้วย การไล่หาบั๊ก (ข้อผิดพลาดของโปรแกรม) แบบนี้จะทำให้คุณเก่งขึ้นอย่างรวดเร็ว
เมื่อการตั้งค่าไม่ได้ผลอย่างที่คิด
ผมเจอปัญหานี้ตอนทำโปรเจกต์วาดแผนที่ด้วย Matplotlib (เครื่องมือวาดกราฟยอดนิยมในภาษา Python) โดยผมตั้งใจจะให้แผนที่กินพื้นที่ตามสัดส่วนที่คำนวณไว้ แต่พอวาดแผนที่ของประเทศโปแลนด์ออกมา พื้นที่กลับน้อยกว่าที่ควรจะเป็นถึง 4 เท่า ทั้งที่ใช้การตั้งค่าเดียวกับประเทศอื่นๆ
ผมลองไล่ตัวเลขดูพบว่าค่าความกว้างนั้นถูกต้องตามที่คาดการณ์ไว้ แต่ค่าความสูงกลับผิดพลาดอย่างรุนแรง การที่ความสูงผิดไปมากขนาดนี้บอกผมว่ามันต้องมีอะไรบางอย่างมาบังคับให้กราฟวาดตัวมันเองใหม่ โดยไม่สนใจกฎที่เราวางไว้ตั้งแต่ต้น นี่คือสัญญาณเตือนว่ามีคำสั่งบางอย่างกำลัง แอบเปลี่ยนการตั้งค่า ของเราอยู่เบื้องหลัง
สำหรับมือใหม่ เมื่อเจอเหตุการณ์ที่ "เลขไม่ตรงกับที่สั่ง" อย่าเพิ่งรีบแก้โค้ดที่ไฟล์คอนฟิก เพราะบ่อยครั้งที่ค่าที่เราสั่งไว้มันถูกต้องอยู่แล้ว แต่ตัวคำสั่งที่ใช้แสดงผลต่างหากที่เข้าไปปรับเปลี่ยนขนาดเองโดยอัตโนมัติ การสังเกตความผิดปกติของตัวเลขคือทักษะสำคัญที่โปรแกรมเมอร์ต้องมี
ทำความรู้จักกับตัวการร้ายที่ชื่อ imshow
ในภาษา Python เมื่อเราใช้ ax.imshow() (คำสั่งสำหรับแสดงภาพลงบนแกนกราฟ) เพื่อแสดงภาพถ่ายดาวเทียมหรือแผนที่ลงไป หลายคนไม่รู้ว่ามันไม่ได้แค่ "แปะรูป" ลงไปเฉยๆ แต่มันพยายามรักษาสัดส่วนของรูปภาพต้นฉบับเอาไว้ด้วย Aspect Ratio (สัดส่วนความกว้างต่อความสูง) คือสิ่งที่มันพยายามรักษาไว้เสมอ
ลองนึกภาพว่าคุณมีกรอบรูปสี่เหลี่ยมผืนผ้า แต่คุณพยายามยัดรูปสี่เหลี่ยมจัตุรัสลงไป ถ้าคุณไม่สั่งให้มันยืดขยายตามกรอบ โปรแกรมก็จะปรับขนาดพื้นที่วาดให้กลายเป็นสี่เหลี่ยมจัตุรัสตามรูปภาพนั้นทันที นั่นคือสาเหตุที่ทำให้พื้นที่ด้านบนหรือด้านล่างกลายเป็นช่องว่าง เพราะตัวฟังก์ชันมันเปลี่ยนขนาดแกนกราฟไปแล้ว
ปัญหานี้เป็นสิ่งที่มือใหม่มักพลาด เพราะเรามักจะมองว่า imshow เป็นแค่ตัวแสดงภาพ แต่จริงๆ แล้วมันคือตัวกำหนดรูปร่างของแกนกราฟด้วย หากคุณต้องการให้ภาพเต็มพื้นที่ตามที่คุณกำหนด คุณต้องรู้วิธีสั่งให้มันเลิกยุ่งกับสัดส่วนอัตโนมัติเสียก่อน
import matplotlib.pyplot as plt
# สร้างพื้นที่ขนาด 10x5 โดยไม่ได้ตั้งค่าสัดส่วน
fig, ax = plt.subplots(figsize=(10, 5))
# แสดงภาพแบบปกติที่ imshow จะปรับขนาดแกนเอง
ax.imshow(data)
plt.show()
ในโค้ดนี้ plt.subplots คือการสร้างพื้นที่วาดภาพขึ้นมา แต่เมื่อเราใส่ ax.imshow(data) ลงไปโดยไม่มีการตั้งค่าเพิ่มเติม ตัว Matplotlib จะมองว่าข้อมูลรูปภาพสำคัญที่สุดและจะปรับขนาดแกนกราฟให้เท่ากับสัดส่วนของรูปภาพทันที ผลลัพธ์ที่ได้คือช่องว่างสีขาวเหลืออยู่บนพื้นที่ที่ควรจะเต็ม ซึ่งเป็นผลมาจากฟังก์ชัน imshow ที่พยายามรักษาความสมดุลของภาพนั่นเอง
วิธีแก้ปัญหาด้วยการคุมสัดส่วน
วิธีแก้ปัญหาที่ตรงจุดที่สุดคือการบอกให้ imshow เลิกยุ่งกับสัดส่วนของแกนกราฟ โดยการเพิ่มอาร์กิวเมนต์ (ข้อมูลที่ส่งเข้าไปในฟังก์ชัน) ที่ชื่อว่า aspect เข้าไปในคำสั่ง imshow เพื่อบังคับให้มันยืดขยายตามกรอบที่เราเตรียมไว้ได้เลย
การตั้งค่า aspect='auto' คือกุญแจสำคัญ มันเป็นการบอกโปรแกรมว่า "ไม่ต้องรักษาความสมดุลของรูปภาพนะ ให้ยืดรูปให้เต็มขนาดพื้นที่ที่ฉันตั้งไว้ได้เลย" ซึ่งจะทำให้ช่องว่างที่เคยเหลือหายไปและภาพจะแสดงผลได้ตามความกว้างและความสูงที่คุณออกแบบไว้
นี่คือตัวอย่างการแก้ไขที่ถูกต้องครับ:
# แก้ไขโดยการระบุ aspect='auto'
ax.imshow(data, aspect='auto')
เมื่อเราเพิ่ม aspect='auto' เข้าไปในคำสั่ง imshow ตัวโปรแกรมจะหยุดการคำนวณสัดส่วนอัตโนมัติและยอมให้รูปภาพยืดขยายไปจนเต็มพื้นที่ที่กำหนดไว้ใน figsize ทันที ผลลัพธ์ที่ได้คือภาพจะเต็มกรอบตามความคาดหมาย และช่องว่างที่เคยเป็นปัญหาจะหมดไปโดยสิ้นเชิง
บทเรียนจากการแก้บั๊กที่ไม่มีใครบอก
เหตุการณ์นี้สอนเราว่า Documentation (เอกสารอธิบายการใช้งาน) ของเครื่องมือที่เราใช้นั้นสำคัญมาก แต่บางครั้งมันก็ไม่ได้บอกทุกอย่างที่เกิดขึ้นเบื้องหลัง การที่เราอ่านโค้ดแล้วพบว่าค่าที่เราตั้งไว้ถูกต้อง แต่ผลลัพธ์กลับผิด ให้สันนิษฐานได้เลยว่ามีฟังก์ชันตัวใดตัวหนึ่งในกระบวนการทำงานที่มีการตั้งค่าเริ่มต้น (Default value) แอบทำงานอยู่
สำหรับคนที่กำลังก้าวเข้าสู่เส้นทางโปรแกรมเมอร์ การเจอเรื่องแบบนี้ถือเป็นเรื่องดี เพราะมันคือโอกาสในการเรียนรู้การทำ Debugging (กระบวนการไล่หาและแก้ไขข้อผิดพลาด) ในระดับที่ลึกขึ้น คุณจะไม่ใช่แค่คนที่เขียนโค้ดตามตัวอย่าง แต่จะเป็นคนที่เข้าใจว่า "ทำไม" โค้ดถึงทำงานแบบนั้น
จำไว้ว่าโปรแกรมเมอร์ที่เก่งไม่ได้วัดกันที่เขียนโค้ดเร็ว แต่คือคนที่รู้วิธีหาต้นตอของปัญหาเมื่อสิ่งที่คาดหวังไม่เกิดขึ้น การตั้งคำถามว่า "ทำไมมันถึงทำแบบนั้น" คือทักษะที่สำคัญที่สุดในการทำงานร่วมกับซอฟต์แวร์ที่ซับซ้อนในอนาคต
สรุป: การนำไปใช้จริง
สรุปสั้นๆ คือ เมื่อใดก็ตามที่คุณใช้คำสั่งวาดภาพหรือแสดงผลกราฟิกแล้วได้ผลลัพธ์ที่ไม่เต็มพื้นที่ หรือมีช่องว่างแปลกๆ โผล่มา ให้สงสัยไว้ก่อนว่าตัวฟังก์ชันนั้นกำลังพยายามจัดการสัดส่วนให้คุณเองอยู่ ให้รีบไปดูในคู่มือการใช้งานว่ามีพารามิเตอร์เกี่ยวกับ aspect หรือ scaling (การย่อขยาย) หรือไม่
ลองเอาไปใช้กับโปรเจกต์ของคุณดูครับ ถ้าคุณกำลังทำ Dashboard (หน้าจอแสดงผลข้อมูล) ด้วย Library อย่าง Plotly หรือ Seaborn แล้วเจอปัญหาในลักษณะเดียวกัน การหาคำสั่งที่ควบคุมการยืดขยายของกราฟจะเป็นวิธีแก้ปัญหาที่คุณจะเจอบ่อยที่สุดในการทำงานจริง
การตั้งค่าให้ชัดเจนในทุกบรรทัด จะช่วยลดความสับสนและทำให้โปรแกรมของคุณทำงานได้แม่นยำขึ้นเสมอ อย่าปล่อยให้ค่าเริ่มต้นของโปรแกรมมาตัดสินใจแทนคุณในส่วนที่สำคัญต่อการออกแบบหน้าตาโปรแกรมครับ
ที่มา: The Dead Space Wasn't a Config Miss — imshow Was Silently Reshaping the Axes — DEV Community