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



numpy & matplotlib เบื้องต้น บทที่ ๓๓: การวาดในระบบพิกัดเชิงขั้ว
เขียนเมื่อ 2016/06/12 16:14
แก้ไขล่าสุด 2022/07/21 20:37
ในบทที่ผ่านๆมาเราทำทุกอย่างในระบบพิกัดฉากมาโดยตลอด เพราะเป็นระบบพื้นฐานที่ง่ายที่สุด

แต่หากต้องการทำให้ทุกอย่างอยู่ในระบบพิกัดเชิงขั้ว matplotlib ก็สามารถทำได้เช่นกัน



วาดกราฟในพิกัดเชิงขั้ว
การเขียนให้อยู่ในรูปพิกัดเชิงขั้วทำได้โดยกำหนดที่ตัว axes โดยตอนสร้าง axes ขึ้นมาให้ใส่คีย์เวิร์ดว่า polar=1 หรือไม่ก็ projection='polar'

จากนั้นเวลาวาดกราฟก็ใช้คำสั่งวาดแบบเดียวกับที่ใช้กันมาในระบบพิกัดฉาก แต่ค่าที่ต้องใส่จะใช้อาร์กิวเมนต์ตัวแรกเป็นค่ามุม และตัวหลังเป็นระยะห่างจากใจกลาง

ค่ามุมมีหน่วยเป็นเรเดียน ดังนั้นหากจะใส่หน่วยเป็นองศาก็ต้องแปลงก่อน โดยอาจใช้ฟังก์ชัน np.radians ช่วย

ตัวอย่าง วาดกราฟซึ่งมีระยะห่างจากใจกลางเพิ่มตามมุม
import numpy as np
import matplotlib.pyplot as plt
mum = np.linspace(0,360,361)
r = mum
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.plot(np.radians(mum),r)
plt.show()

แค่นี้ก็ออกมาเป็นพิกัดเชิงขั้วอย่างง่ายแล้ว



ตรงนี้หากเราตัดบรรทัด plt.axes(polar=1) ออกไปแล้วลองวาดใหม่ผลที่ได้ก็จะได้เป็นกราฟเส้นตรงธรรมดา



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

พิกัดเชิงขั้วถ้าหากวนครบ 360 องศาก็จะกลับมาอยู่ที่มุมเดิม ดังนั้นจะเห็นกราฟที่วนซ้อนกันไปเรื่อยๆได้ กราฟ cos ธรรมดาในระบบพิกัดฉากพอมาอยู่ในระบบพิกัดเชิงขั้วก็กลายเป็นลวดลายสวยงามแบบ นี้ได้
mum = np.linspace(0,3600,3601)
r = 1+np.cos(np.radians(mum*1.1))
plt.figure(figsize=[9,6])
plt.subplot(121)
plt.plot(np.radians(mum),r)
plt.subplot(122,polar=1)
plt.plot(np.radians(mum),r)
plt.subplots_adjust(0.05,0.05,0.97,0.97,0.1,0.1)
plt.show()



ที่จริงแล้วหากไม่ต้องการวาดให้อยู่ในรูปพิกัดเชิงขั้วเราอาจจะแปลงจาก r,θ เป็น x,y เองก็ได้ด้วยการคำนวณโดย x = rcosθ, y = rsinθ

ลองทำการคำนวณแปลงเป็น x,y แล้วพล็อตกราฟธรรมดาก็จะได้กราฟแบบเดียวกัน เพียงแต่อยู่ในระบบพิกัดฉาก
mum = np.linspace(0,3600,3601)
plt.figure(figsize=[7,7])
r = 1+np.cos(np.radians(mum*1.1))
x = r*np.cos(np.radians(mum))
y = r*np.sin(np.radians(mum))
plt.plot(x,y)
plt.show()





การปรับแต่ง
โดยหลักแล้วกราฟในพิกัดเชิงขั้วก็สามารถปรับแต่งอะไรต่างๆได้ในลักษณะคล้ายกับของพิกัดฉาก แต่ก็มีความแตกต่างออกไปบ้างเล็กน้อย

