การวาดกราฟหลายอันและ setting ต่างๆที่เกี่ยวกับ axis ใน matplotlib

Visits:528

Matplotlib เป็นแพคเกจที่เป็นพื้นฐานของ python สำหรับการวาดกราฟจากข้อมูลซึ่งจำเป็นมากสำหรับงานทางด้าน Data Analysis, Science, Engineering และอื่นๆอีกมากมาย โพสต์นี้จะแนะนำให้คุณรู้จักกับการวาดกราฟหลายๆอันภายใต้กรอบอันเดียวกันและ setting ต่างๆที่เกี่ยวกับแกน(axis)ของกราฟ


1. สร้างกราฟเดี่ยว

คำสั่งในการพลอตกราฟเท่าที่จำเป็นคือ

import matplotlib.pyplot as plt
ax = plt.axes()
ax.plot([1,2,3,4], [5,8,7,1])
plt.show()

คำสั่ง plt.axes() จะสร้างแกนหรือกราฟ ซึ่งจะสร้างตัวแปร ax ซึ่งเป็น object ที่ใช้แทนกราฟ คำสั่งอะไรเกี่ยวกับกราฟก็จะนำหน้าด้วย ax. (หรือตัวแปรที่เราตั้ง) โปรแกรมนี้เราพลอตกราฟของ x=[1,2,3,4] และ y=[5,8,7,1] ด้วยคำสั่ง plot กรอบใหญ่หรือ window ของกราฟจะเรียกว่า figure ซึ่งจะถูกสร้างขึ้นโดยอัตโนมัติเมื่อเราสั่ง plt.show()

2. สร้างกราฟหลายอันใน figure เดียวกัน

เราสามารถวาดกราฟได้มากกว่าหนึ่งภายใน window หรือหนึ่ง figure ซึ่งกรณีนี้จะต้องสร้าง axes หรือแกนตามจำนวนกราฟแล้วใช้คำสั่ง plot วาดตาม axes ของใครของมัน ซึ่งในกรณีนี้ให้ใช้คำสั่ง

fig = plt.figure()
ax1 = fig.add_subplot(param1)
ax2 = fig.add_subplot(param2)
ax3 = fig.add_subplot(param3)
...

คำสั่งแรก figure() จะสร้าง object ที่เป็นตัวแทนของกรอบ คำสั่ง add_subplot() จะสร้าง object ที่เป็นตัวแทนแกน(หรือกราฟ)เช่นเดียวกับ axes() แต่จะกระทำกับ fig (แทนที่จะทำกับ plt) เพื่อสร้าง axes ที่อยู่ภายใต้กรอบ(figure)เดียวกันซึ่งสามารถทำซ้ำกันหลายครั้งเท่ากับจำนวนแกนหรือกราฟที่ต้องการ

ดูจากตัวอย่างต่อไปนี้

import matplotlib.pyplot as plt
fig = plt.figure()
def createaxis():
    ax1 = fig.add_subplot(1,2,1)
    ax2 = fig.add_subplot(1,2,2)
    return ax1, ax2หรือ figure
ax1, ax2 = createaxis()
ax1.plot([1,2,3,4], [5, 8, 7, 1])
ax2.plot([1,2,3,4], [5, 8, 7, 1])
plt.show()

เขียนเป็นฟังก์ชั่นจะสะดวกในการเขียนมากกว่า createaxis() จะสร้างกราฟขึ้นมาสองอัน parameter ของ add_subplot() จะใช้บอกว่ามีกราฟกี่อันและวางในแนวไหน ตัวอย่างนี้เราต้องการกราฟสองอันวางเรียงในแนวนอนหรือมี layout แบบ 1 แถว 2 หลัก และแทนด้วย ax1 และ ax2 ตามลำดับ

ax1 มี parameter เป็น (1,2,1) หมายถึงเป็นในกรอบ(figure)ที่มี 1 แถว 2 หลักและเป็นสมาชิกตัวที่ 1
ax2 มี parameter เป็น (1,2,2) หมายถึงเป็นในกรอบ(figure)ที่มี 1 แถว 2 หลักและเป็นสมาชิกตัวที่ 2

ตัวอย่างต่อไปนี้เป็นการสร้างกราฟ 4 อันในหนึ่งกรอบ(figure)ที่ต้องการให้มี layout แบบ 2 แถว 2 หลัก

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 4))
def createaxis():
    ax1 = fig.add_subplot(2,2,1)
    ax2 = fig.add_subplot(2,2,2)
    ax3 = fig.add_subplot(2,2,3)
    ax4 = fig.add_subplot(2,2,4)
    return ax1, ax2, ax3, ax4
