Hướng dẫn dùng plt tight_layout python



Các khóa học miễn phí qua video:
Lập trình C Java C# SQL Server PHP HTML5-CSS3-JavaScript

Mục lục bài viết:

  • Tại sao Matplotlib có thể gây nhầm lẫn?
  • Pylab: Nó là gì, và tôi có nên sử dụng nó không?
  • Cấu trúc phân cấp đối tượng Matplotlib
  • Phương pháp tiếp cận hợp lệ so với không có trạng thái
  • Hiểu ký hiệu plt.subplots ()
  • "Hình" đằng sau hậu trường
  • A Burst of Color: imshow () và matshow ()
  • Âm mưu trong gấu trúc
  • Kết thúc
  • Nhiêu tai nguyên hơn
  • Phụ lục A: Cấu hình và kiểu dáng
  • Phụ lục B: Chế độ tương tác

Nội dung chính

  • Mục lục bài viết:
  • Tại sao Matplotlib có thể gây nhầm lẫn?
  • Pylab: Nó là gì, và tôi có nên sử dụng nó không?
  • Cấu trúc phân cấp đối tượng Matplotlib
  • Phương pháp tiếp cận hợp lệ so với không có trạng thái
  • Hiểu plt.subplots()ký hiệu
  • "Hình" đằng sau hậu trường
  • Một sự bùng nổ của màu sắc: imshow()vàmatshow()
  • Âm mưu trong gấu trúc
  • Kết thúc
  • Nhiêu tai nguyên hơn
  • Phụ lục A: Cấu hình và kiểu dáng
  • Phụ lục B: Chế độ tương tác


Một bức tranh có giá trị bằng một nghìn từ và với thư viện matplotlib của Python , may mắn thay chỉ cần ít hơn một nghìn từ mã để tạo ra một đồ họa có chất lượng sản xuất.

Tuy nhiên, matplotlib cũng là một thư viện lớn, và việc có được một cốt truyện trông vừa phải thường đạt được thông qua quá trình thử và sai. Sử dụng một lớp lót để tạo ra các ô cơ bản trong matplotlib khá đơn giản, nhưng việc điều khiển 98% thư viện còn lại một cách khéo léo có thể khiến bạn nản lòng.

Bài viết này là hướng dẫn trình độ sơ cấp đến trung cấp về matplotlib kết hợp lý thuyết với các ví dụ. Mặc dù việc học bằng ví dụ có thể cực kỳ sâu sắc, nhưng nó cũng giúp bạn có được hiểu biết thậm chí chỉ ở mức độ bề mặt về hoạt động bên trong và cách bố trí của thư viện.

Đây là những gì chúng tôi sẽ đề cập đến:

  • Pylab và pyplot: cái nào?
  • Các khái niệm chính về thiết kế của matplotlib
  • Hiểu biết plt.subplots()
  • Hình dung mảng với matplotlib
  • Mưu đồ với sự kết hợp gấu trúc + matplotlib

Phần thưởng miễn phí: Nhấp vào đây để tải xuống 5 ví dụ Python + Matplotlib với mã nguồn đầy đủ mà bạn có thể sử dụng làm cơ sở để tạo các âm mưu và đồ họa của riêng mình.

Bài viết này giả định rằng người dùng biết một chút về NumPy. Chúng tôi sẽ chủ yếu sử dụng numpy.randommô-đun để tạo dữ liệu "đồ chơi", lấy mẫu từ các phân phối thống kê khác nhau .

Nếu bạn chưa có matplotlib cài đặt, xem ở đây cho một hướng trước khi tiếp tục.

Tại sao Matplotlib có thể gây nhầm lẫn?

Học matplotlib đôi khi có thể là một quá trình khó chịu. Vấn đề không phải là tài liệu của matplotlib thiếu: tài liệu thực sự rất phong phú. Nhưng những vấn đề sau có thể gây ra một số thách thức:

  • Bản thân thư viện rất lớn, với tổng số 70.000 dòng mã.
  • Matplotlib là nơi có nhiều giao diện khác nhau (cách xây dựng một hình vẽ) và có khả năng tương tác với một số ít các phần mềm phụ trợ khác nhau. (Phần phụ trợ xử lý quá trình biểu đồ thực sự được hiển thị như thế nào, không chỉ được cấu trúc bên trong.)
  • Trong khi đó là toàn diện, một số tài liệu công khai của riêng matplotlib là nghiêm túc out-of-date . Thư viện vẫn đang phát triển và nhiều ví dụ cũ hơn trôi nổi trên mạng có thể mất ít hơn 70% dòng mã trong phiên bản hiện đại của chúng.

Vì vậy, trước khi chúng ta đi đến bất kỳ ví dụ rối mắt nào, sẽ rất hữu ích nếu bạn nắm được các khái niệm cốt lõi về thiết kế của matplotlib.

Pylab: Nó là gì, và tôi có nên sử dụng nó không?

Hãy bắt đầu với một chút lịch sử: John D. Hunter, một nhà sinh học thần kinh, bắt đầu phát triển matplotlib vào khoảng năm 2003, ban đầu lấy cảm hứng để mô phỏng các lệnh từ phần mềm MATLAB của Mathworks . John đã qua đời một cách bi thảm ở tuổi 44 vào năm 2012, và matplotlib hiện là một nỗ lực toàn diện của cộng đồng, được phát triển và duy trì bởi nhiều người khác. (John đã nói về sự phát triển của matplotlib tại hội nghị SciPy 2012, rất đáng để xem.)

Một tính năng có liên quan của MATLAB là phong cách toàn cầu của nó. Khái niệm Python về nhập không được sử dụng nhiều trong MATLAB và hầu hết các hàm của MATLAB đều có sẵn cho người dùng ở cấp cao nhất.