ลองดูตัวอย่างเช่นการแก้ตำแหน่งขีดบอกค่านั้นทำได้โดยใช้ฟังก์ชัน plt.xticks กับ plr.yticks หรือด้วยเมธอด set_xticks กับ set_yticks ได้เหมือนกัน โดย xticks ในที่นี้จะเป็นขีดของมุม ส่วน yticks เป็นขีดของระยะห่างจากใจกลาง
mum = np.linspace(0,7200,3601)
r = 1+np.cos(np.radians(mum*1.05))
plt.figure(figsize=[7,7])
ax = plt.axes(polar=1,facecolor='#FFDDCC')
plt.xticks(np.radians(np.arange(0,360,30))) # ตั้งให้แสดงทุก 30 องศา
plt.yticks([]) # ใส่ลิสต์ว่างแล้วตัวเลขแนวรัศมีจะหายไป
ax.plot(np.radians(mum),r,'r')
plt.show()



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

การเปลี่ยนการแสดงผลให้เป็นหน่วยเรเดียนหรือเป็นอะไรอื่นๆอาจทำได้โดยใช้ set_xticklabels

ลองพิมพ์เพิ่มลงไปตามนี้จะได้ค่าเป็นหน่วยเรเดียน
ax.set_xticklabels(np.radians(np.arange(0,360,30)))

หรือลองใช้ latex เพื่อให้ดูสวยขึ้น เช่น พิมพ์ตามนี้เพิ่มเข้าไป
xtl = []
for x in np.arange(12):
    if(x%6==0):
        xtl += [r'$%d\pi$'%(x/6)]
    elif(x%3==0):
        xtl += [r'$\frac{%d}{2}\pi$'%(x/3)]
    elif(x%2==0):
        xtl += [r'$\frac{%d}{3}\pi$'%(x/2)]
    else:
        xtl += [r'$\frac{%d}{6}\pi$'%x]
ax.set_xticklabels(xtl,fontsize=24)



สำหรับค่าขีดบอกตำแหน่งในแนวรัศมีนั้นนอกจากจะปรับได้ด้วย set_yticks แล้วยังอาจใช้ set_rgrids ซึ่งจะดีกว่าตรงที่สามารถตั้งตำแหน่งที่จะวางได้ด้วย โดยใส่คีย์เวิร์ด angle หน่วยเป็นองศา
ax.set_rgrids([1,1.5,2],angle=135,fontsize=16)



นอกจากนี้หากต้องการปรับแค่ตำแหน่งมุมที่วางตัวเลขก็อาจแค่ใช้เมธอด set_rlabel_position โดยใส่ค่าตัวเลขเป็นหน่วยองศาลงไป เช่น
ax.set_rlabel_position(225)

แบบนี้ก็จะย้ายไปอยู่มุมซ้ายล่าง

การปรับเส้นรอบวงให้ไปทำที่ออบเจ็กต์ในแอตทริบิวต์ของแกนซึ่งมีชื่อว่า spines['polar'] เราสามารถปรับอะไรต่างๆได้เช่นเดียวกับ spines['top'], spines['bottom'], spines['left'] และ spines['right'] ของระบบพิกัดฉาก แต่ในระบบพิกัดฉากมีแค่ spines['polar'] อันเดียวให้ปรับ

การปรับ แต่งทำได้คล้่ายกัน เช่น แต่งสีโดย set_color ปรับความกว้างด้วย set_lw ปรับรูปแบบเส้นด้วย set_ls หรือทำให้หายไปด้วย set_visible(0)
ax.spines['polar'].set_color('b')
ax.spines['polar'].set_lw(4)
ax.spines['polar'].set_ls('--')



ส่วนการปรับขอบเขตการแสดงผลนั้นระบบพิกัดเชิงขั้วจะไม่มีอิสระเท่ากับพิกัดฉาก เพราะยังไงมุมก็ไล่จาก 0 ถึง 360 สิ่งที่ปรับได้มีเพียง r ต่ำสุดและสูงสุดเท่านั้น

การปรับ r สูงสุดทำได้โดยใช้เมธอด set_ylim หรือฟังก์ชัน plt.ylim เช่น
mum = np.linspace(0,7200,3601)
r = 1+np.cos(np.radians(mum*1.05))
plt.figure(figsize=[7,7])
ax = plt.axes(polar=1,facecolor='#FFDDCC')
ax.set_xticks(np.radians(np.arange(0,360,30)))
ax.spines['polar'].set_color('y')
ax.spines['polar'].set_lw(6)
plt.ylim([1.6,2.1]) # หรือ ax.set_ylim([1.6,2.1])
ax.plot(np.radians(mum),r,'r')
plt.show()



