ในการแสดงผลข้อมูลลงบนหน้ากระดาษซึ่งมีเพียงสองมิตินั้น การที่จะแสดงอะไรต่างๆออกไปพร้อมๆกันนั้นก็เป็นความท้าทายอย่างหนึ่ง
ในบทที่ผ่านๆมาได้พูดถึงการใช้สีเพื่อแทนมิติที่สาม แต่ว่านอกจากนั้นแล้วหากแทนที่เราจะแค่ลงพื้นเป็นสีแต่ใช้ตัวเลขวางลงไปแทน ค่าตัวเลขนั้นก็จะบอกค่าของข้อมูลอะไรบางอย่างได้อีก แบบนั้นก็กลายเป็นสี่มิติ
แต่ตัวเลขอาจจะไม่เห็นภาพชัด เราจึงอาจเปลี่ยนเป็นอะไรที่ดูง่ายกว่านั้น รูปแบบหนึ่งที่นิยมใช้ก็คือใช้ลูกศรมาวาง แล้วให้ความยาวของลูกศรเป็นตัวบอกขนาดปริมาณที่ต้องการ
แต่ว่าลูกศรที่วางอยู่บนพื้นสองมิตินั้นค่าขนาดของมันก็เป็นสองมิติ คือมีค่าขนาดในแกน 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()
อ้างอิง