Biết rằng matplotlib có nguồn gốc từ MATLAB giúp giải thích tại sao pylab tồn tại. pylab là một mô-đun trong thư viện matplotlib được xây dựng để bắt chước phong cách toàn cầu của MATLAB. Nó chỉ tồn tại để đưa một số hàm và lớp từ cả NumPy và matplotlib vào không gian tên , tạo sự chuyển đổi dễ dàng cho những người dùng MATLAB trước đây, những người không quen cần các importcâu lệnh.

Những người chuyển đổi Ex-MATLAB (tất cả đều là những người tốt, tôi hứa!) Thích chức năng này, bởi vì với from pylab import *, họ có thể chỉ cần gọi plot()hoặc array()trực tiếp, như họ làm trong MATLAB.

Vấn đề ở đây có thể rõ ràng đối với một số người dùng Python: sử dụng from pylab import *trong một phiên hoặc tập lệnh nói chung là một phương pháp không tốt. Matplotlib hiện trực tiếp đưa ra lời khuyên chống lại điều này trong các hướng dẫn của riêng mình:

“[Pylab] vẫn tồn tại vì lý do lịch sử, nhưng nó được khuyến cáo không nên sử dụng. Nó gây ô nhiễm không gian tên với các chức năng sẽ che khuất các tích hợp sẵn của Python và có thể dẫn đến các lỗi khó theo dõi. Để có được tích hợp IPython mà không cần nhập khẩu, việc sử dụng %matplotlibphép thuật được ưu tiên hơn. " [ Nguồn ]

Trong nội bộ, có rất nhiều hàng nhập khẩu tiềm ẩn xung đột đang được che đậy trong nguồn pylab ngắn hạn . Trên thực tế, việc sử dụng ipython --pylab(từ terminal / dòng lệnh) hoặc %pylab(từ các công cụ IPython / Jupyter) chỉ đơn giản là gọi ẩn from pylab import *.

Điểm mấu chốt là matplotlib đã từ bỏ mô-đun tiện lợi này và giờ đây khuyến nghị rõ ràng không nên sử dụng pylab, đưa mọi thứ phù hợp hơn với một trong những quan niệm chính của Python: rõ ràng tốt hơn ẩn.

Không cần đến pylab, chúng ta thường có thể thoát khỏi chỉ với một lần nhập chính tắc:

>>>

>>> import matplotlib.pyplot as plt

Trong khi chúng ta đang ở đó, hãy cũng nhập NumPy, mà chúng ta sẽ sử dụng để tạo dữ liệu sau này và gọi np.random.seed()để tạo các ví dụ với dữ liệu ngẫu nhiên (giả) có thể tái tạo:

>>>

>>> import numpy as np
>>> np.random.seed(444)

Cấu trúc phân cấp đối tượng Matplotlib

Một khái niệm matplotlib ảnh lớn quan trọng là hệ thống phân cấp đối tượng của nó.

Nếu bạn đã làm việc qua bất kỳ hướng dẫn matplotlib giới thiệu nào, bạn có thể gọi một cái gì đó như thế plt.plot([1, 2, 3]). Một lớp lót này che giấu thực tế rằng một âm mưu thực sự là một hệ thống phân cấp của các đối tượng Python lồng nhau. “Hệ thống phân cấp” ở đây có nghĩa là có một cấu trúc giống như cây của các đối tượng matplotlib bên dưới mỗi âm mưu.

Một Figuređối tượng là vùng chứa ngoài cùng cho đồ họa matplotlib, có thể chứa nhiều Axesđối tượng. Một nguồn gây nhầm lẫn là tên: một Axesthực sự chuyển thành những gì chúng ta nghĩ về một âm mưu hoặc đồ thị riêng lẻ (thay vì số nhiều của "trục", như chúng ta có thể mong đợi).

Bạn có thể coi Figuređối tượng như một thùng chứa giống như hộp chứa một hoặc nhiều Axes(ô thực tế). Bên dưới Axestrong hệ thống phân cấp là các đối tượng nhỏ hơn như dấu tích, dòng riêng lẻ, chú giải và hộp văn bản. Hầu hết mọi “phần tử” của biểu đồ đều là đối tượng Python có thể thao tác của riêng nó, tất cả các dấu tích và nhãn:

Hướng dẫn dùng plt tight_layout python

Đây là một minh họa về hệ thống phân cấp này đang hoạt động. Đừng lo lắng nếu bạn không hoàn toàn quen thuộc với ký hiệu này, mà chúng tôi sẽ đề cập sau:

>>>

>>> fig, _ = plt.subplots()
>>> type(fig)
<class 'matplotlib.figure.Figure'>

Ở trên, chúng tôi đã tạo hai biến với plt.subplots(). Đầu tiên là một Figuređối tượng cấp cao nhất . Biến thứ hai là một biến "tiện ích" mà chúng ta chưa cần, được biểu thị bằng dấu gạch dưới. Bằng cách sử dụng ký hiệu thuộc tính, thật dễ dàng để duyệt qua phân cấp hình và xem dấu tích đầu tiên trên trục y của đối tượng Axes đầu tiên:

>>>

>>> one_tick = fig.axes[0].yaxis.get_major_ticks()[0]
>>> type(one_tick)
<class 'matplotlib.axis.YTick'>

Ở trên, fig(một Figurecá thể lớp) có nhiều Axes(một danh sách, mà chúng tôi lấy phần tử đầu tiên). Mỗi cái Axescó một yaxisvà xaxis, mỗi cái đều có một bộ sưu tập các "bọ ve chính", và chúng tôi lấy cái đầu tiên.

Matplotlib trình bày điều này như một giải phẫu hình người, chứ không phải là một hệ thống phân cấp rõ ràng:

(Theo phong cách matplotlib thực sự, hình trên được tạo trong tài liệu matplotlib ở đây .)

Phương pháp tiếp cận hợp lệ so với không có trạng thái

Được rồi, chúng ta cần thêm một phần lý thuyết nữa trước khi có thể hình dung rõ ràng: sự khác biệt giữa giao diện trạng thái (dựa trên trạng thái, máy trạng thái) và không trạng thái ( hướng đối tượng , OO).