plt.ylim หรือ set_ylim นี้อาจเขียนแทนด้วยเมธอด set_rlim ก็ได้ นอกจากนี้ยังอาจใช้เมธอด set_rmax และ set_rmin เพื่อกำหนดขอบเขตได้ด้วย
ax.set_rmin(0)
ax.set_rmax(0.4)

เวลาที่ใช้ระบบพิกัดฉากถ้าไม่ได้ตั้งอะไรจะมีเส้นกริดขึ้นมาโดยอัตโนมัติ เราสามารถลบเส้นกริดได้โดยใช้เมธอด grid ใส่ค่า 0 ให้
ax.grid(0)



หรือหากต้องการปรับเส้นกริดให้เป็นไปตามที่ต้องการก็ทำได้ในลักษณะเดียวกับพิกัดฉาก เช่น
ax.grid(c='#5500EE', ls='--', lw=3)



นอกจากนี้ก็ยังสามารถใช้ฟังก์ชัน plt.tick_params หรือเมธอด tick_params เพื่อปรับคุณสมบัติต่างๆของตัวเลขขีดบอก เช่นสีและขนาด
ax.tick_params(colors='#EE44AA',labelsize=14)





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

ตัวอย่างแผนภูมิแท่งและกราฟไม้ขีดไฟ
mum = np.linspace(0,360,13)
r = 3+np.cos(np.radians(mum*3))
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.bar(np.radians(mum),r,color='g',width=np.radians(30))
plt.grid(0)
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.stem(np.radians(mum),r,'m')
plt.grid(0)
plt.show()




กราฟระบายสีระหว่างช่วง
mum = np.linspace(0,360,3601)
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.yticks([]) # ลบเลขบอกค่าตามแนวรัศมี
r = [0]*5
for i in range(5):
    r[i] = 2+i*2+np.cos(np.radians(mum*(5*2**i)))
    cmap = plt.get_cmap('summer_r')
    fc = cmap(i/4.)
    if(i==0):
        plt.fill_between(np.radians(mum),r[i],facecolor=fc,lw=0)
    else:
        plt.fill_between(np.radians(mum),r[i],r[i-1],facecolor=fc,lw=0)
plt.show()



แผนภาพการกระจาย
mum = np.linspace(0,720,721)
r = np.random.uniform(1,10,721)
c = np.random.uniform(0,1,721)
plt.figure(figsize=[7,7])
ax = plt.axes(polar=1,facecolor='#FFFFAA')
ax.set_yticks([])
ax.set_ylim([0,10])
ax.scatter(np.radians(mum),r,c=c,s=r*10,cmap='cool',alpha=0.5)
ax.spines['polar'].set_color('#BB22FF')
ax.spines['polar'].set_lw(5)
ax.tick_params(colors='#AA22FF',labelsize=14)
plt.show()



แผนภาพไล่สี
mum,r = np.meshgrid(np.linspace(0,360,361),np.linspace(0,1,401))
c = 2+np.cos(np.radians(mum*2))+np.sin(np.radians(r*1800-45))
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.xticks([])
plt.yticks([])
plt.pcolormesh(np.radians(mum),r,c,cmap='gnuplot')
plt.colorbar(pad=0.01,aspect=40,fraction=0.05,shrink=0.9)
plt.subplots_adjust(0.05,0.05,0.97,0.97,0.1,0.1)
plt.show()



คอนทัวร์
mum,r = np.meshgrid(np.linspace(0,360,91),np.linspace(0,1,101))
c = 2+np.sin(np.radians(mum*2))+np.sin(np.radians(r*1800-45))
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.xticks([])
plt.yticks([])
plt.contourf(np.radians(mum),r,c,5,cmap='gnuplot2')
plt.colorbar()
plt.show()



เส้นกระแส
mum,r = np.meshgrid(np.linspace(0,3600,1801),np.linspace(0,1,101))
u = r*0.1+np.random.rand(101,1801)
v = np.random.rand(101,1801)
plt.figure(figsize=[7,7])
plt.axes(polar=1)
plt.ylim([0,1])
plt.streamplot(np.radians(mum),r,u,v,color='#AA3333')
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月

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

ไทย

日本語

中文