Python
Thứ Bảy, 26/01/2019, 00:01
Matplotlib: Những điều cần biết để tùy chỉnh Figure như ý muốn

Matplotlib: Những điều cần biết để tùy chỉnh Figure như ý muốn

Đôi khi chúng ta có thể vẽ được những hình đơn giản bằng lệnh plt.plot, nhưng không nắm rõ bản chất của các hình vẽ nên không thể "full control" những chi tiết của cửa sổ figure được. Bài viết này sẽ trình bày theo ngôn ngữ đối tượng về những điều cơ bản nhưng rất quan trọng liên quan đến figure của matplotlib. Bài viết không nhằm mục đích hướng dẫn các bạn vẽ hình. Bài viết chỉ trình bày sâu hơn về figure của thư viện Matplotlib. Để xem những khả năng vẽ hình của Matplotlib, mời bạn xem bài viết sau:
Trước hết, để thuận tiệp cho các ví dụ, ta import module pyplot của thư viện matplotlib với tên gọi tắt là **plt **và sử dụng xuyêt suốt các ví dụ
import matplotlib.pyplot as plt
Nhân tiện, chúng ta ôn lại một chút về Python cơ bản. Như đã nói trong bài viết Hiểu đúng về Name và Value trong Python, lệnh import cũng là một lệnh gán trong Python. Biến plt bây giờ sẽ đại diện cho đối tượng matplotlib.pyplot đã được gọi vào bộ nhớ. OK, let's start!

1. Chính xác thì Figure là gì?

Một figure như ta thường thấy là một đối tượng của lớp figure trong thư viện matplotlib. Lớp figure được định nghĩa trong module matplotlib.figure, lớp này chứa tất cả những thành phần của một hình vẽ (top level container for all plot elements). Tức là mọi thuộc tính, phương thức của hình vẽ đều được định nghĩa trong lớp này. Để khởi tạo một figure trống, ta chỉ đơn giản gọi phương thức .figure() của plt
# Khởi tạo figure trống fig1 = plt.figure() # Gọi phương thức show() của pyplot để hiện figure hiện tại plt.show()
Khi đó, biến fig1 trở thành một thể hiện của lớp figure. Lưu ý, sau khi khởi tạo, fig1 chỉ là một reference đến một đối tượng thực sự trên RAM. Để xuất hiện cửa sổ figure, thông thường ta gọi lệnh plt.show() (Mình sẽ nói về bản chất của lệnh này ở phía sau). Ta sẽ được một cửa sổ trống tương tự như sau (tùy theo hệ điều hành): Như ta thấy, tên của cửa sổ là "Figure 1". Tên này là do matplotlib tự động đặt cho. Để đặt tên cho figure ngay lúc khởi tạo, ta chỉ cần đưa vào một chuỗi lúc gọi hàm figure, ví dụ: plt.figure(u"Hàm số sin"). Tip: chữ u phía trước đề khai báo chuỗi Unicode. Như vậy, về mặt trực quan thì figure là cái cửa sổ chứa tất cả những gì bạn sẽ vẽ trên đó.
notion image

2. Thành phần chính của một figure?

Thành phần chính của một figure là các **axes **(những khung nhỏ hơn để vẽ hình lên đó). Một figure có thể chứa một hoặc nhiều axes . Nói cách khác, figure chỉ là khung chứa, chính các axes mới thật sự là nơi các hình vẽ được vẽ lên. Theo ngôn ngữ đối tượng thì: figure có một thuộc tính kiểu list gọi là axes. Danh sách này chứa các axes của figure đó. Mỗi axes là một đối tượng của lớp Axes (lớp này được định nghĩa trong module matplotlib.axes). Mỗi axes có thể chứa một hoặc nhiều hình vẽ (plots). Như vậy, các phần tử như: đường vẽ (plots), các điểm chia (ticks), tên của các trục tọa độ (xlabel, ylabel),... đều là con của axes chứ không phải là của figure. Vì thế, sẽ không có những methods gọi từ figure kiểu như:
  • fig.plot()
  • fig.get_xlabel()
  • fig.set_xticks()
  • ...
Sau đây là ví dụ của một figure có nhiều axes chồng chéo nhau
# Khởi tạo một figure trống fig3 = plt.figure(u'Các axes chồng chéo nhau trong một figure') # Thêm axes bằng lệnh add_subplot fig3.add_subplot(1,1,1, facecolor='white') # Thêm axes bằng lệnh add_axes fig3.add_axes([0.1, 0.4, 0.4, 0.3], facecolor=(0,0,1)) fig3.add_axes([0.6, 0.2, 0.4, 0.3], facecolor='#ff0000') # Thêm tiếp một axes bằng lệnh add_subplot # Viết tắt của fig3.add_subplot(1,3,2) fig3.add_subplot(132, facecolor=(0,0,0,0.5)) # Hiện hình vẽ lên fig3.show()
Tất nhiên, trong thực tế không ai bố trí các axes một cách xấu xí như vậy. Ví dụ trên chỉ cho thấy: một figure có thể có bao nhiêu axes tùy thích, có thể thêm-xóa-sửa các axes bất kỳ lúc nào vì chúng là các đối tượng độc lập (chúng ta để ý thấy trong mỗi axes, các trục tọa độ luôn là từ 0 đến 1).
notion image

3. Quản lí các axes trong figure

