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



numpy & matplotlib เบื้องต้น บทที่ ๗: การปรับแต่งส่วนประกอบของกราฟ
เขียนเมื่อ 2016/06/11 13:36
หลังจากที่บทที่แล้วได้เรียนรู้ส่วนประกอบของฉากที่ใช้กราฟไปแล้ว คราวนี้จะมาลองดูวิธีการปรับแต่งต่างๆ



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

เช่นลอง
import numpy as np
import matplotlib.pyplot as plt
theta = np.radians(np.linspace(0,360,73))
x = 10*np.cos(theta)
y = 10*np.sin(theta)
plt.plot(x,y)
plt.show()



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

เราสามารถปรับขนาดของภาพได้ด้วยการเติมคีย์เวิร์ดในฟังก์ชัน plt.figure

คีย์เวิร์ดที่เกี่ยวข้องมีอยู่ ๒ ตัวคือ figsize และ dpi

figsize คือขนาดของรูปในแนวตั้งและแนวนอน โดยต้องใส่ในรูปทูเพิลหรือลิสต์ มีหน่วยเป็นนิ้ว 1 นิ้วคือ 80 พิกเซลเป็นมาตรฐาน

ค่า figsize มาตรฐานจะเป็น  8x6 ดังนั้นจึงได้ภาพขนาด 640x480 อย่างไรก็ตามอาจมีความต่างไปตามคอมไพเลอร์ที่ใช้

จำนวนพิกเซลต่อนิ้วก็สามารถปรับได้ด้วยการใส่คีย์เวิร์ด dpi ยิ่งค่ามากภาพก็จะยิ่งใหญ่ ขนาดของภาพที่ได้ก็คือ figsize คูณด้วย dpi

ลองแก้ส่วนวาดกราฟเป็น
plt.figure(figsize=[5,5],dpi=40)
plt.plot(x,y)
plt.show()

แบบนี้จะได้ภาพขนาด 200x200 พิกเซล



ตอนที่เซฟภาพด้วยฟังก์ชัน savefig จะต้องปรับค่า dpi อีกทีด้วยการใส่คีย์เวิร์ด ค่า dpi ที่ปรับที่ figsize จะไม่มีผล ดังนั้นหากต้องการเซฟภาพขนาดเท่าเดิมก็พิมพ์
plt.savefig('wongklom.png',dpi=40)



การแต่งสีและขอบของภาพ
นอกจากปรับขนาดแล้วก็ยังสามารถปรับสีและขอบของภาพได้ด้วย คีย์เวิร์ดที่เกี่ยวข้องมีดังนี้
facecolor สีพื้นหลัง
edgecolor สีขอบ
linewidth ความกว้างขอบ
figsize ขนาดภาพในหน่วยนิ้ว [แนวตั้ง,แนวนอน]
dpi สัดส่วนพิกเซลต่อนิ้ว

ลอง

theta = np.radians(np.linspace(0,360,73))
x = 10*np.cos(theta)
y = 10*np.sin(theta)
plt.figure(figsize=[5,5],dpi=60,edgecolor='#AA1111',linewidth=15,facecolor='#99DDFF')
plt.plot(x,y)
plt.show()

ได้กราฟออกมาแลดูสวยงาม



คีย์เวิร์ดต่างๆที่ปรับลงไปเหล่านี้เวลาที่เซฟภาพก็ต้องใส่ลงในฟังก์ชัน savefig เช่นกัน ไม่เช่นนั้นภาพที่ได้ก็จะยังคงเป็นสีขาวโล่ง



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

การปรับขอบเขตสามารถทำได้ด้วยฟังก์ชัน plt.gca หรืออาจเขียนในรูปเมธอดของออบเจ็กต์ figure ที่จะวาดกราฟลง (ชื่อ figure).gca

คีย์เวิร์ดที่ต้องใส่คือ xlim และ ylim โดยค่าที่ต้องใส่คือทูเพิลหรือลิสต์ขอบเขต xlim=[ซ้าย, ขวา], ylim=[ล่าง, บน]

ตัวอย่าง
theta = np.radians(np.linspace(0,10000,2001))
x = 10*np.cos(theta)/(100+theta)
y = 10*np.sin(theta)/(100+theta)
plt.figure(edgecolor='#AA1111',linewidth=10,facecolor='#AAFFEE')
plt.gca(xlim=[-0.16,0.16],ylim=[-0.12,0.12])
plt.plot(x,y,c='#EE2211')
plt.show()





