φυβλαςのβλογ
บล็อกของ phyblas



numpy & matplotlib เบื้องต้น บทที่ ๖: ทำความเข้าใจกับส่วนประกอบของกราฟ
เขียนเมื่อ 2016/06/11 13:09
แก้ไขล่าสุด 2021/09/28 16:42
ในบทที่แล้วได้พูดถึงการเขียนกราฟเบื้องต้นและการแต่งตัวกราฟไปแล้ว แต่ยังไม่ได้พูดถึงปรับแต่งส่วนประกอบต่างๆของกราฟ

การจะปรับแต่งอะไรเพิ่มเติมได้มากขึ้นจำเป็นจะต้องเข้าใจภาพรวมของโครงสร้างส่วนประกอบต่างๆที่ประกอบเป็นฉากสำหรับวาดกราฟก่อน

เนื่องจาก ส่วนประกอบต่างๆมีลักษณะเป็นออบเจ็กต์ ดังนั้นควรจะเข้าใจเรื่องการเขียนโปรแกรมเชิงวัตถุในระดับนึง ไม่เช่นนั้นอาจไม่สามารถเข้าใจกลไกการทำงานของมันได้ดีพอและสามารถใช้งานได้ แค่ผิวเผิน



ส่วนประกอบของกราฟ
ภาพที่เราได้ออกมาเมื่อวาดกราฟนั้นถูกเขียนอยู่บนฉากวาดภาพที่เรียกว่า figure

และบนฉากวาดภาพก็จะมีส่วนแกนวางกราฟ เรียกว่า axes

คำว่า axes เป็นพหูพจน์ของ axis ที่แปลว่าแกน กราฟนึงประกอบขึ้นจากแกนสองแกน ดังนั้นจึงใช้รูปพหูพจน์ อาจจะแปลว่าชุดแกนหรือกลุ่มแกนก็ได้

(ภาษาอังกฤษยุ่งยากตรงที่ต้องพะวงว่าเอกพจน์หรือพหูพจน์ แถมบางคำไม่ไช่แค่เติม s เฉยๆเต็มไปด้วยข้อยกเว้นมากมาย)

ใน figure นึงจะมีกี่ axes ก็ได้ การใส่หลาย axes ลงใน figure นึงจะใช้ฟังก์ชัน subplot ซึ่งจะยังไม่พูดถึงในบทนี้

และกราฟจะถูกวาดลงบนใน axes โดยใน axes นึงอาจวาดหลายกราฟได้ ดังที่ได้แสดงไปในบทที่แล้ว

ยกตัวอย่าง วาดภาพที่มีเส้นกราฟ ๒ เส้นใน axes เดียวกัน
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y1 = np.sin(x)*np.exp(-x/100)+1
y2 = np.sin(x)*np.exp((100-x)/100)-1
plt.plot(x,y1,'g')
plt.plot(x,y2,'m')
plt.show()

เราจะได้เส้นกราฟแบบนี้ออกมา



ตัวภาพทั้งหมดก็คือ figure ส่วนพื้นขาวๆและเส้นแกนสีดำคือส่วนของ axes และเส้นกราฟที่เห็นทั้ง ๒ สีนี้คือส่วนของเส้นกราฟที่วาดลงบน axes

อาจเขียนภาพร่างคร่าวๆได้เป็นแบบนี้



ความจริงแล้วการที่เริ่มต้นมาถึงเราสามารถใช้คำสั่ง plot ได้ทันทีเพราะตัวโปรแกรมนั้นจะทำการตั้ง figure กับ axes ให้อัตโนมัติ

การเขียนย่อแบบนี้มีข้อเสียคือหากเราไม่ได้กดปิดภาพเดิมก่อนที่จะรันใหม่มันก็จะวาดทับกราฟเดิมไป

หากเขียนเต็มๆโดยเริ่มตั้งแต่ตั้ง figure และตั้ง axes จะเขียนแบบนี้ (ขอละตรงส่วน import และนิยามค่า x, y1, y2 ออก)
fig1 = plt.figure()
ax1 = fig1.gca()
ax1.plot(x,y1,'g')
ax1.plot(x,y2,'m')
plt.show()

จะเห็นว่าเพิ่มมาอีก ๒ บรรทัด ภาพที่ได้จะเหมือนเดิม เพียงแต่ว่าจะมีความต่างตรงที่ว่าหากใช้แบบนี้หากเรารันซ้ำโดยที่ยังไม่ได้ ปิดภาพเดิมทิ้งจะมีการเปิดแถบใหม่ขึ้นมาแล้ววาดใหม่ ไม่ได้เขียนทับภาพเดิม

ในที่นี้ fig1 = plt.figure() คือการสร้างออบเจ็กต์ figure ขึ้นมาแล้วเก็บไว้ในตัวแปรชื่อ fig1