Làm thế nào để truy cập và sửa (thay đổi màu, thay đổi vị trí,...) các axes đã thêm vào figure? Để dễ hình dung, chúng ta tiếp tục ví dụ phía trên. Như đã nói, tất cả các axes của figure đều được liệt kê trong fig3.axes, nhưng danh sách này là Read-only. Vì thế để lấy danh sách các axes và thay đổi chúng, ta phải dùng phương thức get_axes() của fig3 (điều này không có gì lạ nếu bạn đã có kinh nghiệm với OOP). Giả sử bây giờ ta muốn bỏ hết các điểm chia tọa độ đi, thêm vào mỗi axes dòng chữ "TEXmath" ở góc dưới bên trái. Chỉ cần dùng vòng lặp for như sau:
for ax in fig3.get_axes(): ax.set_alpha(0.5) ax.set_xticks([ ]) ax.set_yticks([ ]) ax.text(0,0,"TEXmath", {'fontsize':14})
notion image

4. Một số thuộc tính khác của figure

Figure có một thuộc tính rất quan trọng đó là figsize.  Thuộc tính này quy định kích thước cửa sổ figure (theo đơn vị inch). Ví dụ:
fig4 = plt.figure(u'Figure kích thước 6x4 inches',figsize=(6,4)) fig5 = plt.figure(u'Figure kích thước 4x3 inches',figsize=(4,3))
     Tiếp theo là thuộc tính edgecolor và linewidth
notion image
notion image
  • edgecolor quy định màu của khung viền bao quanh tất cả các axes trong figure đó
  • linewidth quy định độ dày của khung viền này
  • facecolor quy định màu nền của figure
  • Tip: Giá trị mặc định của chúng như sau: edgecolor='w'linewidth=0,  facecolor='w'. Vì thế, nếu ta chỉ thay đổi màu edgecolor thì vẫn chưa thấy khung viền này, mà ta còn phải tăng giá trị linewidth lên
  • dpi độ phân giải của hình (dots per inch). Giá trị mặc định là 100. dpi càng cao thì chất lượng ảnh sẽ càng cao

5. Lưu figure đúng cách

Ta biết, để lưu một figure ta dùng method savefig(). Tuy nhiên có một số lưu ý khi sử dụng. Giả sử ta vẽ hình sau đây trên một figure có nền màu xám như sau
import numpy as np # Khởi tạo hai mảng ngẫu nhiên X và Y N = 100 X = np.random.rand(n) Y = np.random.rand(n) # Diện tích sẽ tăng dần theo trục Y area = 100 * Y**2 * np.pi # Màu sắc sẽ thay đổi theo trục X colors = X # Khởi tạo một figure trống có nền xám fig = plt.figure(u'Vẽ các điểm ngẫu nhiên bằng lệnh scatter', facecolor='#00000050') # Gọi phương thức gca() (get curent axes) của fig # Sau đó vẽ lên axes nhận được fig.gca().scatter(X, Y, s=area, c=colors, cmap=plt.cm.jet, edgecolor='k') fig.show()
Lưu ý: method gca() dùng để gọi đến axes đang ở trạng thái active trong figure. Nếu figure chưa có axes nào thì gca() sẽ tạo ra một axes mới, tương đương với add_subplot(111) Bây giờ ta thử lưu figure trên bằng lệnh fig.savefig('random points.png'). Ta sẽ thu được một hình định dạng PNG sau đây trên ổ cứng Như bạn thấy, nền xám của figure đã bị biến thành màu trắng. Nguyên nhân là method savefig() cũng có tham số facecolor (mặc định màu trắng) và tham số này đã over-ride (đè lên) facecolor của figure. Vì thế, để lưu được figure đúng như ta nhìn thấy trên cửa sổ figure ta phải lấy facecolor của figure bằng phương thức get_facecolor(), tương tự như sau:
notion image
notion image
fig.savefig('random points.png', facecolor=fig.get_facecolor())
Tương tự, các tham số edgecolor, dpi ... cũng phải được khai báo trong lệnh savefig để giữ đúng nguyên trạng của figure.
notion image
fig.savefig('random points.png', facecolor=fig.get_facecolor(), edgecolor=fig.get_edgecolor(), dpi = fig.get_dpi())
Tips: Sau khi show hình lên, nếu ta zoom hình, co dãn cửa sổ, di chuyển hình vẽ (bằng công cụ move),... thì những tác động này cũng trực tiếp làm thay đổi figure (tức là ta thấy figure thế nào thì sau khi savefig ta cũng sẽ được như thế đó). Do đó, nếu bạn có rất nhiều figure, để căn chỉnh các figure này cho thống nhất, ta không nên căn chỉnh bằng tay. Mà phải căn chỉnh thông qua các tham số khi khởi tạo và khi lưu figure.

6. Làm thế nào để xóa nội dung một figure?

Xóa nội dung của một figure tức là xóa đi các axes và hình vẽ gắn liền với các axes đó. Việc này là cần thiết trong một số trường hợp, thay vì phải khởi tạo ra figure mới để vẽ lên. Có 3 cách để xóa nội dung của một figure. Giả sử ta cần xóa nội dung của fig:
  • fig.clf()
  • clear()
  • plt.clf()
Cách thứ nhất và thứ hai là hoàn toàn giống nhau, vì thực chất phương thức clear() sẽ gọi đến clf(). Cách thứ 3 chỉ có tác dụng khi fig đang active

7. Kết luận

Như vậy, bài viết giúp bạn ôn lại một số điểm quan trọng sau
  • Figure là đối tượng của python. Về mặt trực quan thì một figure là một cửa sổ chứa các hình vẽ
  • Figure có một hoặc nhiều axes - nơi thực sự các hình vẽ được "gắn" lên
  • Để lấy danh sách các axes của figure, ta gọi phương thức get_axes() từ đối tượng figure
  • Khi lưu hình vẽ bằng phương thức savefig, phải chú ý việc over-ride các thuộc tính của figure
  • Figure cho phép xóa các axes thuộc về nó bằng phương thức clear()

8. Tài liệu tham khảo

 
TEXmath
Cùng chủ đề