Ở trên, chúng tôi đã sử dụng import matplotlib.pyplot as pltđể nhập mô-đun pyplot từ matplotlib và đặt tên cho nó plt.

Hầu như tất cả các hàm từ pyplot, chẳng hạn như plt.plot(), đều ngầm hiểu hoặc tham chiếu đến một Hình hiện tại và các Trục hiện tại, hoặc tạo lại chúng nếu không tồn tại. Ẩn trong các tài liệu matplotlib là đoạn mã hữu ích này:

“[Với pyplot], các hàm đơn giản được sử dụng để thêm các phần tử cốt truyện (đường, hình ảnh, văn bản, v.v.) vào các trục hiện tại trong hình hiện tại .” [nhấn mạnh thêm]

Những người dùng Hardcore cũ-MATLAB có thể chọn từ này bằng cách nói điều gì đó như, “ plt.plot()là một giao diện máy trạng thái ngầm theo dõi con số hiện tại!” Trong tiếng Anh, điều này có nghĩa là:

  • Giao diện trạng thái thực hiện các cuộc gọi của nó với plt.plot()và các hàm pyplot cấp cao nhất khác. Chỉ có một Hình hoặc Trục mà bạn đang thao tác tại một thời điểm nhất định và bạn không cần phải đề cập đến nó một cách rõ ràng.
  • Sửa đổi các đối tượng bên dưới một cách trực tiếp là cách tiếp cận hướng đối tượng. Chúng ta thường thực hiện việc này bằng cách gọi các phương thức của một Axesđối tượng, đối tượng này chính là đối tượng đại diện cho một âm mưu.

Luồng của quá trình này, ở mức cao, trông như thế này:

Liên kết chúng lại với nhau, hầu hết các hàm từ pyplot cũng tồn tại dưới dạng các phương thức của matplotlib.axes.Axeslớp.

Điều này dễ dàng nhận thấy hơn bằng cách nhìn vào bên dưới mui xe. plt.plot()có thể rút gọn xuống năm dòng mã hoặc lâu hơn:

>>>

# matplotlib/pyplot.py
>>> def plot(*args, **kwargs):
...     """An abridged version of plt.plot()."""
...     ax = plt.gca()
...     return ax.plot(*args, **kwargs)

>>> def gca(**kwargs):
...     """Get the current Axes of the current Figure."""
...     return plt.gcf().gca(**kwargs)

Gọi plt.plot()chỉ là một cách thuận tiện để lấy Axes hiện tại của Hình hiện tại và sau đó gọi plot()phương thức của nó . Điều này có nghĩa là khẳng định rằng giao diện trạng thái luôn "theo dõi ngầm" cốt truyện mà nó muốn tham chiếu.

pyplot là nơi có một loạt các chức năng thực sự chỉ là trình bao bọc xung quanh giao diện hướng đối tượng của matplotlib. Ví dụ, với plt.title(), có các phương thức setter và getter tương ứng trong cách tiếp cận OO, ax.set_title()và ax.get_title(). (Sử dụng getters và setters có xu hướng phổ biến hơn trong các ngôn ngữ như Java nhưng là một tính năng chính của phương pháp OO của matplotlib.)

Kêu gọi plt.title()được dịch sang dòng này: gca().set_title(s, *args, **kwargs). Đây là những gì nó đang làm:

  • gca() lấy trục hiện tại và trả về nó.
  • set_title()là một phương thức setter đặt tiêu đề cho đối tượng Axes đó. “Sự tiện lợi” ở đây là chúng ta không cần phải chỉ định rõ ràng bất kỳ đối tượng Axes nào plt.title().

Tương tự, nếu bạn dành một chút thời gian để xem nguồn cho các hàm cấp cao nhất như plt.grid()plt.legend()và plt.ylabels(), bạn sẽ nhận thấy rằng tất cả chúng đều tuân theo cùng một cấu trúc ủy quyền cho các Axes hiện tại gca()và sau đó gọi một số phương thức của hiện tại Rìu. (Đây là cách tiếp cận hướng đối tượng cơ bản!)

Hiểu plt.subplots()ký hiệu

Được rồi, đủ lý thuyết. Bây giờ, chúng tôi đã sẵn sàng để gắn kết mọi thứ lại với nhau và thực hiện một số âm mưu. Kể từ đây trở đi, chúng ta sẽ chủ yếu dựa vào cách tiếp cận không trạng thái (hướng đối tượng), có thể tùy chỉnh nhiều hơn và có ích khi đồ thị trở nên phức tạp hơn.

Cách quy định để tạo một Hình có một Trục theo cách tiếp cận OO là (không quá trực quan) với plt.subplots(). Đây thực sự là lần duy nhất mà phương pháp OO sử dụng pyplot, để tạo Hình và Trục:

>>>

>>> fig, ax = plt.subplots()

Ở trên, chúng tôi đã tận dụng khả năng giải nén có thể lặp lại để gán một biến riêng biệt cho từng kết quả trong số hai kết quả của plt.subplots(). Lưu ý rằng chúng tôi đã không chuyển các đối số đến subplots()đây. Cuộc gọi mặc định là subplots(nrows=1, ncols=1). Do đó, axlà một AxesSubplotđối tượng duy nhất :

>>>

>>> type(ax)
<class 'matplotlib.axes._subplots.AxesSubplot'>

Chúng ta có thể gọi các phương thức thể hiện của nó để thao tác với âm mưu tương tự như cách chúng ta gọi các hàm pyplots. Hãy minh họa bằng biểu đồ diện tích xếp chồng lên nhau của ba chuỗi thời gian:

>>>

>>> rng = np.arange(50)
>>> rnd = np.random.randint(0, 10, size=(3, rng.size))
>>> yrs = 1950 + rng