และ ax1 = fig1.gca() คือการสร้างออบเจ็กต์ axes ขึ้นมาภายใน fig1 แล้วเก็บไว้ในตัวแปรชื่อ ax1

gca ย่อมาจาก get current axes หมายถึงเอาแกนปัจจุบัน ที่จริงแล้วฟังก์ชันนี้มีไว้เพื่อปรับตั้งค่าต่างๆใน axes ที่ใช้งานอยู่ปัจจุบัน แต่กรณีที่ figure ที่เราเลือกอยู่ยังไม่มี axes จะเป็นการสร้างขึ้นมาใหม่ หากจะปรับตั้งค่าอะไรต่างๆของ axes ก็จะมาปรับในฟังก์ชันนี้ แต่ตอนนี้เราจะยังไม่ปรับแต่จะสร้างขึ้นมาเฉยๆก่อน การปรับอะไรต่างๆจะพูดถึงในบทถัดไป

จะเห็นว่า gca ตามหลัง fig1 ไม่ใช่ plt นั่นหมายความว่ามันเป็นเมธอดที่กระทำต่อออบเจ็กต์ fig1 โดยตรง

แต่ที่จริงแล้วเราสามารถเขียนแบบนี้ได้เช่นกัน
plt.figure()
ax1 = plt.gca()
ax1.plot(x,y1,'g')
ax1.plot(x,y2,'m')
plt.show()

ในที่นี้ ๒ บรรทัดแรกเปลี่ยนไป โดย plt.figure() ไม่ต้องใช้ตัวแปรอะไรมารองรับ ส่วน fig1.gca() เปลี่ยนเป็น plt.gca()

การเขียน fig1.gca กับ plt.gca นั้นจะมีความหมายต่างกันเล็กน้อย โดย fig1.gca เป็นเมธอดที่กระทำต่อออบเจ็กต์ fig1 โดยตรง โดยจะเพิ่ม axes ลงใน figure นี้

ส่วน plt.gca นั้นเป็นการใช้ในรูปแบบฟังก์ชัน โดยไม่ได้ระบุชัดว่าจะกระทำต่อออบเจ็กต์ไหน จึงเป็นการสร้าง axes ให้กับ figure ที่เลือกอยู่ปัจจุบัน ซึ่งก็คือ figure ที่เพิ่งสร้างขึ้นมา

ลองเปลี่ยนโค้ดเป็นแบบนี้ดู (ยังไม่ต้องใส่ ax1.plot)
plt.figure()
plt.figure()
ax1 = plt.gca()
plt.show()

ในนี้มีการใช้ plt.figure() ๒ ครั้ง ผลที่ได้คือจะเห็นว่ามีภาพโผล่ขึ้นมา ๒ ภาพ โดยวางซ้อนกันอยู่ อันที่อยู่ด้านหน้าคืออันที่สร้างขึ้นทีหลัง (อาจต้องเลื่อนอันด้านหน้าออกจึงจะเห็นอันด้านหลัง)



จะเห็นว่าอันที่อยู่ด้านหน้ามีพื้นสีขาวพร้อมแกนอยู่ ในขณะที่อันข้างหลังว่างเปล่า เพราะอันด้านหน้า ถูกเติม axes ลงไปนั่นเอง

ลองเปลี่ยนโค้ดเป็น
fig1 = plt.figure()
fig2 = plt.figure()
ax1 = fig1.gca()
plt.show()

ผลที่ได้จะกลับกัน คืออันหลังมีฉากสีขาวอยู่



นั่นเพราะคราวนี้พิมพ์เป็น fig1.gca แทนที่จะเป็น plt.gca นั่นคือเราระบุชัดว่าจะให้สร้าง axes ที่ fig1 ไม่ใช่ fig2 ดังนั้นแม้ว่าเราจะสร้าง fig2 ขึ้นมาทีหลัง axis ก็จะยังถูกเพิ่มให้ fig1 อยู่ดี

ตรงนี้น่าจะพอทำให้เห็นภาพชัดขึ้นมาบ้างไม่มากก็น้อย



กลับมาดูที่โค้ดเดิมซึ่งเขียนไว้ข้างต้น
fig1 = plt.figure()
ax1 = fig1.gca()
ax1.plot(x,y1,'g')
ax1.plot(x,y2,'m')
plt.show()

พิจารณาส่วนถัดมา คือ ax1.plot(x,y1) นี่คือการสร้างออบเจ็กต์เส้นกราฟขึ้นภายใน ax1

จะเห็นว่า plot ในที่นี้ไม่ได้ตามหลัง plt แต่ตามหลัง ax1 แทน หมายความว่า plot ในที่นี้เป็นเมธอดที่กระทำต่อออบเจ็กต์ ax1 โดยตรง

