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



numpy & matplotlib เบื้องต้น บทที่ ๒๙: สนามลูกศร
เขียนเมื่อ 2016/06/12 11:55
แก้ไขล่าสุด 2022/07/21 20:34
ในการแสดงผลข้อมูลลงบนหน้ากระดาษซึ่งมีเพียงสองมิตินั้น การที่จะแสดงอะไรต่างๆออกไปพร้อมๆกันนั้นก็เป็นความท้าทายอย่างหนึ่ง

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

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

แต่ว่าลูกศรที่วางอยู่บนพื้นสองมิตินั้นค่าขนาดของมันก็เป็นสองมิติ คือมีค่าขนาดในแกน x และ y ดังนั้นแค่วางลูกศรลงไปก็สามารถบอกข้อมูลได้สองค่าในเวลาเดียวกัน

ลูกศรอันหนึ่งมีข้อมูลทั้งตำแหน่งแกน x แกน y และขนาดในแกน x แกน y จึงรวมเป็น ๔ ค่า

นอกจากนี้ถ้าเราระบายสีลงบนลูกศรด้วยสีนั้นก็จะสามารถให้ข้อมูลอะไรได้เพิ่มอีก จึงรวมเป็น ๕ ค่า

ใน matplotlib มีฟังก์ชันสำหรับวาดลูกศรหลายๆรูปกระจายลงบนแผนภาพตามตำแหน่งที่ต้องการ นั่นคือ plt.quiver

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

ค่อยๆเริ่มทำความเข้าใจไปทีละขั้น ดังที่ได้กล่าวไปแล้วว่าลูกศรในสองมิตินั้นเป็นสิ่งที่อาจมีทั้งตำแหน่ง ซึ่งทั้งสองอย่างนี้ก็แยกเป็นแกน x และ y

ค่าทั้ง ๔ นี้คือสิ่งที่ต้องใส่ลงเป็นอาร์กิวเมนต์ ๔ ตัวแรกในฟังก์ชัน plt.quiver
plt.quiver(x,y,u,v)

โดย
x คือตำแหน่งในแกน x
y คือตำแหน่งในแกน y
u คือขนาดในแกน x
v คือขนาดในแกน y

โดยที่ค่าหนึ่งค่าจะแทนลูกศรหนึ่งอัน แต่เมื่อใส่เป็นลิสต์หรืออาเรย์ก็จะเป็นการใส่ลูกศรลงไปหลายอัน

ลองดูตัวอย่างอย่างง่ายกันดูเลย
import matplotlib.pyplot as plt
x = [1,3,5]
y = [2,3,2]
u = [2,2,1]
v = [1,-1,4]
plt.axes(xlim=[0,7],ylim=[0,7])
plt.quiver(x,y,u,v)
plt.show()



ในตัวอย่างนี้เราเริ่มจากลองสร้างลิสต์ที่เก็บค่าตำแหน่งในแนวแนก x และ y ของลูกศร ๓ อัน เก็บไว้ในตัวแปร x และ y จากนั้นก็สร้างลิสต์เก็บขนาดของลูกศรเก็บไว้ในตัวแปร u และ v

จากนั้นก็ใช้ค่า x,y,u,v นี้มาเป็นอาร์กิวเมนต์ใส่ใน plt.quiver

ผลลัพธ์ที่ได้ก็จะออกมาแบบนี้

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

ความจริงแล้วปัญหาอยู่ตรงที่ว่าหน่วยของขนาดลูกศรในฟังก์ชันนี้นั้นค่าตั้งต้น ไม่ได้ตั้งให้เป็นขนาดตามพิกัดค่า x y ในกราฟ แต่กลับเป็นหน่วยตามขนาดภาพ

เราสามารถทำให้หน่วยกลายเป็นหน่วยตามค่า x y ได้โดยเติมคีย์เวิร์ดเพิ่มลงไป

ลองแก้ตรงส่วน plt.quiver ให้เป็นตามนี้
plt.quiver(x,y,u,v,angles='xy',scale_units='xy',scale=1)



เท่านี้ก็จะได้ลูกศรที่มีขนาดตามค่าที่ต้องการแล้ว

ในที่นี้ angles และ scale_units นั้นเป็นคีย์เวิร์ดที่กำหนดรูปแบบการปรับมุมและหน่วยที่ใช้ปรับมาตราส่วน

ที่ใส่ค่าเป็น ='xy' หมายถึงปรับให้เข้ากับแกน xy

ส่วน scale นั้นค่ามาตราส่วน ซึ่งหลังจากที่เราปรับ angles และ scale_units ให้เป็น xy แล้วค่า scale จะเป็นตัวกำหนดว่าลูกศรจะมีขนาดคูณไปจากค่าขนาดตามแกน x y ที่เราป้อนกี่เท่า ในที่นี้เราต้องการให้มีขนาดตามนั้นเลยก็ใส่เป็น 1

หากไม่ใส่ค่า scale ลงไปลูกศรจะถูกปรับขนาดตามความเหมาะสมโดยอัตโนมัติ



