ในบทก่อนๆได้พูดถึงการสร้างแผนภาพไล่สีไปแล้ว อย่างไรก็ตามในแง่ของการวิเคราะห์ข้อมูลแล้ว บางทีแค่เห็นความแตกต่างของสีก็อาจจะไม่เพียงพอ เราอาจเห็นภาพได้ชัดมากขึ้นกว่าเดิมหากทำเป็นคอนทัวร์
คอนทัวร์คือแผนภาพไล่สีแบบมีลำดับขั้นชัดเจน เห็นเส้นแบ่งแต่ละขั้นเป็นส่วนๆ
ที่จริงหากใช้ BoundaryNorm ดังที่กล่าวไปใน
บทที่ ๒๖ ก็สามารถสร้างคอนทัวร์ได้ แต่ว่ามีวิธียืดหยุ่นกว่านั้น matplotlib ได้เตรียมฟังก์ชันสำหรับสร้างคอนทัวร์โดยเฉพาะไว้อยู่แล้ว
ฟังก์ชันที่ใช้สร้างคอนทัวร์มี ๒ ตัวคือ plt.contour เป็นคอนทัวร์แบบไม่ใส่พื้นสี กับ plt.contourf เป็นคอนทัวร์แบบใส่พื้นสี
คอนทัวร์แบบเส้นแบ่ง การสร้างคอนทัวร์ที่มีแต่เส้นไม่มีพื้นทำได้โดยใช้ฟังก์ชัน plt.contour โดยอาร์กิวเมนต์และคีย์เวิร์ดโดยหลักๆที่ใช้ก็จะคล้ายกับ plt.pcolor
ตัวอย่าง
import numpy as np
import matplotlib.pyplot as plt
x,y = np.meshgrid(np.linspace(-10,10,100),np.linspace(-10,10,100))
z = np.sin(x)+np.sin(y)
plt.contour(x,y,z,cmap='jet')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()
จะเห็นว่าผลที่ได้คล้ายกับแผนภาพสี เพียงแต่แทนที่จะปรากฏเป็นพื้นสีก็ปรากฏเป็นเส้นที่แบ่งเขตค่าแทน และสีของเส้นก็กำหนดโดยคัลเลอร์แม็ปที่กำหนดใน cmap
จำนวนเขตที่แบ่งสามารถทำได้โดยใส่อาร์กิวเมนต์ตัวที่สี่ต่อจากค่าสีลงไป จะได้คอนทัวร์ที่แบ่งส่วนโดยเว้นค่าห่างเท่าๆกันโดยมีเส้นแบ่งตามจำนวนนั้น เช่นลองแก้เป็น
plt.contour(x,y,z,22,cmap='jet')
จำได้ว่าแบ่งเป็น 21 ส่วนแทนที่จะเป็น 6 ส่วนซึ่งเป็นค่าตั้งต้น
ส่วนแบ่งจะใช้ลิสต์หรืออาเรย์ก็ได้ ซึ่งในกรณีนี้จะทำให้สามารถกำหนดขีดแบ่งได้ตามที่ต้องการ ไม่จำเป็นจำต้องแบ่งเท่าๆกัน
plt.contour(x,y,z,[-2,-1.9,-1.5,-1,1,1.5,1.9,2],cmap='jet')
รูปแบบของเส้นและความหนาของเส้นสามารถกำหนดได้ด้วยคีย์เวิร์ด linewidths และ linestyles
หากใส่เลขเดี่ยวจะเป็นการกำหนดรูปแบบให้กับทุกเส้นพร้อมกัน
ลอง
plt.contour(x,y,z,9,linewidths=4,linestyles='-.',cmap='jet')
หากใส่เป็นลิสต์จะเป็นการกำหนดความหนาและรูปแบบให้กับเส้นทีละเส้น
plt.contour(x,y,z,7,linewidths=[1,4,1,4,1,4,1],linestyles=['-',':','-',':','-',':','-'],cmap='jet')
สีสามารถกำหนดด้วยคีย์เวิร์ด colors แทนที่จะกำหนดด้วย cmap ได้ ทั้งสองคีย์เวิร์ดนี้จะใช้คู่กันไม่ได้
ลอง
plt.contour(x,y,z,7,colors=['m','g','y','r','c','b','#000000'])
การใส่ตัวเลขบอกค่าลงบนเส้น บางทีแค่มีแถบสีด้านข้างคอยบอกค่าก็อาจไม่ชัดพอ ถ้าใส่ค่าตัวเลขลงไปบนเส้นคอนทัวร์ได้เลยอาจทำให้เห็นภาพอะไรง่ายกว่า
การใส่ตัวเลขลงบนเส้นสามารถทำได้โดยฟังก์ชัน plt.clabel
อาร์กิวเมนต์ที่ต้องใส่ในฟังก์ชันนี้คือออบเจ็กต์แทนตัวกราฟคอนทัวร์ที่ต้องการใส่ตัวเลข ดังนั้นเราต้องเอาตัวแปรมารับค่าคืนกลับจากฟังก์ชัน plt.contour แล้วจึงใช้ตัวแปรนั้นไปใส่ในฟังก์ชัน plt.clabel
ตัวอย่าง
x,y = np.meshgrid(np.linspace(-5,5,100),np.linspace(-5,5,100))
z = np.cos(x)+np.cos(y)
pct = plt.contour(x,y,z,9,cmap='jet')
plt.clabel(pct)
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()
จะเห็นว่ามีตัวเลขบอกค่าเข้าแทรกบนเส้น ทำให้เส้นแหว่งไป
ถ้าไม่อยากให้เส้นแหว่งไปก็ทำได้โดยใส่คีย์เวิร์ด inline=0 ลองแก้เป็น
plt.clabel(pct,inline=0)
รูปแบบของตัวเลขที่แสดงสามารถปรับได้ด้วยคีย์เวิร์ด fmt และขนาดอักษรก็เปลี่ยนได้ด้วยคีย์เวิร์ด fontsize
ลอง
plt.clabel(pct,fontsize=17,fmt='%+.3f')
ตำแหน่งของตัวเลขที่ปรากฏนี้ถูกจัดวางตามความเหมาะสมให้โดยอัตโนมัติ
คอนทัวร์บนแผนภาพแจกแจงความหนาแน่น เวลาวาดแผนภาพไล่สีเพื่อแสดงการแจกแจงความหนาแน่นเราสามารถใช้ฟังก์ชัน plt.hist2d ได้ แต่ว่าสำหรับคอนทัวร์แล้วไม่มีฟังก์ชันเฉพาะสำหรับทำแบบนั้น
ดังนั้นจึงอาจต้องใช้ np.histogram2d หรืออาจใช้ค่าที่ได้จาก plt.hist2d มาวาดเป็นคอนทัวร์อีกทีก็ได้ (รายละเอียดเกี่ยวกับแผนภาพแจกแจงความหนาแน่นอ่านใน
บทที่แล้ว)
เราอาจวาดคอนทัวร์ทับลงบนแผนภาพไล่สีที่ได้จาก plt.hist2d ไปเลยก็ได้
ตัวอย่าง ลองวาดแผนภาพไล่สีแสดงการแจกแจงแบบปกติที่มีจุดศูนย์กลางอยู่สองจุดซึ่งมีขนาดไม่เท่ากัน
px1 = np.random.randn(700000) # ตำแน่งกลุ่มก้อนใหญ่
px2 = np.random.randn(300000)+4 # ตำแน่งกลุ่มก้อนเล็ก
px = np.hstack((px1,px2)) # นำกลุ่มก้อนทั้งสองมารวมกัน
py = np.random.randn(1000000)
lx = np.linspace(-3,6,151) # จุดขีดแบ่งของช่อง
ly = np.linspace(-3,3,101)
h = plt.hist2d(px,py,bins=[lx,ly],cmap='summer')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
x,y = np.meshgrid((lx[1:]+lx[:-1])/2,(ly[1:]+ly[:-1])/2)
z = h[0].T
plt.contour(x,y,z,linewidths=2,cmap='winter')
plt.show()
คอนทัวร์แบบลงสี หากใช้ฟังก์ชัน plt.contourf แทน plt.contour ก็จะเป็นการสร้างคอนทัวร์ที่พื้นมีสี ลักษณะโดยส่วนใหญ่ก็คล้ายๆกัน
ตัวอย่าง
x,y = np.meshgrid(np.linspace(-5,5,100),np.linspace(-5,5,100))
z = np.cos(x**2+y**2)
plt.contourf(x,y,z,9,cmap='nipy_spectral')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()
ลองวาดเปรียบเทียบความต่างระหว่าง plt.contour และ plt.contourf
x,y = np.meshgrid(np.linspace(-5,5,100),np.linspace(-5,5,100))
z = np.cos(x)+np.cos(y*0.5)
plt.subplot(2,1,1)
plt.contourf(x,y,z,np.linspace(-2,2,9),cmap='ocean')
plt.colorbar(pad=0.01)
plt.subplot(2,1,2)
plt.contour(x,y,z,np.linspace(-2,2,9),cmap='ocean')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()
ถ้าจะวาดทั้งเส้นทั้งระบายสีพื้นก็ใช้คู่กันซ้อนทับกันได้เลย
x,y = np.meshgrid(np.linspace(-5,5,100),np.linspace(-5,5,100))
z = np.cos(x)+np.cos(y)
plt.contour(x,y,z,np.linspace(-2,2,9),colors='m',linestyles='-',linewidths=3)
plt.contourf(x,y,z,np.linspace(-2,2,9),cmap='seismic')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()
คอนทัวร์แบบลงสีในแผนภาพแจกแจงความหนาแน่นเนื่องจากใน matplotlib ไม่มีฟังก์ชันสำหรับสร้างคอนทัวร์แจกแจงความหนาแน่นโดยตรง ถ้าเราไม่ได้ใช้ plt.hist2d เพื่อสร้างแผนภาพไล่สีแจกแจงความหนาแน่นมาก่อนก็อาจใช้ np.histogram2d ของ numpy ช่วย
px = np.random.randn(1000000)+np.linspace(-8,8,1000000)
py = np.random.randn(1000000)+np.cos(np.linspace(-8,8,1000000))
lx = np.linspace(-10,10,101)
ly = np.linspace(-4,4,101)
h = np.histogram2d(px,py,bins=[lx,ly])
x,y = np.meshgrid((lx[1:]+lx[:-1])/2,(ly[1:]+ly[:-1])/2)
z = h[0].T
plt.contourf(x,y,z)
plt.colorbar(orientation='horizontal',pad=0.01)
plt.subplots_adjust(0.05,-0.03,0.95,0.97)
plt.show()
อ้างอิง