ซึ่งที่จริงแล้วเราสามารถเขียนเป็น plt.plot แบบนี้ได้เช่นกัน
fig1 = plt.figure()
ax1 = fig1.gca()
plt.plot(x,y1,'g')
plt.plot(x,y2,'m')
plt.show()

กรณีที่เขียน plt.plot แบบนี้จะเป็นการวาดกราฟที่ตัว axes ที่ถูกใช้อยู่ในปัจจุบัน ซึ่งก็คือ axes ที่เพิ่งสร้างขึ้นมาหรือถูกใช้งานล่าสุด

หลักการเช่นเดียวกับ plt.gca คือสามารถเลือกทำแบบระบุตัวออบเจ็กต์ก็ได้ หรือจะไม่ระบุก็ได้ซึ่งจะเป็นการเลือกตัวที่ใช้งานอยู่ล่าสุด

สรุปขั้นตอนก็คือ
สร้าง figure ชื่อ fig1 > สร้าง axes ชื่อ ax1 บน fig1 > วาดกราฟที่ 1 ลงบน ax1 > วาดกราฟที่ 2 ลงบน ax1

หากลองแก้เป็น
fig1 = plt.figure()
ax1 = fig1.gca()
fig2 = plt.figure()
ax2 = fig2.gca()
ax1.plot(x,y1,'g')
ax2.plot(x,y2,'m')
plt.show()

ผลที่ได้คือคราวนี้จะออกมาเป็น ๒ กราฟแยกกัน (อย่าลืมว่าอาจซ้อนกันอยู่)



หากวาดภาพร่างก็จะได้แบบนี้



ซึ่งทั้งหมดนี้อาจสามารถเขียนใหม่โดยไม่ใช่การเขียนเชิงวัตถุได้เลยเช่นกัน
plt.figure()
plt.gca()
plt.plot(x,y1,'g')
plt.figure()
plt.gca()
plt.plot(x,y2,'m')
plt.show()

อาจดูเข้าใจง่ายกว่า คือวาดไปทีละภาพเลย แต่ข้อเสียของการเขียนแบบนี้คือทุกอย่างต้องทำตามลำดับขั้น คือจัดการทุกอย่างในภาพแรกให้เสร็จ แล้วจึงมาทำอะไรในภาพหลัง จะทำย้อนไปย้อนมาไม่ได้

เรายังอาจเขียนย่อให้เหลือแค่นี้ได้อีกด้วย
plt.plot(x,y1,'g')
plt.figure()
plt.plot(x,y2,'m')
plt.show()

ด้านบนสุดไม่ต้องขึ้นต้นด้วย plt.figure และ plt.gca ก่อนเพราะถ้าหากเริ่มต้นมาถึงก็สั่ง plot ทันทีเลย ทั้ง figure และ axes จะถูกสร้างขึ้นมาอัตโนมัติ

แต่พอจะเปลี่ยนมาเขียนภาพใหม่จะต้อง plt.figure() ใหม่ก่อน ไม่เช่นนั้นจะเป็นการเขียนทับภาพเดิม และในส่วนนี้ plt.gca ก็ละได้อีกเช่นกันเพราะ axes จะถูกสร้างอัตโนมัติเวลาที่สั่ง plot



การเซฟภาพด้วย plt.savefig นั้นที่จริงแล้วก็เป็นการเซฟภาพ figure ที่เรากำลังเลือกอยู่ล่าสุด

แต่สามารถเปลี่ยนเป็นเซฟภาพใดๆได้โดยการเขียนในรูปเมธอดที่กระทำต่อตัว figure ที่ต้องการ เช่น fig1.savefig
fig1 = plt.figure()
plt.plot(x,y1,'g')
fig2 = plt.figure()
plt.plot(x,y2,'m')
fig1.savefig('fig1.png')
fig2.savefig('fig2.png')

แบบนี้ก็จะได้ไฟล์ ๒ ไฟล์ที่มีกราฟคนละอัน



นอกจากนี้ plt.figure() และ plt.gca() ยังสามารถใส่อาร์กิวเมนต์เพื่อกำหนดคุณสมบัติต่างๆของ figure และ axes ที่จะสร้างขึ้นมาใหม่ได้ด้วย

สรุปโดยรวมแนวทางต่อจากนี้ ว่าการใช้ฟังก์ชัน plt.figure() และ plt.gca() ควรจะใช้เมื่อไหรนั้น ก็ขึ้นอยู่กับว่าต้องการจะแต่งเติมอะไรในส่วนของ figure และ axis หรือเปล่า

และควรจะเอาตัวแปรมาเก็บค่าไว้ด้วยหรือเปล่าก็ขึ้นอยู่กับว่าจะมีการเรียกใช้ภายหลังตอนหลังจากที่ไปทำอะไรกับภาพอื่นอีกหรือเปล่า



อ้างอิง



<< บทที่แล้ว     บทถัดไป >>
หน้าสารบัญ


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> matplotlib

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

ไทย

日本語

中文