Гузариш ба мундариҷа
Мавзӯи 5 аз 5

Якчанд график дар як расм

Чаро якчанд графикро дар як расм мегузорем?

Дар ҳисобот аксар вақт чанд ҷанбаи маълумотро нишон додан лозим аст: тағйироти бузургӣ, тақсимоти он ва робитааш бо нишондиҳандаи дигар. Агар ҳама чизро дар як минтақа омезем, шкалаҳо ва номҳо ба ҳам халал мерасонанд. Якчанд минтақа дар як расм барои хондани паҳлу ба паҳлу ва нигоҳ доштани натиҷа дар як файл ёрӣ медиҳанд.

То ин дам функсияҳои plt.plot ва plt.title минтақаи ҷориро худашон интихоб мекарданд. Акнун ба минтақаи лозимӣ ошкоро муроҷиат мекунем. Ин кодро, махсусан дар даврҳо, пешгӯишаванда мекунад. Ҳар мисоли поён мустақил буда, баробари тасвир хосиятҳои расмро чоп мекунад.

1. Figure — варақ, Axes — минтақа

Figure тамоми расм аст: андоза, сарлавҳаи умумӣ ва маҷмӯи минтақаҳо. Axes як минтақаи график бо шкалаҳо, хатҳо ва номҳои худ аст. Сарфи назар аз ҳарфи охирини s, як объекти Axes як минтақаро ифода мекунад, на массивро. Як меҳвари алоҳидаи шкала Axis ном дорад.

plt.subplots() расм ва минтақаро сохта, онҳоро ҳамчун ҷуфт бармегардонад. Методҳои кашидани минтақа plot, bar, hist, scatter ном доранд; методҳои танзим одатан аз set_ оғоз мешаванд.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 1], [3, 2])
ax.set_title("A")
ax.set_xlabel("x")
print(len(fig.axes))
print(ax.get_title(), ax.get_xlabel())

Натиҷа:

1
A x

fig.axes як минтақаро дар бар мегирад. ax методҳои set_title, set_xlabel, set_ylabel, set_xlim, set_ylim дорад. Масалан, ax.set_xlabel("x") танҳо минтақаи интихобшударо тағйир медиҳад, новобаста аз он ки pyplot кадом минтақаро ҷорӣ мешуморад.

2. Сатрҳо ва сутунҳои минтақаҳо

subplots(rows, columns) минтақаҳоро дар тӯри росткунҷа мегузорад. Барои тӯри дорои чанд сатр ва сутун axes массиви дученакаи numpy аст. Индексгузорӣ аз сифр сар мешавад: аввал сатр аз боло ба поён, баъд сутун аз чап ба рост.

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 2)
axes[0, 0].plot([2, 4])
axes[0, 1].bar(["A", "B"], [3, 5])
axes[1, 0].hist([1, 2, 2], bins=2)
axes[1, 1].scatter([0, 1], [4, 2])
print(axes.shape)
print(len(fig.axes))
print(len(axes[0, 0].lines), len(axes[1, 1].collections))

Натиҷа:

(2, 2)
4
1 1

Дар сатри боло хат ва сутунҳо, дар поён гистограмма ва нуқтаҳо ҳастанд. Индекси [1, 0] минтақаи поёни чапро ифода мекунад. Ҳар даъват танҳо бо объекти интихобшуда кор мекунад, бинобар ин намудҳои графикро озодона якҷо кардан мумкин аст.

3. Чаро шакли axes тағйир меёбад?

Бо танзимоти пешфарз subplots андозаҳои массивро, ки дарозиашон як аст, мебардорад. Ин рафтор squeeze ном дорад. Агар як сатр бошад, массиви якченака ҳосил мешавад; агар танҳо як минтақа бошад, худи объекти Axes бармегардад.

import matplotlib.pyplot as plt
from matplotlib.axes import Axes

fig, axes = plt.subplots(1, 3)
print(axes.shape)
fig, ax = plt.subplots(1, 1)
print(isinstance(ax, Axes))

Натиҷа:

(3,)
True

Шакли (3,) се элементро дар як андоза ифода мекунад. Чунин тӯрро кушодан қулай аст: fig, (left, middle, right) = plt.subplots(1, 3). Барои чанд сатр ва як сутун низ массиви якченака ҳосил мешавад: axes[0], axes[1] ва ғайра.

Агар код бояд бо андозаҳои гуногуни тӯр яксон кор кунад, бо squeeze=False нигоҳ доштани ҳар ду андозаро дархост кунед. Хосияти flat имкон медиҳад, ки ҳамаи минтақаҳои массивро пайдарпай гузарем.

import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, squeeze=False)
for i, ax in enumerate(axes.flat):
    ax.set_title(str(i))
print(axes.shape)
print([ax.get_title() for ax in axes.flat])

Натиҷа:

(1, 2)
['0', '1']

Шакл ҳамеша дученака аст: ҳатто барои як минтақа (1, 1) мешавад. Дар массиви дученака ба минтақа бо axes[row, column] ё axes[row][column] муроҷиат мекунанд. axes.flat тӯрро сатр ба сатр аз чап ба рост мегузарад.

4. Шкалаи умумӣ барои муқоиса

sharex=True меҳварҳои уфуқии минтақаҳоро мепайвандад, sharey=True амудиро. Ин вақте муфид аст, ки мавқеъ ё баландии якхела дар ҳамаи графикҳо бояд як бузургиро ифода кунад. Меҳварҳои пайвастшуда худи хатҳоро якҷо намекунанд.

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 1, sharex=True)
axes[0].plot([2, 8], [1, 3])
axes[1].plot([2, 8], [5, 4])
axes[0].set_xlim(2, 8)
print(axes[0].get_xlim())
print(axes[1].get_xlim())