ax1, ax2, ax3, ax4 = createaxis()
ax1.plot([1,2,3,4], [5, 8, 7, 1])
ax2.plot([1,2,3,4], [5, 8, 7, 1])
ax3.plot([1,2,3,4], [5, 8, 7, 1])
ax4.plot([1,2,3,4], [5, 8, 7, 1])
plt.show()

ลองดูตัวอย่างที่ซับซ้อนขึ้น

Example 1

เป็นตัวอย่างของกรอบที่มี layout แบบ 3 แถว 2 หลักที่มีกราฟอยู่ 4 อันและกินพื้นที่ตามรูปด้านล่าง

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 4))
def createaxis():
    ax1 = fig.add_subplot(3,2,1)
    ax2 = fig.add_subplot(3,2,3)
    ax3 = fig.add_subplot(3,2,5)
    ax4 = fig.add_subplot(3,2,(2,6))
    return ax1, ax2, ax3, ax4
ax1, ax2, ax3, ax4 = createaxis()
plt.show()

ตัวอย่างนี้ plt.figure() จะมี parameter figsize=(5,4) หมายความว่าให้สร้างกรอบหรือ window ที่มีความกว้าง 5 นิ้วและสูง 4 นิ้ว(โดยประมาณ) ซึ่งอาจจำเป็นต้องกำหนดเองหากกรอบที่สร้างให้โดยอัตโนมัติไม่ได้สัดส่วนที่ต้องการ

Parameter ในกราฟอันที่ 4 คือ ( 3,2,(2,6) ) หมายถึงกราฟนี้อยู่ในกรอบแบบ 3 แถว 2 หลักโดยที่กราฟอันที่ 4 กินพื้นที่ของกราฟอันที่ 2 ถึงอันที่ 6

Example 2

เป็นตัวอย่างของกรอบที่มี layout แบบ 2 แถว 2 หลักที่มีกราฟอยู่ 3 อันและกินพื้นที่ตามรูปด้านล่าง

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 4))
def createaxis():
    ax1 = fig.add_subplot(2,2,(1, 3))
    ax2 = fig.add_subplot(2,2,2)
    ax3 = fig.add_subplot(2,2,4)
    return ax1, ax2, ax3
ax1, ax2, ax3 = createaxis()
plt.show()

Example 3

เป็นตัวอย่างของกรอบที่มี layout แบบ 2 แถว 3 หลักที่มีกราฟอยู่ 4 อันและกินพื้นที่ตามรูปด้านล่าง

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7.5, 4))
def createaxis():
    ax1 = fig.add_subplot(2,3,1)
    ax2 = fig.add_subplot(2,3,2)
    ax3 = fig.add_subplot(2,3,3)
    ax4 = fig.add_subplot(2,3,(4,6))
    return ax1, ax2, ax3, ax4
ax1, ax2, ax3, ax4 = createaxis()
plt.show()

Example 4

เป็นตัวอย่างของกรอบที่มี layout แบบ 2 แถว 3 หลักที่มีกราฟอยู่ 4 อันและกินพื้นที่ตามรูปด้านล่างอีกแบบหนึ่ง

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7.5, 4))
def createaxis():
    ax1 = fig.add_subplot(2,3,(1, 3))
    ax2 = fig.add_subplot(2,3,4)
    ax3 = fig.add_subplot(2,3,5)
    ax4 = fig.add_subplot(2,3,6)
    return ax1, ax2, ax3, ax4
ax1, ax2, ax3, ax4 = createaxis()
plt.show()

3. Dark mode

หากต้องการให้ background ของกราฟเป็นสีดำหรือสีอื่นๆ ให้ใช้คำสั่ง

fig.patch.set_facecolor('black')
ax.patch.set_facecolor('black')
ax.patch.set_alpha(0.7) 

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

ax.spines['bottom'].set_color('white')
ax.spines['top'].set_color('white')
ax.spines['right'].set_color('white')
ax.spines['left'].set_color('white')