การปรับตำแหน่งและตัวเลขขีดพิกัด
นอกจากจะปรับขอบเขตแล้วเรายังสามารถปรับเส้นขีดที่บอกตำแหน่งได้ด้วย จากที่ปกติจะถูกกำหนดโดยอัตโนมัติตามความเหมาะสม สามารถทำได้โดยเพิ่มคีย์เวิร์ด xticks และ yticks ค่าที่ต้องใส่คือลิสต์หรืออาเรย์ไล่เรียงตำแหน่งขีด

np.linspace น่าจะเป็นฟังก์ชันที่เหมาะในการสร้างอาเรย์เพื่อใช้ในการนี้ เพราะสามารถกำหนดขอบเขตและขีดให้เว้นระยะเท่าๆตามจำนวนที่ต้องการได้

ลองดูกราฟเดิม
theta = np.radians(np.linspace(0,10000,2001))
x = 10*np.cos(theta)/(100+theta)
y = 10*np.sin(theta)/(100+theta)
plt.figure(edgecolor='#1111AA',linewidth=10,facecolor='#AAFFEE')
plt.gca(xlim=[-0.16,0.16],ylim=[-0.12,0.12],
        xticks=np.linspace(-0.16,0.16,9),
        yticks=np.linspace(-0.11,0.11,12))
plt.plot(x,y,c='#EE2211')
plt.show()



จะเห็นว่าจำนวนขีดเพิ่มขึ้นตามที่ต้องการ

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

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

แก้กราฟเป็นตามนี้ โดยเพิ่ม yticklabels และ xticklabels เข้าไป
plt.figure(edgecolor='#11AA11',linewidth=10,facecolor='#FFAAEE')
xlim = [-0.16,0.16]
ylim = [-0.12,0.12]
xticks = np.linspace(-0.16,0.16,9)
yticks = np.linspace(-0.11,0.11,12)
xticklabels = ['%.2fcm'%s for s in xticks]
yticklabels = ['%.2fcm'%s for s in yticks]
plt.gca(xlim=xlim,ylim=ylim,xticks=xticks,yticks=yticks,yticklabels=yticklabels,xticklabels=xticklabels)
plt.plot(x,y,c='#EE2211')
plt.show()

จะได้ว่ามีคำว่า cm เพิ่มเข้ามาในกราฟ



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

ค่าคีย์เวิร์ดต่างๆที่ใส่ลงใน gca() นั้นที่จริงแล้วเป็นการไปตั้งค่าแอตทริบิวต์ภายในออบเจ็กต์ axes เราสามารถตั้งค่าให้มันภายหลังแทนที่จะตั้งทันที

สามารถทำได้โดยใช้เมธอดซึ่งขึ้นต้นด้วยคำว่า set_ ตัวอย่างข้างต้นเขียนใหม่ได้เป็น
plt.figure(edgecolor='#11AA11',linewidth=10,facecolor='#FFAAEE')
ax = plt.gca()
ax.set_xlim([-0.16,0.16])
ax.set_ylim([-0.12,0.12])
ax.set_xticks(np.linspace(-0.16,0.16,9))
ax.set_yticks(np.linspace(-0.11,0.11,12))
ax.set_xticklabels(['%.2fcm'%s for s in np.linspace(-0.16,0.16,9)])
ax.set_yticklabels(['%.2fcm'%s for s in np.linspace(-0.11,0.11,12)])
plt.plot(x,y,c='#EE2211')
plt.show()

ผลที่ได้จะเหมือนเดิม แต่จะเห็นว่า plt.gca ไม่ต้องใส่อะไรลงไปเลย และต้องมีการเอาตัวแปร ax มารับด้วยเพื่อจะนำมาเรียกใช้เพื่อการปรับค่าในบรรทัดต่อๆมา

หรืออาจเขียนสั้นง่ายกว่านั้นโดยโดยใช้ฟังก์ชัน plt.xlim, plt.ylim, plt.xticks และ plt.yticks โดยไม่จำเป็นต้องใช้ plt.gca เลย
plt.figure(edgecolor='#11AA11',linewidth=10,facecolor='#FFAAEE')
plt.xlim([-0.16,0.16])
plt.ylim([-0.12,0.12])
plt.xticks(np.linspace(-0.16,0.16,9),['%.2fcm'%s for s in np.linspace(-0.16,0.16,9)])
plt.yticks(np.linspace(-0.11,0.11,12),['%.2fcm'%s for s in np.linspace(-0.11,0.11,12)])
plt.plot(x,y,c='#EE2211')
plt.show()