สีของลูกศรเป็นอีกสิ่งหนึ่งที่สามารถกำหนดลงไปให้กับลูกศรแต่ละอันได้ โดยให้ใส่ในคีย์เวิร์ด color
x = [1,3,5,5]
y = [2,3,2,6]
u = [2,2,1,-2]
v = [1,-1,4,-2]
c = ['r','g','b','y']
plt.axes(xlim=[0,7],ylim=[0,7])
plt.quiver(x,y,u,v,color=c,angles='xy',scale_units='xy',scale=1)
plt.show()



ตำแหน่งของลูกศรนั้นจะวางโดยให้ปลายหางอยู่ที่ค่า x,y ที่ใส่ ส่วนตำแหน่งหัวลูกศรจะอยู่ที่ตำแหน่งปลายหางบวกด้วยขนาด

แต่เราสามารถเปลี่ยนให้ตำแหน่งพิกัด x,y ที่ใส่นั้นแทนหัวลูกศรหรือกลางลูกศรแทนได้โดยใส่คีย์เวิร์ด pivot

โดย pivot='mid' หรือ pivot='middle' ตำแหน่ง x,y จะเป็นกึ่งกลางลูกศร

ถ้า pivot='tip' ตำแหน่ง x,y จะเป็นหัวลูกศร

ถ้าไม่ใส่หรือใส่ pivot='tail' ตำแหน่ง x,y จะเป็นปลายลูกศร

ลองวาดสองแบบเทียบกันดู
x = [1,2,3]
y = [1,1,1]
u = [1,1,1]
v = [1,2,3]
plt.axes(xlim=[0,5],ylim=[-2,5])
plt.quiver(x,y,u,v,color='r',pivot='tail',angles='xy',scale_units='xy',scale=1)
plt.quiver(x,y,u,v,color='b',pivot='tip',angles='xy',scale_units='xy',scale=1)
plt.show()



ปกติแล้วเวลาใช้เราจะใส่ค่าอาร์กิวเมนต์ ๔ ตัว x,y,u,v แต่บางครั้งก็อาจใส่แค่ ๒ ตัวก็ได้ ซึ่งในกรณีแบบนี้ ๒ ตัวนั้นจะถูกตีความเป็น u กับ v ส่วนค่า x และ y จะถูกกำหนดให้โดยอัตโนมัติตามลำดับ
import numpy as np
import matplotlib.pyplot as plt
u = np.ones(10)
v = np.arange(10)
plt.axes(xlim=[-1,11],ylim=[-1,10])
plt.quiver(u,v,angles='xy',scale_units='xy',scale=1)
plt.show()



จะเห็นว่า x,y เริ่มที่ 0,0 แล้วก็ไล่ไปเรื่อยๆตามแนวแกน x

กรณีที่ u กับ v เป็นอาเรย์สองมิติ ก็จะถูกจัดเรียงตามแกน x และ y โดยไล่ไปทีละ 1 ในแต่ละแกน
u = np.ones([5,5])
v = np.zeros([5,5])
plt.axes(xlim=[-1,6],ylim=[-1,5])
plt.quiver(u,v,angles='xy',scale_units='xy',scale=1)
plt.show()



ลองดูตัวอย่างการใช้อีกหน่อย เช่นลองสุ่มตำแหน่งเส้นทางการเดินแล้วให้ลูกศรชี้ต่อกันไปเรื่อยๆ
u = np.random.uniform(0,100,50)
v = np.random.uniform(-100,100,50)
x = u.cumsum()
y = v.cumsum()
plt.quiver(x,y,u,v,pivot='tip',angles='xy',scale_units='xy',scale=1)
plt.show()





ต่อไปมาลองดูการประยุกต์การใช้งานที่เป็นรูปธรรมมากขึ้น

ลูกศรอาจใช้แสดงปริมาณอะไรบางอย่างในสองมิติ เช่นขนาดและทิศทางกระแสลมที่ตำแหน่งต่างๆ

ตัวอย่าง ลองให้สุ่มความแรงของลม ค่า u และ v ที่สุ่มขึ้นจะเป็นตัวกำหนดขนาดและทิศทางของลม
x,y = np.meshgrid(np.linspace(-5,5,11),np.linspace(-5,5,11))
u = np.random.randn(11,11)
v = np.random.randn(11,11)
plt.figure(figsize=[7,7])
plt.axes(aspect=1)
plt.quiver(x,y,u,v,color='c')
plt.show()



จะเห็นว่าในที่นี้ไม่ได้ใส่คีย์เวิร์ด scale=1 เพราะต้องการให้ลูกศรปรับขนาดเอาเองตามความเหมาะสม โดยทั่วไปแล้วจะปล่อยให้เป็นแบบนี้มากกว่า เพราะค่าขนาดของสิ่งที่เราต้องการแสดงมักจะไม่ได้เป็นหน่วยเดียวกับตำแหน่ง อยู่แล้ว เช่นความเร็วลมมีหน่วยเป็นเมตรต่อวินาที แต่ตำแหน่งมีหน่วยเป็นเมตร เป็นต้น ดังนั้นขนาดของลูกศรจะยาวเท่าไหร่ก็ได้ ที่สำคัญคือขนาดของลูกศรแต่ละอันต้องเป็นไปในมาตราส่วนเดียวกัน