>>> fig, ax = plt.subplots(figsize=(5, 3))
>>> ax.stackplot(yrs, rng + rnd, labels=['Eastasia', 'Eurasia', 'Oceania'])
>>> ax.set_title('Combined debt growth over time')
>>> ax.legend(loc='upper left')
>>> ax.set_ylabel('Total debt')
>>> ax.set_xlim(xmin=yrs[0], xmax=yrs[-1])
>>> fig.tight_layout()

Đây là những gì đang xảy ra ở trên:

  • Sau khi tạo ba chuỗi thời gian ngẫu nhiên, chúng tôi xác định một Hình ( fig) chứa một Trục (một biểu đồ, ax).

  • Chúng tôi gọi các phương thức axtrực tiếp để tạo biểu đồ vùng xếp chồng và thêm chú giải, tiêu đề và nhãn trục y. Theo cách tiếp cận hướng đối tượng, rõ ràng rằng tất cả những điều này đều là thuộc tính của ax.

  • tight_layout() áp dụng cho toàn bộ đối tượng Hình để làm sạch vùng đệm khoảng trắng.

Hãy xem một ví dụ với nhiều ô con (Axes) trong một Hình, vẽ hai mảng tương quan được vẽ từ phân phối đồng nhất rời rạc :

>>>

>>> x = np.random.randint(low=1, high=11, size=50)
>>> y = x + np.random.randint(1, 5, size=x.size)
>>> data = np.column_stack((x, y))

>>> fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2,
...                                figsize=(8, 4))

>>> ax1.scatter(x=x, y=y, marker='o', c='r', edgecolor='b')
>>> ax1.set_title('Scatter: $x$ versus $y$')
>>> ax1.set_xlabel('$x$')
>>> ax1.set_ylabel('$y$')

>>> ax2.hist(data, bins=np.arange(data.min(), data.max()),
...          label=('x', 'y'))
>>> ax2.legend(loc=(0.65, 0.8))
>>> ax2.set_title('Frequencies of $x$ and $y$')
>>> ax2.yaxis.tick_right()

Có một chút nữa đang diễn ra trong ví dụ này:

  • Vì chúng ta đang tạo một Hình “1x2”, kết quả trả về plt.subplots(1, 2)bây giờ là một đối tượng Hình và một mảng NumPy gồm các đối tượng Axes. (Bạn có thể kiểm tra điều này với fig, axs = plt.subplots(1, 2)và xem xét axs.)

  • Chúng tôi giải quyết ax1và xử lý ax2riêng lẻ, điều này sẽ khó thực hiện với cách tiếp cận trạng thái. Dòng cuối cùng là một minh họa tốt về hệ thống phân cấp đối tượng, nơi chúng tôi đang sửa đổi phần yaxisthuộc về Trục thứ hai, đặt các dấu tích và dấu tích của nó ở bên phải.

  • Văn bản bên trong ký hiệu đô la sử dụng đánh dấu TeX để đặt các biến ở dạng nghiêng.

Hãy nhớ rằng nhiều Trục có thể nằm trong hoặc “thuộc” một hình nhất định. Trong trường hợp trên, fig.axeshãy cho chúng tôi danh sách tất cả các đối tượng Axes:

>>>

>>> (fig.axes[0] is ax1, fig.axes[1] is ax2)
(True, True)

fig.axeslà chữ thường, không phải chữ hoa. Không thể phủ nhận thuật ngữ này hơi khó hiểu.)

Tiến thêm một bước này nữa, chúng ta có thể tạo một hình khác chứa lưới 2x2 các Axesđối tượng:

>>>

>>> fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(7, 7))

Bây giờ, là axgì? Nó không còn là một Axesmảng đơn lẻ , mà là một mảng NumPy hai chiều của chúng:

>>>

>>> type(ax)
numpy.ndarray

>>> ax
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1106daf98>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x113045c88>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x11d573cf8>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x1130117f0>]],
      dtype=object)

>>> ax.shape
(2, 2)

Điều này được xác nhận lại bởi docstring:

axCó thể là một matplotlib.axes.Axesđối tượng đơn lẻ hoặc một mảng Axesđối tượng nếu nhiều vùng phụ được tạo."

Bây giờ chúng ta cần gọi các phương thức vẽ biểu đồ trên mỗi phương thức này Axes(nhưng không phải là mảng NumPy, chỉ là một vùng chứa trong trường hợp này). Một cách phổ biến để giải quyết vấn đề này là sử dụng giải nén có thể lặp lại sau khi làm phẳng mảng thành một chiều:

>>>

>>> fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(7, 7))
>>> ax1, ax2, ax3, ax4 = ax.flatten()  # flatten a 2d NumPy array to 1d

Chúng tôi cũng có thể làm điều này với ((ax1, ax2), (ax3, ax4)) = ax, nhưng cách tiếp cận đầu tiên có xu hướng linh hoạt hơn.

Để minh họa cho một số tính năng âm mưu phụ cao cấp hơn, chúng ta hãy kéo một số California dữ liệu nhà ở kinh tế vĩ mô được chiết xuất từ một kho lưu trữ tar nén, sử dụng iotarfilevà urllibtừ thư viện chuẩn của Python.

>>>

>>> from io import BytesIO
>>> import tarfile
>>> from urllib.request import urlopen

>>> url = 'http://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz'
>>> b = BytesIO(urlopen(url).read())
>>> fpath = 'CaliforniaHousing/cal_housing.data'

>>> with tarfile.open(mode='r', fileobj=b) as archive:
...     housing = np.loadtxt(archive.extractfile(fpath), delimiter=',')

Biến "phản hồi" ybên dưới, để sử dụng thuật ngữ thống kê, là giá trị nhà trung bình của khu vực. popvà agelần lượt là dân số và tuổi nhà trung bình của khu vực:

>>>

>>> y = housing[:, -1]
>>> pop, age = housing[:, [4, 7]].T