ซึ่งจะเซตสีของแกนรอบด้าน (ค่าปกติจะเซตสีดำให้กับ bottom และ left สีขาวให้กับ top และ right

เขียนทั้งหมดเป็นฟังก์ชั่นจะดูง่ายกว่า

from matplotlib import pyplot as plt
fig = plt.figure()
ax = fig.add_subplot()
def set_label(title, xlabel, ylabel, tcolor, xcolor, ycolor):
    ax.set_title(title, color='white', fontsize=20)
    ax.set_xlabel(xlabel, color='lightgreen', fontsize=18)
    ax.set_ylabel(ylabel, color='lightgreen', fontsize=18)
def set_darkmode():
    fig.patch.set_facecolor('black')
    ax.patch.set_facecolor('black')
    ax.patch.set_alpha(0.7)
    ax.spines['bottom'].set_color('white')
    ax.spines['top'].set_color('white')
    ax.spines['right'].set_color('white')
    ax.spines['left'].set_color('white')
    set_label('This is empty subplot', 'temperature', 'pressure', 'white', 'lightgreen', 'lightgreen')
set_darkmode()
plt.show()

4. Title และ Label

คำสั่งแรกเซตข้อความ title, ขนาดฟอนต์และสี คำสั่งสองเซตข้อความที่แกน x ขนาดฟอนต์และสี

ax.set_title('This is graph title', fontsize=16, color='green')
ax.set_xlabel('x axis', fontsize=16, color='green')

หรือเขียนเป็นฟังก์ชั่นไว้ใช้งานจะดูง่ายกว่า

from matplotlib import pyplot as plt
fig = plt.figure()
ax = plt.axes()
def set_label(title, xlabel, ylabel):
    ax.set_title(title)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
set_label('Example graph', 'time', 'velocity')

5. เซตแกน x และ y

5.1 ขอบเขตของแกน

ปกติ range บนแกน x และ y จะถูกเซตให้โดยอัตโนมัติตามข้อมูลที่เราสั่ง plot แต่หากเราต้องการเปลี่ยน

ax.set_xlim([0, 10])

หมายถึงให้เซตช่วงของแกน x เป็น 0 ถึง 10 แกน y ก็เปลี่ยนเป็น ylim หรือเขียนเป็นฟังก์ชั่นไว้ใช้งานจะดูง่ายกว่า

from matplotlib import pyplot as plt
fig = plt.figure()
ax = plt.axes()
xlim = 10
ylim = 20
def set_lims():
    ax.set_xlim([0, xlim])
    ax.set_ylim([0, ylim])
set_lims()
plt.show()

สังเกตว่า xlim และ ylim จะเซตไว้เป็นตัวแปร global จะสะดวกกว่าเพราะเราต้องใช้ค่านี้ในฟังก์ชั่นอื่นด้วย

5.2 กำหนด step ของแกน x และ y (tick)

หากไม่กำหนด matplotlib จะกำหนด step หรือ scale บนแกน x และ y ให้เราอัตโนมัติ แต่เราสามารถกำหนดสเกลได้เองซึ่งในภาษา matplotlib จะเรียกสเกลว่า tick เช่นหากต้องการให้มีตัวเลขบนแกน x ที่ตำแหน่ง 0, 2, 4, 6, 8, 10 ก็ใช้คำสั่ง

ax.set_xticks([0, 2, 4, 6, 8, 10]) 

หากมีช่วงถี่มากก็ใช้คำสั่ง arange หรือ linspace สร้างจะสะดวกกว่า

ax.set_xticks(arange(0, 10+0.1, 2))
#or
ax.set_xticks(linspace(0, 10, 5))

โดยทั่วไปนิยมใช้ arange มากกว่าเพราะกำหนดช่วงโดยการบวกทีละ step, (2) ที่ต้องใส่ 10+0.1 เพราะว่าคำสั่งนี้ไม่รวมตัวเลขปลายทาง หากเขียน arange(0, 10, 2) จะให้เอาท์พุทเป็น [0, 2, 4, 6, 8] จึงต้องบวก 0.1 เพื่อให้ปลายทางเป็น 10.1 (เป็น trick) เมื่อบวกถึง 10 ก็จะรวมเป็นเอาท์พุทด้วย [0, 2, 4, 6, 8, 10] (12 ไม่รวมเพราะเกิน 10.1)

หากใช้ linspace(0, 10, 5) step จะเป็น 10/5 เท่ากับ 2 ให้เอาท์พุท [0, 2, 4, 6, 8, 10] ตามต้องการ (คำสั่งนี้รวมเลขปลายทาง) แต่ไม่สะดวกหากแต่ละ tick ไม่เป็นจำนวนเต็มเช่น [0, 2.5, 5, 7.5, 10]

จะต้องใช้ร่วมกับคำสั่ง grid จึงจะแสดง tick ออกมา

ax.set_xticks(arange(0, 10+0.1, 2))
ax.grid(which='major', alpha=0.9, axis='x')

major เป็นการบอกว่า tick นี้เป็นขีดหลัก alpha เป็นตัวบอกว่าจะให้ขีดมีความหนาเท่าไร(สูงสุด 1) axis ใส่เป็นแกน x หรือ y ที่ต้องการ หากต้องการขีดย่อยภายในช่วงของขีดหลักก็ใช้

ax.set_xticks(arange(0, 10+0.1, 0.5), minor=True)
ax.grid(which='minor', alpha=0.5, axis='x')

minor เป็นการระบุว่า tick และ grid ที่เซตเป็นของขีดย่อย คำสั่งต่อไปนี้เรากำหนด tick บนแกน x

ax.set_xticks(arange(0, 10+0.1, 2))
ax.set_xticks(arange(0, 10+0.1, 0.5), minor=True)
ax.grid(which='minor', alpha=0.5, axis='x')
ax.grid(which='major', alpha=0.9, axis='x')
ax.tick_params(axis='x', colors='blue')

คำสั่งสุดท้ายกำหนดให้ขีดและตัวเลขบนแกนมีสีฟ้า

หรือเขียนเป็นฟังก์ชั่นไว้ใช้งาน

from matplotlib import pyplot as plt
from numpy import arange
fig = plt.figure()
ax = fig.add_subplot()
xlim = 10
ylim = 10
def set_lims():
    ax.set_xlim([0, xlim])
    ax.set_ylim([0, ylim])
def set_ticks(axis='both', major_step=2, minor_step=1):
    if axis=='x' or axis=='both':
        ax.tick_params(axis='x', colors='blue')
        ax.set_xticks(np.arange(0, xlim+0.1, major_step))
        ax.set_xticks(np.arange(0, xlim+0.1, minor_step), minor=True)
        ax.grid(which='minor', alpha=0.5, axis='x')
        ax.grid(which='major', alpha=0.9, axis='x')
    if axis=='y' or axis=='both':
        ax.tick_params(axis='y', colors='blue')
        ax.set_yticks(np.arange(0, ylim+0.1, major_step))
        ax.set_yticks(np.arange(0, ylim+0.1, minor_step), minor=True)
        ax.grid(which='minor', alpha=0.5, axis='y')
        ax.grid(which='major', alpha=0.9, axis='y')
def set_axis_attribute():
    ax.xaxis.label.set_color('blue')
    ax.xaxis.label.set_fontsize(18)
    ax.yaxis.label.set_color('blue')
    ax.yaxis.label.set_fontsize(18)
plt.show()

6. กราฟแบบ log

ในงานทางด้าน science/engineering มักมีการวาดกราฟโดย rescale แกน x และ y ให้เป็น log scale ซึ่งทำได้ง่ายดายโดยเปลี่ยนคำสั่ง plot ไปเป็น loglog() หมายถึงให้ rescale เป็น log scale ทั้งแกน x และ y และ semilogx() และ semilogy() ให้ทำเฉพาะแกน x และ y ตามลำดับ

import matplotlib.pyplot as plt
from numpy import linspace
x = linspace(1, 10)
y = x
fig = plt.figure()
def normal():
    ax = fig.add_subplot(221)
    ax.plot(x,y)
    ax.set_title("normal")
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.grid(which="both")
def loglog():
    ax2 = fig.add_subplot(222)
    ax2.loglog(x,y)
    ax2.set_title("Loglog")
    ax2.set_xlabel("X")
    ax2.set_ylabel("Y")
    ax2.grid(which="both")
def semilogx():
    ax2 = fig.add_subplot(223)
    ax2.semilogx(x,y)
    ax2.set_title("semilogx")
    ax2.set_xlabel("X")
    ax2.set_ylabel("Y")
    ax2.grid(which="both")
def semilogy():
    ax2 = fig.add_subplot(224)
    ax2.semilogy(x,y)
    ax2.set_title("semilogy")
    ax2.set_xlabel("X")
    ax2.set_ylabel("Y")
    ax2.grid(which="both")
normal()
loglog()
semilogx()
semilogy()
plt.show()
Facebook Comments