φυβλαςのβλογ
บล็อกของ 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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文