Tiếp theo, hãy xác định một "chức năng trợ giúp" đặt một hộp văn bản bên trong một âm mưu và hoạt động như một "tiêu đề trong sơ đồ":

>>>

>>> def add_titlebox(ax, text):
...     ax.text(.55, .8, text,
...         horizontalalignment='center',
...         transform=ax.transAxes,
...         bbox=dict(facecolor='white', alpha=0.6),
...         fontsize=12.5)
...     return ax

Chúng tôi đã sẵn sàng để thực hiện một số âm mưu. gridspecMô-đun của Matplotlib cho phép tùy chỉnh subplot nhiều hơn. pyplot's subplot2grid()tương tác độc đáo với mô-đun này. Giả sử chúng tôi muốn tạo một bố cục như thế này:

Ở trên, những gì chúng ta thực sự có là một lưới 3x2. ax1gấp đôi chiều cao và chiều rộng của ax2ax3, nghĩa là nó chiếm hai cột và hai hàng.

Đối số thứ hai subplot2grid()là vị trí (hàng, cột) của Axes trong lưới:

>>>

>>> gridsize = (3, 2)
>>> fig = plt.figure(figsize=(12, 8))
>>> ax1 = plt.subplot2grid(gridsize, (0, 0), colspan=2, rowspan=2)
>>> ax2 = plt.subplot2grid(gridsize, (2, 0))
>>> ax3 = plt.subplot2grid(gridsize, (2, 1))

Bây giờ, chúng ta có thể tiến hành như bình thường, sửa đổi từng Axes riêng lẻ:

>>>

>>> ax1.set_title('Home value as a function of home age & area population',
...               fontsize=14)
>>> sctr = ax1.scatter(x=age, y=pop, c=y, cmap='RdYlGn')
>>> plt.colorbar(sctr, ax=ax1, format='$%d')
>>> ax1.set_yscale('log')
>>> ax2.hist(age, bins='auto')
>>> ax3.hist(pop, bins='auto', log=True)

>>> add_titlebox(ax2, 'Histogram: home age')
>>> add_titlebox(ax3, 'Histogram: area population (log scl.)')

Ở trên, colorbar()(khác với ColorMap trước đó) được gọi trực tiếp trên Hình, thay vì Axes. Đối số đầu tiên của nó sử dụng Matplotlib's .scatter()và là kết quả của nó ax1.scatter(), có chức năng như một ánh xạ các giá trị y vào ColorMap.

Nhìn bằng mắt thường, không có nhiều sự khác biệt về màu sắc (biến y) khi chúng ta di chuyển lên và xuống trục y, cho thấy rằng tuổi nhà dường như là yếu tố quyết định mạnh mẽ hơn giá trị căn nhà.

"Hình" đằng sau hậu trường

Mỗi lần bạn gọi plt.subplots()hoặc ít được sử dụng hơn plt.figure()(tạo một Hình, không có Trục), bạn đang tạo một đối tượng Hình mới mà matplotlib lén lút lưu giữ trong bộ nhớ. Trước đó, chúng ta đã đề cập đến khái niệm Hình hiện tại và Trục hiện tại. Theo mặc định, đây là các Hình và Trục được tạo gần đây nhất, chúng ta có thể hiển thị bằng hàm tích hợp id()để hiển thị địa chỉ của đối tượng trong bộ nhớ:

>>>

>>> fig1, ax1 = plt.subplots()

>>> id(fig1)
4525567840

>>> id(plt.gcf())  # `fig1` is the current figure.
4525567840

>>> fig2, ax2 = plt.subplots()
>>> id(fig2) == id(plt.gcf())  # The current figure has changed to `fig2`.
True

(Chúng tôi cũng có thể sử dụng istoán tử tích hợp ở đây.)

Sau quy trình trên, hình hiện tại là hình fig2gần đây nhất được tạo ra. Tuy nhiên, cả hai số liệu vẫn còn quanh quẩn trong bộ nhớ, mỗi con số có một số ID tương ứng (được lập chỉ mục 1, theo kiểu MATLAB):

>>>

>>> plt.get_fignums()
[1, 2]

Một cách hữu ích để lấy tất cả các Hình là ánh xạ plt.figure()tới từng số nguyên sau:

>>>

>>> def get_all_figures():
...    return [plt.figure(i) for i in plt.get_fignums()]

>>> get_all_figures()
[<matplotlib.figure.Figure at 0x10dbeaf60>,
 <matplotlib.figure.Figure at 0x1234cb6d8>]

Hãy nhận biết điều này nếu chạy một tập lệnh mà bạn đang tạo một nhóm các số liệu. Bạn sẽ muốn đóng từng người một cách rõ ràng sau khi sử dụng để tránh a MemoryError. Tự nó, plt.close()đóng hình hiện tại, plt.close(num)đóng số hình numvà plt.close('all')đóng tất cả các cửa sổ hình:

>>>

>>> plt.close('all')
>>> get_all_figures()
[]

Một sự bùng nổ của màu sắc: imshow()vàmatshow()

Mặc dù ax.plot()là một trong những phương pháp vẽ âm mưu phổ biến nhất trên Axes, nhưng cũng có rất nhiều phương pháp khác. (Chúng tôi đã sử dụng ax.stackplot()ở trên. Bạn có thể tìm thấy danh sách đầy đủ tại đây .)

Các phương pháp được sử dụng nhiều là imshow()và matshow(), với cái sau là một lớp bao bọc xung quanh cái trước. Những điều này hữu ích bất cứ lúc nào mà một mảng số thô có thể được hình dung dưới dạng một lưới màu.

Đầu tiên, hãy tạo hai lưới riêng biệt với một số lập chỉ mục NumPy ưa thích:

>>>

>>> x = np.diag(np.arange(2, 12))[::-1]
>>> x[np.diag_indices_from(x[::-1])] = np.arange(2, 12)
>>> x2 = np.arange(x.size).reshape(x.shape)