และจำเป็นที่จะต้องมีอะไรบางอย่างที่แสดงบอกว่าลูกศรยาวเท่าไหร่เท่ากับมีค่า เป็นเท่าไหร่ เราสามารถใช้ฟังก์ชัน plt.quiver เพื่อใส่คำอธิบายของลูกศรได้

ลองสร้างภาพเดิมใหม่โดยแค่เพิ่ม quiverkey เข้าไป
x,y = np.meshgrid(np.linspace(-5,5,11),np.linspace(-5,5,11))
u = np.random.randn(11,11)
v = np.random.randn(11,11)
plt.figure(figsize=[7,7])
plt.axes(aspect=1)
qv = plt.quiver(x,y,u,v,color='c')
plt.quiverkey(qv,0.5,1.05,2,'2 m/s',color='r',labelcolor='b',labelpos='W')
plt.show()



จะได้ว่าด้านบนมีลูกศรสีแดงโผล่ขึ้นมาพร้อมเลขบอกขนาด

อาร์กิวเมนต์ที่ใช้ในฟังก์ชันนี้เรียงตามลำดับดังนี้
- ออบเจ็กต์ของกลุ่มลูกศร (ต้องเอาตัวแปรมารับตอนใช้ plt.quiver)
- ตำแหน่งในแกนนอน หน่วยเป็นสัดส่วนต่อความกว้างกรอบกราฟ (0.5 คือตรงกลาง)
- ตำแหน่งในแกนตั้ง  หน่วยเป็นสัดส่วนต่อความสูงกรอบกราฟ (ใส่เลขมากกว่า 1 เล็กน้อยคืออยู่เหนือกรอบขึ้นไป)
- ความยาวของลูกศร หน่วยเป็นหน่วยเดียวกับลูกศรที่ปรากฏในฉากทั้งหมด
- ข้อความอธิบายประกอบ

นอกจากนี้ก็มีคีย์เวิร์ด
- labelpos ตำแหน่งของข้อความเมื่อเทียบกับตำแหน่งลูกศร ค่าที่ใส่ได้คือ N S E W ซึ่งแทน บน ล่าง ขวา ซ้าย
- color สีลูกศร
- labelcolor สีตัวหนังสือ
- fontproperties รูปแบบของตัวอักษร
- coordinates กำหนดว่าค่าตำแหน่งในแนวแกนนอนและแกนตั้งที่ใส่ลงไปนี้จะอ้างอิงตามอะไร ค่าที่ใช้ได้คือ axes figure data inches ถ้าไม่ใส่จะเป็น axes คืออ้างอิงตามกรอบกราฟ

ลูกศรอาจเอาไว้ใช้ชี้ถึงความชันของค่าบางอย่างในระนาบสองมิติ ซึ่งค่านั้นอาจแสดงด้วยแผนภาพไล่สีหรือคอนทัวร์

ถ้าเราสามารถคำนวณอนุพันธ์ย่อยได้เราสามารถใช้ลูกศรเพื่อแสดงค่าความชันของค่านั้น

numpy มีความสามารถในการคำนวณค่าความชันอยู่แล้ว ซึ่งจะพูดถึงในบทหน้า ในที่นี้จะใช้ฟังก์ชันที่รู้ความชันอยู่แล้วก่อน

ตัวอย่างฟังก์ชันที่หาอนุพันธ์ง่าย เช่น z = sinx+siny

เราสามารถรู้ได้จากสูตรคำนวณอนุพันธ์ย่อยทันทีว่าความชันในแกน x เป็น cosx และความชันในแกน y เป็น cosy


ลองวาดคอนทัวร์ควบคู่ไปกับลูกศร จะเห็นได้ว่าลูกศรบ่งบอกถึงความชัน
x,y = np.meshgrid(np.linspace(-5,5,101),np.linspace(-5,5,101))
z = np.sin(x)+np.sin(y) # ค่า z ซึ่งจะใช้เป็นสีในคอนทัวร์
plt.contourf(x,y,z,12,cmap='summer')
plt.colorbar()
x,y = np.meshgrid(np.linspace(-5,5,21)[1:-1],np.linspace(-5,5,21)[1:-1])
u = np.cos(x) # ความชันของ z ในแกน x
v = np.cos(y) # ความชันของ z ในแกน y
plt.quiver(x,y,u,v,color='m',angles='xy',scale_units='xy')
plt.show()





อ้างอิง


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


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

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

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

หมวดหมู่

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

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

สารบัญ

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

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

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



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

  ค้นหาบทความ

  บทความแนะนำ

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

ไทย

日本語

中文