จะสังเกตได้ว่าในที่นี้ plt.xticks จะใช้แทนทั้ง set_xticks และ set_xticklabels ไปในเวลาเดียวกันเลย แต่ไม่มีฟังก์ชัน plt.xticklabels ดังนั้นต้องระวังอย่าสับสน

นอกจากนั้นยังสามารถดูค่าในภายหลังได้ด้วยเมธอดที่ขึ้นต้นด้วย get_
print(ax.get_xlim()) # ได้ (-0.16, 0.16)
print(ax.get_xticks()) # ได้ [-0.16 -0.12 -0.08 -0.04 0. 0.04 0.08 0.12 0.16]

นอกจากนี้ยังมีวิธีอื่นการปรับตำแหน่งและรูปแบบการแสดงผลของเลขขีดบนกราฟซึ่งอาจจะเข้าใจยากกว่าแต่ค่อนข้างสะดวกกว่า ซึ่งจะพูดถึงในบทที่ ๓๗



การควบคุมสัดส่วนของ x และ y ในกราฟ
จะเห็นว่าพอปรับ xlim และ ylim ก็จะทำให้สัดส่วนของค่า x และ y เปลี่ยนไปด้วย การปรับ xlim และ ylim ก็เป็นการช่วยปรับสัดส่วนของ x และ y ไปด้วย แต่ว่าแบบนั้นควบคุมสัดส่วนได้ยาก ไหนจะต้องคำนึงถึงขนาดของ figure ด้วย

กรณีที่ต้องการกำหนดสัดส่วนของค่า x และ y ให้แน่นอนอาจใส่คีย์เวิร์ด aspect เพิ่มลงไปใน gca

ค่า aspect คือสัดส่วนระหว่างด้านแกน y ต่อแกน x ถ้าใส่เป็น 1 สัดส่วนจะเท่ากัน ถ้าใส่ 0.5 x จะยืดใหญ่กว่า y สองเท่า เป็นต้น

นอกจากใส่เป็นตัวเลขแล้วอาจใส่เป็นสายอักขระ ซึ่งคำที่ใส่ได้คือ equal หมายถึง xy เท่ากัน (=1) และ auto หมายถึงปรับอัตโนมัติ

ตัวอย่าง
theta = np.radians(np.linspace(0,2000,5001))
r = 10*(10+(theta+np.cos(theta**3/100)**2))/(30+theta)
x = r*np.cos(theta)
y = r*np.sin(theta)
fig = plt.figure(facecolor='#228899')
ax = fig.gca(aspect=0.5)
ax.plot(x,y,c='#9933AA')
plt.show()



นอกจากนี้ยังอาจปรับได้ทีหลังด้วยเมธอด set_aspect

เช่นลองพิมพ์ลงไปตามนี้แล้วกลับไปดูที่ภาพอีกทีก็จะพบว่ากลายเป็นสัดส่วนเท่ากัน
ax.set_aspect('equal')




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

หากต้องการปรับ axes ได้อย่างอิสระอาจเลือกใช้แทนที่จะใช้ gca อาจเลือกใช้ plt.axes

plt.axes นั้นจะมีอาร์กิวเมนต์ที่ต้องใส่ไว้ก่อนที่จะ ใส่คีย์เวิร์ดต่างๆเช่นเดียวกับ gca

อาร์กิวเมนต์นั้นคือลิสต์ที่ประกอบไปด้วยค่า [ขอบซ้าย,ขอบล่าง,ความกว้าง,ความสูง] โดยทั้งหมดมีหน่วยเป็นสัดส่วนต่อความกว้างและความยาวของภาพทั้งภาพ (1 คือเต็มภาพ)

ส่วนคีย์เวิร์ดอื่นๆก็จะใส่เหมือนกับ gca สามารถใส่ xlim, xticks, ฯลฯ ได้

ตัวอย่าง
theta = np.radians(np.linspace(0,3000,2001))
r = (10+(theta+np.cos(theta**2/10)**2))/(100+theta)
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.figure(figsize=[5,5],facecolor='#66AAEE')
plt.axes([0,0,1,1],xlim=[-0.42,0.42],ylim=[-0.42,0.42])
plt.plot(x,y,c='#99EE11')
plt.show()



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

ลองปรับลดลงมาหน่อยให้พอเห็น
plt.axes([0.05,0.05,0.93,0.93],xlim=[-0.42,0.42],ylim=[-0.42,0.42])

แบบนี้ก็จะเล็กลงมาจนตัวเลขอยู่ในกรอบ