Tiếp theo, chúng ta có thể ánh xạ những thứ này với biểu diễn hình ảnh của chúng. Trong trường hợp cụ thể này, chúng tôi tắt "tắt" tất cả các nhãn và dấu trục bằng cách sử dụng tính năng hiểu từ điển và chuyển kết quả tới ax.tick_params():

>>>

>>> sides = ('left', 'right', 'top', 'bottom')
>>> nolabels = {s: False for s in sides}
>>> nolabels.update({'label%s' % s: False for s in sides})
>>> print(nolabels)
{'left': False, 'right': False, 'top': False, 'bottom': False, 'labelleft': False,
 'labelright': False, 'labeltop': False, 'labelbottom': False}

Sau đó, chúng ta có thể sử dụng trình quản lý ngữ cảnh để tắt lưới và gọi matshow()từng Axes. Cuối cùng, chúng ta cần đặt thanh màu về mặt kỹ thuật là một Axes mới bên trong fig. Đối với điều này, chúng ta có thể sử dụng một chút chức năng bí truyền từ sâu bên trong matplotlib:

>>>

>>> from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable

>>> with plt.rc_context(rc={'axes.grid': False}):
...     fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))
...     ax1.matshow(x)
...     img2 = ax2.matshow(x2, cmap='RdYlGn_r')
...     for ax in (ax1, ax2):
...         ax.tick_params(axis='both', which='both', **nolabels)
...     for i, j in zip(*x.nonzero()):
...         ax1.text(j, i, x[i, j], color='white', ha='center', va='center')
...
...     divider = make_axes_locatable(ax2)
...     cax = divider.append_axes("right", size='5%', pad=0)
...     plt.colorbar(img2, cax=cax, ax=[ax1, ax2])
...     fig.suptitle('Heatmaps with `Axes.matshow`', fontsize=16)

Âm mưu trong gấu trúc

Thư viện gấu trúc đã trở nên phổ biến không chỉ để cho phép phân tích dữ liệu mạnh mẽ , mà còn cho các phương pháp vẽ biểu đồ đóng hộp sẵn tiện dụng của nó. Tuy nhiên, điều thú vị là các phương pháp lập biểu đồ của gấu trúc thực sự chỉ là những trình bao bọc thuận tiện xung quanh các lệnh gọi matplotlib hiện có.

Đó là, plot()phương thức trên Series và DataFrame của gấu trúc là một trình bao bọc xung quanh plt.plot(). Ví dụ, một tiện lợi được cung cấp là nếu Chỉ mục của DataFrame bao gồm ngày tháng, gcf().autofmt_xdate()được gọi nội bộ bởi gấu trúc để có được Hình hiện tại và tự động định dạng trục x một cách độc đáo.

Đổi lại, hãy nhớ rằng plt.plot()(cách tiếp cận dựa trên trạng thái) được hiểu ngầm về Hình hiện tại và các Trục hiện tại, vì vậy gấu trúc đang theo cách tiếp cận dựa trên trạng thái bằng cách mở rộng.

Chúng ta có thể chứng minh “chuỗi” các lệnh gọi hàm này bằng một chút xem xét nội tâm. Đầu tiên, hãy xây dựng một Series gấu trúc vani đơn giản, giả sử chúng ta đang bắt đầu trong một phiên phiên dịch mới:

>>>

>>> import pandas as pd

>>> s = pd.Series(np.arange(5), index=list('abcde'))
>>> ax = s.plot()

>>> type(ax)
<matplotlib.axes._subplots.AxesSubplot at 0x121083eb8>

>>> id(plt.gca()) == id(ax)
True

Kiến trúc nội bộ này rất hữu ích để biết khi nào bạn đang trộn các phương pháp vẽ biểu đồ gấu trúc với các lệnh gọi matplotlib truyền thống, được thực hiện bên dưới trong việc vẽ biểu đồ trung bình động của một chuỗi thời gian tài chính được theo dõi rộng rãi. malà Chuỗi gấu trúc mà chúng ta có thể gọi ma.plot()(phương thức gấu trúc), sau đó tùy chỉnh bằng cách truy xuất các Trục được tạo bởi lệnh gọi này ( plt.gca()), cho matplotlib để tham khảo:

>>>

>>> import pandas as pd
>>> import matplotlib.transforms as mtransforms

>>> url = 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=VIXCLS'
>>> vix = pd.read_csv(url, index_col=0, parse_dates=True, na_values='.',
...                   infer_datetime_format=True,
...                   squeeze=True).dropna()
>>> ma = vix.rolling('90d').mean()
>>> state = pd.cut(ma, bins=[-np.inf, 14, 18, 24, np.inf],
...                labels=range(4))

>>> cmap = plt.get_cmap('RdYlGn_r')
>>> ma.plot(color='black', linewidth=1.5, marker='', figsize=(8, 4),
...         label='VIX 90d MA')
>>> ax = plt.gca()  # Get the current Axes that ma.plot() references
>>> ax.set_xlabel('')
>>> ax.set_ylabel('90d moving average: CBOE VIX')
>>> ax.set_title('Volatility Regime State')
>>> ax.grid(False)
>>> ax.legend(loc='upper center')
>>> ax.set_xlim(xmin=ma.index[0], xmax=ma.index[-1])

>>> trans = mtransforms.blended_transform_factory(ax.transData, ax.transAxes)
>>> for i, color in enumerate(cmap([0.2, 0.4, 0.6, 0.8])):
...     ax.fill_between(ma.index, 0, 1, where=state==i,
...                     facecolor=color, transform=trans)
>>> ax.axhline(vix.mean(), linestyle='dashed', color='xkcd:dark grey',
...            alpha=0.6, label='Full-period mean', marker='')

