Автор: Шабанов Павел Александрович
E-mail: [email protected]
URL: Заметки по программированию в науках о Земле
Дата последнего обновления: 12.03.2017
# Преамбула
%matplotlib inline
import os
import matplotlib.pyplot as plt
from matplotlib import rcParams
import numpy as np
def save(name='', fmt='png'):
pwd = os.getcwd()
iPath = './pictures/{}'.format(fmt)
if not os.path.exists(iPath):
os.mkdir(iPath)
os.chdir(iPath)
plt.savefig('{}.{}'.format(name, fmt), fmt='png')
os.chdir(pwd)
#plt.close()
rcParams['font.family'] = 'fantasy'
rcParams['font.fantasy'] = 'Arial'
Дополнительная координатная ось;
Работа с легендой дополнительной оси;
Единая легенда;
Графики с логарифмическими координатными осями.
Деления (ticks) неотделимы от координатной оси на которой они находятся. Однако свойства самих делений (цвет, длина, толщина и др.), и их подписей (кегль, поворот, цвет шрифта, шрифт и др.), а также связанные с ними линии вспомогательной сетки grid, удобно хранить в отдельном хранилище-контейнере Ticks, а не в контейнере Axis. Повторюсь, что эти вещи очень связаны и одно в отрыве от другого теряет смысл. Тем более, что для удобства пользователей разработчики сделали множество методов для работы с делениями из контейнеров более высокого уровня (Axes, Axis).
Иногда требуется нанести на один рисунок две величины, имеющие общие единицы измерения по одной оси, но разные по другой. Например, это могут быть временные ряды сильно отличающихся по масштабу величин. Или ряды величин, имеющих разные единицы измерения. В таких случаях удобно нарисовать дополнительную координатную ось (обычно - ординат).
Такую возможность обеспечивает метод ax.twinx() для оси OX и метод ax.twiny() для оси OY. В результате создаётся ещё одна область рисования, совпадающая по размерам с исходной. На каждой области рисуются соответствюущие значения, при этом с помощью пользовательской настройки подписей осей ординат можно добиться, чтобы вспомогательные сетки grid обеих областей совпадали.
# Пример 10.1
from matplotlib import rcParams
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-2*np.pi, 2*np.pi, 0.2)
y = np.sin(x) * np.cos(x)
f = np.sin(x) + np.cos(x)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx() # Создаём вторую область рисования ax2
print 'Результат работы метода twinx %s' % type(ax2)
ax1.plot(x, f, label = u'Сумма cos и sin', color='green')
ax1.set_xlabel(u'Аргумент')
ax1.set_ylabel(u'Функция 1', color='green')
ax1.grid(True, color='green')
ax1.tick_params(axis='y', which='major', labelcolor='green')
ax2.plot(x, y*333, label = u'Произведение cos и sin', color='red')
ax2.set_ylabel(u'Функция 2', color='red')
ax2.grid(True, color='red')
ax2.tick_params(axis='y', which='major', labelcolor='red')
ax1.set_title(u'Несколько разномасштабных переменных')
save('pic_10_1', fmt='png')
save('pic_10_1', fmt='pdf')
plt.show()
Если график, где присутствует дополнительная координатная ось, выполнен в чёрно-белом варианте, понять какой график относится к левой шкале, а какой к правой невозможно. В таком случае необходимо использовать легенду для идентификации данных. При работе с легендой такого графика есть свои нюансы.
# Пример 10.2.1
from matplotlib import rcParams
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-2*np.pi, 2*np.pi, 0.2)
y = np.sin(x) * np.cos(x)
f = np.sin(x) + np.cos(x)
fig = plt.figure()
# Явно задаём область рисования в виде четырёхуголника
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx() # Создаём вторую шкалу ax2
ax1.plot(x, f, label = u'Сумма cos и sin', color='green')
ax1.set_xlabel(u'Аргумент')
ax1.set_ylabel(u'Функция 1', color='green')
ax1.grid(True, color='green')
ax2.plot(x, y*333, label = u'Произведение cos и sin', color='red')
ax2.set_ylabel(u'Функция 2', color='red')
ax2.grid(True, color='red')
#ax2.legend()
ax1.set_title(u'Несколько разномасштабных переменных')
# Легенда для всего рисунка fig
plt.legend()
save('pic_10_2_1', fmt='png')
save('pic_10_2_1', fmt='pdf')
plt.show()
Несмотря на то, что было указано нарисовать легенду ко всему рисунку, отобразилась легенда только для одной координатной оси из двух!
На самом деле обе подписи легенды отобразились верно, но более новая легенда перезатёрла предыдущую. Потери можно избежать, если указать другое место расположения. Чтобы каждая подпись была в своём месте, нужно воспользоваться методом ax.legend()
, а не plt.legend()
.
Расположение легенды задаётся параметром loc метода legend(), который принимает значения в виде цифр (1-9), начиная от верхнего левого угла и заканчивая нижним правым, и в виде условных обозначений. Значение loc='best' автоматически выберет место на рисунке, где легенда меньше всего будет "портить" график. Также можно убрать рамку вокруг легенды для визуального уменьшения места (frameon=False), занимаемого легендой, снижая тем самым геометрическое давление рисунка в целом.
# Пример 10.2.2
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-2*np.pi, 2*np.pi, 0.2)
y = np.sin(x) * np.cos(x)
f = np.sin(x) + np.cos(x)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx() # Создаём вторую шкалу ax2
ax1.plot(x, f, label = u'Сумма cos и sin', color='green')
ax1.set_xlabel(u'Аргумент')
ax1.set_ylabel(u'Функция 1', color='green')
ax1.grid(True, color='green')
ax1.legend(loc=2)
ax2.plot(x, y*333, label = u'Произведение cos и sin', color='red')
ax2.set_ylabel(u'Функция 2', color='red')
ax2.grid(True, color='red')
ax2.legend(loc=1)
plt.title(u'Несколько разномасштабных переменных')
save('pic_10_2_2', fmt='png')
save('pic_10_2_2', fmt='pdf')
plt.show()
Если есть необходимость объединить обе легенды, сделав её единой, то можно пойти на следующую хитрость:
# Пример 10.3
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-2*np.pi, 2*np.pi, 0.2)
y = np.sin(x) * np.cos(x)
f = np.sin(x) + np.cos(x)
fig = plt.figure()
ax1 = fig.add_subplot(111)
line1 = ax1.plot(x, f, label = u'Сумма cos и sin', color='green')
ax1.set_xlabel(u'Аргумент')
ax1.set_ylabel(u'Функция 1', color='green')
ax1.grid(True, color='green')
ax2 = ax1.twinx() # Создаём вторую шкалу ax2
line2 = ax2.plot(x, y*333, label = u'Произведение cos и sin', color='red')
ax2.set_ylabel(u'Функция 2', color='red')
ax2.grid(True, color='red')
lns = line1 + line2
labs = [l.get_label() for l in lns]
ax1.legend(lns, labs, loc=3, frameon=False)
plt.title(u'Общая легенда для двух осей')
save('pic_10_3', fmt='png')
save('pic_10_3', fmt='pdf')
plt.show()
Иногда очень удобно использовать не стандартную равномерную шкалу на координатных осях, а логарифмическую.
Сделать шкалу координатной оси логарифмической позволяют методы plt.xscale('log')/plt.yscale('log')
или для областей рисования - ax.set_xscale('log')/ax.set_yscale('log')
.
Из определения натурального логарифма и экспоненты вытекает следующий факт: если ось ординат имеет логарифмическую шкалу, то график функции, которая равна экспоненте от аргумента, будет выглядеть как прямая линия.
# Пример 10.4.1
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(20)
y = np.exp(x)
fig = plt.figure()
# 1 x и y=x
ax = fig.add_subplot(221)
ax.plot(x, x)
ax.grid(True)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = x', fontsize=14)
# 2 x и y=exp(x)
ax = fig.add_subplot(222)
ax.plot(x, y)
ax.grid(True)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = exp(x)', fontsize=14)
# 3 x и y=exp(x). OY с log шкалой
ax = fig.add_subplot(223)
ax.set_yscale('log') # log здесь - натуральный логарифм!
# для работы с типом axis -> ax.set_yscale('log')
ax.plot(x, y)
ax.grid(True)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = exp(x)', fontsize=14)
ax.set_title(u'OY log шкала', loc='center')
# 4 x и y=x. OX с log шкалой
ax = fig.add_subplot(224)
ax.set_xscale('log') # log здесь - натуральный логарифм!
ax.plot(x, x)
ax.grid(True)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = x', fontsize=14)
ax.set_title(u'OX log шкала', loc='center')
# Автоматическое форматирование риснука
plt.tight_layout()
save('pic_10_4_1', fmt='png')
save('pic_10_4_1', fmt='pdf')
plt.show()
Для того, чтобы выразить обе координатные оси в логарифмических шкалах, существует метод plt.loglog()
или ax.loglog()
.
# Пример 10.4.2
x = np.arange(50)
y = np.exp(x)
fig = plt.figure()
# 1 Обычные шкалы
ax = fig.add_subplot(211)
ax.plot(x, y)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = exp(x)', fontsize=14)
ax.grid(True)
ax.legend(loc='best', frameon=False)
# Log шкалы
ax = fig.add_subplot(212)
ax.loglog()
ax.plot(x, y)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('y = exp(x)', fontsize=14)
ax.set_title(u'OY log и OX log шкалы')
ax.grid(True)
plt.tight_layout()
save('pic_10_4_2', fmt='png')
save('pic_10_4_2', fmt='pdf')
plt.show()
Автор: Шабанов Павел Александрович
E-mail: [email protected]
Часть II Структура рисунка в matplotlib
Часть III Специальные элементы рисунка в matplotlib