Натиҷа:

(2.0, 8.0)
(2.0, 8.0)

Тағйири ҳудудҳои минтақаи боло ба минтақаи поён низ таъсир кард. Ҳар яке қиматҳои y-и худро нигоҳ дошт. Барои меҳварҳои умумӣ matplotlib метавонад номҳои такрории аломатҳои шкаларо пинҳон кунад, то тӯр сербор нашавад.

5. Андоза, сарлавҳаи умумӣ ва нигоҳдорӣ

figsize=(width, height) андозаи тамоми варақро бо дюйм муайян мекунад. fig.suptitle сарлавҳаи умумӣ ва ax.set_title сарлавҳаи минтақаи алоҳидаро мегузорад. fig.tight_layout() фосилаҳои байни минтақаҳо ва номҳои онҳоро танзим мекунад.

Дар мисоли навбатӣ тасвир дар хотира, дар BytesIO, нигоҳ дошта мешавад, то андозаро бе сохтани файл санҷем. dpi шумораи пикселҳо дар як дюйм аст; ҳангоми нигоҳдорӣ бо сарҳадҳои одӣ паҳноӣ ва баландӣ бо пиксел ба андозаи дюймӣ зарб ба dpi баробар аст.

from io import BytesIO
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(5, 2))
ax.plot([0, 1], [3, 2])
fig.suptitle("Шарҳ")
fig.tight_layout()
buffer = BytesIO()
fig.savefig(buffer, format="png", dpi=100)
buffer.seek(0)
image = mpimg.imread(buffer)
print(fig.get_size_inches().tolist())
print(image.shape[:2])

Натиҷа:

[5.0, 2.0]
(200, 500)

Массиви тасвир аввал баландӣ ва баъд паҳноиро нигоҳ медорад: (200, 500) маънои 200 сатр ва 500 сутуни пикселҳоро дорад. Барои файли одӣ ба ҷойи buffer роҳ диҳед: fig.savefig("report.png", dpi=100). Параметри bbox_inches="tight" метавонад ҳошияҳоро бурад ва андозаи ниҳоиро бо пиксел тағйир диҳад.

Агар сарлавҳаи умумӣ ё номҳои дароз боз ҳам рӯйи ҳам оянд, андозаи расмро зиёд кунед ё бо fig.tight_layout(rect=(0, 0, 1, 0.9)) ҷойи иловагӣ монед. Роҳи дигар интихоби layout="constrained" ҳангоми сохтани расм аст; ин механизми алоҳидаи ҷойгиркунӣ мебошад ва онро бо tight_layout якҷо кардан лозим нест.

Дар дохил чӣ рӯй медиҳад?

Figure рӯйхати минтақаҳоро нигоҳ медорад ва ҳар Axes хатҳо, маҷмӯаҳои нуқтаҳо, росткунҷаҳо ва матнҳои худро дорад. subplots мавқеи минтақаҳоро дар тӯр ҳисоб карда, истинодҳои онҳоро бармегардонад. Массиви axes роҳи қулайи гирифтани истиноди зарурӣ аст, на худи тасвир.

Функсияҳои pyplot ба расм ва минтақаи ҷорӣ муроҷиат мекунанд: онҳоро бо plt.gcf() ва plt.gca() гирифтан мумкин аст. Методҳои ax объектро ошкоро интихоб мекунанд, бинобар ин аз ивази тасодуфии минтақаи ҷорӣ вобаста нестанд. Ҳангоми нигоҳдорӣ fig.savefig ҳамаи минтақаҳои ҳамин Figure-ро якҷо мекашад. Дар барномаҳои дароз расмҳои нолозимро бо plt.close(fig) пӯшида, захираҳоро озод мекунанд.

Хатоҳои маъмул ва ислоҳи онҳо

  1. Индексгузории минтақаи ягона. Пас аз fig, axes = plt.subplots(1, 1) ифодаи axes[0] хатои TypeError медиҳад. Ислоҳ: объектро мустақим истифода баред ё аз аввал squeeze=False интихоб карда, бо [0, 0] муроҷиат кунед.
  2. Шумораи нодурусти индексҳо. Пас аз plt.subplots(2, 2) ифодаи axes[0].plot(...) ба массиви сатр муроҷиат карда, AttributeError медиҳад. Ислоҳ: минтақаро бо ду индекс, масалан axes[0, 1], интихоб кунед.
  3. Сарлавҳа дар минтақаи тасодуфӣ. plt.title("A") графики ҷориро тағйир медиҳад, ки метавонад дигар бошад. Ислоҳ: барои минтақаи интихобшуда ax.set_title("A") ё барои тамоми расм fig.suptitle("A") истифода баред.
  4. Пиксел ба ҷойи дюйм. figsize=(500, 200) варақи азим месозад, на тасвири 500 × 200 пиксел. Ислоҳ: ҳангоми dpi=100 аз figsize=(5, 2) истифода бурда, бо ҳамон dpi нигоҳ доред.

Ёддошт

Амал Навишт
Як минтақа fig, ax = plt.subplots()
Тӯр fig, axes = plt.subplots(rows, columns)
Ҳамеша массиви дученака squeeze=False
Интихоб ва гузариш axes[row, column], axes.flat
Танзими минтақа ax.set_title(...), ax.set_xlabel(...)
Шкалаҳои умумӣ sharex=True, sharey=True
Андоза ва сарлавҳаи умумӣ figsize=(w, h), fig.suptitle(...)
Фосилаҳо ва файл fig.tight_layout(), fig.savefig(...)