Có rất nhiều điều xảy ra ở trên:

  • malà đường trung bình động trong 90 ngày của Chỉ số VIX, một thước đo kỳ vọng của thị trường về sự biến động cổ phiếu trong ngắn hạn. statelà sự phân chia của đường trung bình động vào các trạng thái chế độ khác nhau. VIX cao được coi là báo hiệu mức độ sợ hãi cao hơn trên thị trường.

  • cmaplà một ColorMap — một đối tượng matplotlib về cơ bản là một ánh xạ các điểm nổi sang các màu RGBA. Bất kỳ bản đồ màu nào cũng có thể được đảo ngược bằng cách thêm vào '_r''RdYlGn_r'bản đồ màu Đỏ-Vàng-Xanh được đảo ngược cũng vậy . Matplotlib duy trì một hướng dẫn tham khảo trực quan tiện dụng về ColorMaps trong tài liệu của mình.

  • Tiếng gọi gấu trúc thực duy nhất mà chúng tôi đang thực hiện ở đây là ma.plot(). Điều này gọi plt.plot()nội bộ, vì vậy để tích hợp cách tiếp cận hướng đối tượng, chúng ta cần có một tham chiếu rõ ràng đến các Axes hiện tại với ax = plt.gca().

  • Đoạn mã thứ hai tạo ra các khối tô màu tương ứng với mỗi thùng statecmap([0.2, 0.4, 0.6, 0.8])nói, “Hãy cho chúng tôi một chuỗi RGBA cho các màu ở 'phần trăm' thứ 20, 40, 60 và 80 dọc theo quang phổ của Bản đồ màu." enumerate()được sử dụng vì chúng tôi muốn ánh xạ từng màu RGBA trở lại trạng thái.

Pandas cũng được tích hợp sẵn với một loạt các âm mưu nâng cao hơn (có thể mất toàn bộ hướng dẫn của riêng chúng). Tuy nhiên, tất cả những thứ này, giống như các đối tác đơn giản hơn của chúng, đều dựa vào máy móc matplotlib bên trong.

Kết thúc

Như được thể hiện qua một số ví dụ ở trên, không có gì phải bàn cãi rằng matplotlib có thể là một thư viện nặng về cú pháp, kỹ thuật. Việc tạo một biểu đồ sẵn sàng sản xuất đôi khi đòi hỏi một nửa giờ sử dụng Google và kết hợp một loạt các đường để tinh chỉnh một cốt truyện.

Tuy nhiên, hiểu được cách các giao diện của matplotlib tương tác là một khoản đầu tư có thể mang lại hiệu quả. Như Dan Bader của Real Python đã khuyên, dành thời gian để phân tích mã thay vì dùng đến giải pháp “sao chép mì ống” của Stack Overflow có xu hướng là một giải pháp lâu dài thông minh hơn. Bám sát cách tiếp cận hướng đối tượng có thể tiết kiệm hàng giờ thất vọng khi bạn muốn đưa một cốt truyện từ đơn giản thành một tác phẩm nghệ thuật.

Nhiêu tai nguyên hơn

Từ tài liệu matplotlib:

  • Một chỉ mục của các ví dụ matplotlib
  • Câu hỏi thường gặp về sử dụng
  • Các hướng dẫn trang, được chia thành mới bắt đầu, trung cấp và phần tiên tiến
  • Vòng đời của một cốt truyện , liên quan đến các phương pháp tiếp cận hướng đối tượng so với trạng thái

Tài nguyên của bên thứ ba:

  • Bảng gian lận matplotlib của DataCamp
  • Sinh học tính toán PLOS: Mười quy tắc đơn giản để có số liệu tốt hơn
  • Chương 9 (Vẽ và Hình dung) trong Python của Wes McKinney để Phân tích Dữ liệu, xuất bản lần thứ 2.
  • Chaper 11 (Hình dung với Matplotlib, Pandas và Seaborn) của Ted Petrou's Pandas Cookbook
  • Phần 1.4 (Matplotlib: Vẽ sơ đồ) của Ghi chú bài giảng SciPy
  • Bảng màu xkcd
  • Trang tài nguyên bên ngoài matplotlib
  • Matplotlib, Pylab, Pyplot, v.v.: Sự khác biệt giữa chúng là gì và khi nào sử dụng mỗi loại? từ queirozf.com
  • Các hình dung trang trong tài liệu hướng gấu trúc

Các thư viện âm mưu khác:

  • Các sanh ở biển thư viện, được xây dựng trên đầu trang của matplotlib và được thiết kế cho đồ họa thống kê tiên tiến, có thể mất toàn bộ hướng dẫn tất cả các ngày của riêng mình
  • Datashader , một thư viện đồ họa đặc biệt hướng tới các bộ dữ liệu lớn
  • Danh sách các gói của bên thứ ba khác từ tài liệu matplotlib

Phụ lục A: Cấu hình và kiểu dáng

Nếu bạn đang làm theo hướng dẫn này, có khả năng là các ô hiện ra trên màn hình của bạn trông khác biệt so với các ô hiển thị ở đây.

Matplotlib cung cấp hai cách để định cấu hình kiểu một cách thống nhất trên các lô khác nhau:

  1. Bằng cách tùy chỉnh tệp matplotlibrc
  2. Bằng cách thay đổi các tham số cấu hình của bạn một cách tương tác hoặc từ một tập lệnh .py .