แต่ถ้าไม่ใส่อาร์กิวเมนต์ตัวแรกนี้ก็จะได้เป็นค่าตั้งต้น นั่นคือ [0.125,0.1,0.775,0.8]

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

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

ดังนั้นด้วย plt.axes จะทำให้เราสามารถวาดหลายกราฟในภาพเดียวกันได้ สำหรับการวาดหลายกราฟพร้อมกันจะยังไม่พูดถึงตรงนี้แต่จะเขียนถึงในบทที่ ๑๐



การเปลี่ยนสีฉากหลัง
อีกอย่างที่สามารถเปลี่นได้ก็คือสีฉากหลังของกราฟ ทำได้โดยใส่คีย์เวิร์ด facecolor เพิ่มเข้าไป

ตัวอย่าง
theta = np.radians(np.linspace(0,20000,10001))
x = (10+np.cos(theta*10)/0.5)*np.cos(theta)/(50+theta**1.2)
y = (10+np.cos(theta*10)/0.5)*np.sin(theta)/(50+theta**1.2)
plt.gca(facecolor='#222222',xlim=[-0.16,0.16],ylim=[-0.12,0.12])
plt.plot(x,y,c='#EEEEEE',marker='o',alpha=0.5,ls='-.')
plt.show()



หรืออาจตั้งค่าทีหลังโดยใช้คำสั่ง set_facecolor ก็ได้เช่นกัน

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

สรุปคีย์เวิร์ดที่ใส่ใน gca หรือ axes เพื่อปรับตั้งค่าต่างๆได้ (เฉพาะที่กล่าวถึงแล้วในบทนี้)
คีย์เวิร์ด ฟังก์ชัน เมธอด ความหมาย
xlim plt.xlim set_xlim ขอบเขตในแกน x
ylim plt.ylim set_ylim ขอบเขตในแกน y
xticks plt.xticks set_xticks ค่าตำแหน่งขีดบอกในแกน x
yticks plt.yticks set_yticks ค่าตำแหน่งขีดบอกในแกน y
xticklabels plt.xticks set_xticklabels ข้อความที่ขีดบอกในแกน x
yticklabels plt.yticks set_yticklabels ข้อความที่ขีดบอกในแกน y
aspect - set_aspect สัดส่วนค่าแกน y ต่อ x
axes_bgcolor - set_axes_bgcolor สีฉากหลัง



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

ส่วนประกอบต่างๆของ matplotlib ไม่ว่าจะ figure หรือ axes หรือตัวเส้นกราฟ หรืออื่นๆที่ยังไม่ได้กล่าวถึงก็ตาม การปรับค่าอะไรต่างๆนั้นมักมี ๒ วิธี คือการกำหนดค่าตั้งแต่ตอนเริ่มสร้างโดยใส่ค่าเพิ่มเป็นคีย์เวิร์ด กับการมาปรับตอนหลังจากที่สร้างแล้วด้วยฟังก์ชันหรือเมธอดต่างๆ

ดังที่เห็นในกรณีของ gca เราอาจใส่คีย์เวิร์ด xticks, xticklabels, ฯลฯ ลงไปในวงเล็บ () หลัง gca ได้เลย หรือจะใส่วงเล็บว่างๆแล้วมาปรับค่าด้วยเมธอด set_ ต่างๆภายหลังก็ได้

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



อ้างอิง


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


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

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

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

หมวดหมู่

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

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
python
-- numpy
-- matplotlib

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

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



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

  ค้นหาบทความ

  บทความแนะนำ

หลักการเขียนทับศัพท์ภาษาจีนกวางตุ้ง
การใช้ unix shell เบื้องต้น ใน linux และ mac
หลักการเขียนทับศัพท์ภาษาจีนกลาง
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
บันทึกการเที่ยวสวีเดน 1-12 พ.ค. 2014
แนะนำองค์การวิจัยและพัฒนาการสำรวจอวกาศญี่ปุ่น (JAXA)
เล่าประสบการณ์ค่ายอบรมวิชาการทางดาราศาสตร์โดยโซวเคนได 10 - 16 พ.ย. 2013
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
บันทึกการเที่ยวญี่ปุ่นครั้งแรกในชีวิต - ทุกอย่างเริ่มต้นที่สนามบินนานาชาติคันไซ
หลักการเขียนทับศัพท์ภาษาญี่ปุ่น
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ
ทำไมถึงอยากมาเรียนต่อนอก
เหตุผลอะไรที่ต้องใช้ภาษาวิบัติ?

ไทย

日本語

中文