Tệp matplotlibrc (Tùy chọn # 1 ở trên) về cơ bản là một tệp văn bản chỉ định các cài đặt do người dùng tùy chỉnh được ghi nhớ giữa các phiên Python. Trên Mac OS X, điều này thường nằm ở ~ / .matplotlib / matplotlibrc .

Mẹo nhanh: GitHub là một nơi tuyệt vời để lưu giữ các tệp cấu hình. Tôi giữ của tôi ở đây . Chỉ cần đảm bảo rằng chúng không chứa thông tin nhận dạng cá nhân hoặc thông tin riêng tư, chẳng hạn như mật khẩu hoặc khóa riêng SSH!

Ngoài ra, bạn có thể thay đổi các thông số cấu hình của mình một cách tương tác (Tùy chọn # 2 ở trên). Khi bạn import matplotlib.pyplot as plt, bạn có quyền truy cập vào một rcParamsđối tượng giống như một từ điển Python về cài đặt. Tất cả các đối tượng mô-đun bắt đầu bằng “rc” là phương tiện để tương tác với các kiểu và cài đặt cốt truyện của bạn:

>>>

>>> [attr for attr in dir(plt) if attr.startswith('rc')]
['rc', 'rcParams', 'rcParamsDefault', 'rc_context', 'rcdefaults']

Trong số này:

  • plt.rcdefaults()khôi phục các tham số rc từ các giá trị mặc định bên trong của matplotlib, được liệt kê tại plt.rcParamsDefault. Thao tác này sẽ hoàn nguyên (ghi đè) bất cứ thứ gì bạn đã tùy chỉnh trong tệp matplotlibrc.
  • plt.rc() được sử dụng để thiết lập các tham số một cách tương tác.
  • plt.rcParamslà một đối tượng giống như từ điển (có thể thay đổi) cho phép bạn thao tác cài đặt trực tiếp. Nếu bạn đã tùy chỉnh cài đặt trong tệp matplotlibrc, những cài đặt này sẽ được phản ánh trong từ điển này.

Với plt.rc()và plt.rcParams, hai cú pháp này tương đương nhau để điều chỉnh cài đặt:

>>>

>>> plt.rc('lines', linewidth=2, color='r')  # Syntax 1

>>> plt.rcParams['lines.linewidth'] = 2  # Syntax 2
>>> plt.rcParams['lines.color'] = 'r'

Đáng chú ý, lớp Hình sau đó sử dụng một số trong số này làm đối số mặc định của nó.

Về mặt liên quan, một kiểu chỉ là một cụm cài đặt tùy chỉnh được xác định trước. Để xem các kiểu có sẵn, hãy sử dụng:

>>>

>>> plt.style.available
['seaborn-dark', 'seaborn-darkgrid', 'seaborn-ticks', 'fivethirtyeight',
 'seaborn-whitegrid', 'classic', '_classic_test', 'fast', 'seaborn-talk',
 'seaborn-dark-palette', 'seaborn-bright', 'seaborn-pastel', 'grayscale',
 'seaborn-notebook', 'ggplot', 'seaborn-colorblind', 'seaborn-muted',
 'seaborn', 'Solarize_Light2', 'seaborn-paper', 'bmh', 'seaborn-white',
 'dark_background', 'seaborn-poster', 'seaborn-deep']

Để thiết lập một kiểu, hãy thực hiện cuộc gọi này:

>>>

>>> plt.style.use('fivethirtyeight')

Các âm mưu của bạn bây giờ sẽ mang một diện mạo mới:

Ví dụ đầy đủ này có sẵn ở đây .

Để tạo cảm hứng, matplotlib cũng giữ một số hiển thị bảng định kiểu để tham khảo.

Phụ lục B: Chế độ tương tác

Đằng sau hậu trường, matplotlib cũng tương tác với các phụ trợ khác nhau. Một backend là workhorse đằng sau thực sự hiển thị một biểu đồ. (Ví dụ: trên bản phân phối Anaconda phổ biến, phần phụ trợ mặc định là Qt5Agg.) Một số phần phụ trợ có tính tương tác, nghĩa là chúng được cập nhật động và "bật lên" cho người dùng khi được thay đổi.

Mặc dù chế độ tương tác bị tắt theo mặc định, bạn có thể kiểm tra trạng thái của nó bằng plt.rcParams['interactive']hoặc plt.isinteractive(), và bật và tắt nó với plt.ion()và plt.ioff(), tương ứng:

>>>

>>> plt.rcParams['interactive']  # or: plt.isinteractive()
True

>>>

>>> plt.ioff()
>>> plt.rcParams['interactive']
False

Trong một số ví dụ mã, bạn có thể nhận thấy sự hiện diện plt.show()ở cuối một đoạn mã. Mục đích chính của plt.show(), như tên của nó, là thực sự “hiển thị” (mở) hình khi bạn đang chạy với chế độ tương tác bị tắt. Nói cách khác:

  • Nếu chế độ tương tác được bật, bạn không cần plt.show(), và hình ảnh sẽ tự động bật lên và được cập nhật khi bạn tham khảo chúng.
  • Nếu chế độ tương tác bị tắt, bạn sẽ cần plt.show()hiển thị một hình và plt.draw()cập nhật một cốt truyện.

Dưới đây, chúng tôi đảm bảo rằng chế độ tương tác đang tắt, điều này yêu cầu chúng tôi gọi plt.show()sau khi xây dựng cốt truyện:

>>>

>>> plt.ioff()
>>> x = np.arange(-4, 5)
>>> y1 = x ** 2
>>> y2 = 10 / (x ** 2 + 1)
>>> fig, ax = plt.subplots()
>>> ax.plot(x, y1, 'rx', x, y2, 'b+', linestyle='solid')
>>> ax.fill_between(x, y1, y2, where=y2>y1, interpolate=True,
...                 color='green', alpha=0.3)
>>> lgnd = ax.legend(['y1', 'y2'], loc='upper center', shadow=True)
>>> lgnd.get_frame().set_facecolor('#ffb19a')
>>> plt.show()

Đáng chú ý, chế độ tương tác không liên quan gì đến IDE bạn đang sử dụng hoặc liệu bạn có bật tính năng vẽ nội tuyến với một cái gì đó như jupyter notebook --matplotlib inlinehoặc hay không %matplotlib.


Các khóa học miễn phí qua video:
Lập trình C Java C# SQL Server PHP HTML5-CSS3-JavaScript
« Prev: Python: Tách tập dữ liệu của bạn với train_test_split() của scikit-learning
» Next: Python: Nhận dạng khuôn mặt với dưới 25 dòng mã Python

Copied !!!