Программирование и научные вычисления на языке Python/§9

Визуализация функции *f(x)* состоит в том, чтобы нарисовать кривую *y = f(x)* в координатах *xy*. Технически это заключается в проведении прямых линий между точками, заданными значениями функции. Чем больше точек мы берем, тем более гладкой получается кривая.

Предположим, мы хотим изобразить функцию *f(x)* для *a < x < b*. Сначала мы должны задать *n* координат в интервале [*a, b*], которые мы назовем *x 0*,

*x*, ... ,

1*x*. Затем мы вычисляем

n-1*y*. Далее, если мы расположим значения

i= f(xi)*x*и

i*y*соответственно в массивах

i`x`и

`y`, мы можем начертить график с помощью команды

`plot(x, y)`.

Естественно, имена функции и аргумента могут быть другими. В нашем первом примере о графиках мы будем рисовать кривую для функции от времени `t`.

## Matplotlib

Для визуализации при использовании SciPy часто применяют библиотеку Matplotlib, являющуюся аналогом средств вывода графики MATLAB. Преимущества Matplotlib следующие в том что он использует Python, а значит мы можем задействовать любую из стандартных или других доступных библиотек, он распространяется по свободной лицензии, что так важно ученым и студентам, обладающим обычно небольшим бюджетом для своих изысканий. Также как и Python, поскольку он на нем основан, Matplotlib портируем на многие операционные системы. Для того, чтобы ознакомиться с возможностями библиотеки, достаточно заглянуть в галерею проекта. Под каждой визуализацией приводится породивший ее код, и стоит заметить как немного места он занимает в сравнении с другими языками.

## Набор точек

Одним из больших преимуществ Matplotlib является та скорость, с которой мы можем построить график и привести первый пример:



```
>>> import matplotlib.pyplot as plt
>>> plt.plot([1, 3, 2, 4])
[<matplotlib.lines.Line2D object at 0x01A00430>]
>>> plt.show()
```


После выполнения последней строчки, вызывается окно Matplotlib, внутри которого мы видим рисунок, показанный справа, который мы можем сохранить в удобном формате с помощью крайней правой иконки в нижней панели, например, обычном графическом формате *PNG*. Что же мы построили?

В первой инструкции мы импортировали основной модуль библиотеки для построения графиков под именем `plt`, именно так наиболее часто сокращается это длинное имя. Мы не используем импортирование всех функций через *, поскольку, во-первых это долго, во-вторых сильно захламляет пространство имен. Поэтому пользуемся коротким префиксом. После того, как мы импортировали модуль, мы можем пользоваться его функциями, здесь мы использовали функцию `plot()`, которая собственно и строит график, а потом функция `show()` его нам показывает.

Аргумент, принимаемый функцией `plot()` это последовательность y-значений. Другой, который мы опустили, стоящий перед y — это последовательность x-значений. Поскольку его нет, генерируется для четырех указанных y, список из четырех x: [0, 1, 2, 3]. Отсюда и такой график.



## Функция

Естественно использовать две координаты вместе и вместо списков массивы. Давайте построим график какой-нибудь сложной функции, например, :



```
from numpy import *
import matplotlib.pyplot as plt
def f(t):
return t**2*exp(-t**2)
t = linspace(0, 3, 51) # 51 точка между 0 и 3
y = f(t)
plt.plot(t, y)
plt.show()
```


Как видно, код такой же ясный и простой, как полученный с помощью него график. Если функция больше нигде не используется, то можно получить еще более компактный код, задав ее сразу же после определения массива t:



```
from numpy import *
import matplotlib.pyplot as plt
t = linspace(0, 3, 51)
y = t**2*exp(-t**2)
plt.plot(t, y)
plt.show()
```



## Украшения

Кроме того, чтобы просто построить кривую, было бы хорошо ее назвать, обозначить оси, вывести легенду (это особенно пригодится, когда мы научимся строить несколько графиков. Кроме того, нам может захотеться изменить вид самой кривой, пределы, в которых мы ее смотрим. И все это c matplotlib, конечно, возможно:



```
from numpy import *
import matplotlib.pyplot as plt
t = linspace(0, 3, 51)
y = t**2*exp(-t**2)
plt.plot(t, y, 'g--', label='t^2*exp(-t^2)')
plt.axis([0, 3, -0.05, 0.5]) # задание [xmin, xmax, ymin, ymax]
plt.xlabel('t') # обозначение оси абсцисс
plt.ylabel('y') # обозначение оси ординат
plt.title('My first normal plot') # название графика
plt.legend() # вставка легенды (текста в label)
plt.show()
```


Кроме отмеченных новшеств, обозначенных в комментариях, в аргументах функции `plot()` мы видим два новых. Последний задает текст легенды графика. Строковый аргумент `g--` и ответственен за то, что изменился вид кривой. В сравнении с предыдущим примером, график позеленел (**g**reen) и вырисовывается -- штриховой линией. По умолчанию этот аргумент b-, что и означает синюю (**b**lue) сплошную линию. Ниже приведена таблица, которая позволяет выбрать нужный аргумент.



b, blue | c, cyan | g, green | k, black | m, magenta | r, red | w, white | y, yellow | - | -- | -. | : |

синий | голубой | зеленый | черный | пурпурный | красный | белый | желтый | сплошная | штриховая | штрих-пунктир | пунктир |




## Несколько кривых

Часто встречаются задачи, в которых мало визуализировать какую-то функцию, нужно и сравнить ее с другой функцией или даже несколькими. Давайте сравним уже знакомую нам функцию с некоторой похожей функцией, например, . Оказывается, что для этого достаточно добавить еще одну инструкцию `plot()`:



```
from numpy import *
import matplotlib.pyplot as plt
t = linspace(0, 3, 51)
y1 = t**2*exp(-t**2)
y2 = t**4*exp(-t**2)
plt.plot(t, y1, label='t^2*exp(-t^2)')
plt.plot(t, y2, label='t^4*exp(-t^2)')
# декоративная часть
plt.xlabel('t')
plt.ylabel('y')
plt.title('Plotting two curves in the same plot')
plt.legend()
plt.show()
```


Как видно из полученного рисунка, matplotlib и без наших указаний понимает, что кривые надо обозначать разными цветами. Но если, нам захочется управлять самим, (например, при черно-белой печати разумнее использовать разный стиль линий) мы знаем как это делать. Кроме того, бывает нужно показывать не сглаженную кривую, а именно точки из этой кривой. Для этого используется синтаксис маркеров, в общем-то такой же, что и для линий. Давайте посмотрим:



```
from numpy import *
import matplotlib.pyplot as plt
t = np.linspace(0, 3, 51)
y1 = t**2*exp(-t**2)
y2 = t**4*exp(-t**2)
y3 = t**6*exp(-t**2)
plt.plot(t, y1, 'g^', # маркеры из зеленых треугольников
t, y2, 'b--', # синяя штриховая
t, y3, 'ro-') # красные круглые маркеры,
# соединенные сплошной линией
plt.xlabel('t')
plt.ylabel('y')
plt.title('Plotting with markers')
plt.legend(['t^2*exp(-t^2)',
't^4*exp(-t^2)',
't^6*exp(-t^2)'], # список легенды
loc='upper left') # положение легенды
plt.show()
```


Заметьте, что мы изменили положение легенды, иначе бы она дерзко закрывала красный график. По умолчанию легенда располагается в правом верхнем углу, но можно ее и перенести за счет аргумента `loc`. Этому аргументу можно присваивать и численное значение, но конечно легче воспринимается строка. В таблице ниже приводятся возможные варианты.



Место | String | Code |

лучший вариант | best | 0 |

вверху справа | upper right | 1 |

вверху слева | upper left | 2 |

внизу слева | lower left | 3 |

внизу справа | lower right | 4 |

справа | right | 5 |

посередине слева | center left | 6 |

посередине справа | center right | 7 |

посередине внизу | lower center | 8 |

посередине вверху | upper center | 9 |

посередине | center | 10 |




### Маркеры

Здесь также показано как можно объединять сразу три графика в одной инструкции. Кроме того, видно, что можно не только использовать маркеры (`y1`) или линии(`y2`), но и объединять их вместе (`y3`). Наиболее часто в научных исследованиях и журналах приводят графики, отличаемые друг от друга именно по маркерам, поэтому и в matplotlib для их обозначения имеется множество способов:

**.**точечный маркер**,**точки, размером с пиксель**o**круги**v**треугольники носом вниз**^**треугольники носов вверх**>**треугольники смотрят вправо**<**треугольники смотрят влево**s**квадраты**p**пентагоны*****звездочки**h**шестиугольники**H**повернутые шестиугольники**+**плюсы**x**крестики**D**ромбы**d**узкие ромбы**|**вертикальные засечки



### Дополнительные аргументы plot()

Итак, в одном аргументе, мы можем задать сразу три параметра: первым указываем цвет, вторым — стиль линии, третьим — тип маркера. Однако уже такая нотация может у человека незнакомого с ней, вызвать удивление. Кроме того, она не позволяет разделять параметры линии и маркера, поэтому существует вариант с использованием keywords — все также это позволяет щедрая функция `plot()`:

Keyword argument
|
Что меняет
|

color или c
|
цвет линии |

linestyle
|
стиль линии, используются обозначения, показанные выше |

linewidth
|
толщина линии в виде float-числа |

marker
|
вид маркера |

markeredgecolor
|
цвет края (edge) маркера |

markeredgewidth
|
толщина края маркера |

markerfacecolor
|
цвет самого маркера |

markersize
|
размер маркера |



Итак, мы уже меняли все внутри окна графика и надписи за его пределами. Что осталось неизменным, так это подбираемые самим matplotlib оси. Делается это с помощью функций `xticks()` и `yticks()`, в которые передаются один или два списка значений: либо просто список указываемых значений, либо их же, но вначале те места, на которые они встают:



```
x = [5, 3, 7, 2, 4, 1]
plt.xticks(range(len(x)), ['a', 'b', 'c', 'd', 'e', 'f'])
plt.yticks(range(1, 8, 2))
```


Кроме того, было бы желательно уметь наносить сетку. Для этого тоже имеется простая команда:



```
plt.grid(True)
```


Также часто требуется одну или обе оси выставить в логарифмическом масштабе. Для этого применяются команды `plt.semilogx()` и `plt.semilogy()`.

## Сохранение файла

Как сказано, мы можем сохранять файлы, используя панель под рисунком, но мы также можем и запрограммировать автоматическое сохранение наших результатов в файле и довольно легко:



```
from numpy import *
import matplotlib.pyplot as plt
t = linspace(0, 3, 51)
y = t**2*exp(-t**2)
plt.plot(t, y)
plt.savefig('name_of_plot.png', dpi=200)
```


Файл сохраняется в той же директории с именем и расширением, указанным в первом аргументе. Второй необязательный аргумент позволяет «на лету» менять разрешение картинки, сохраняемой в файл.

Бывает так, что смотреть на картинки в уже настроенной программе не нужно и требуется их именно сохранять на будущее, чтобы просмотреть и сравнить их все вместе. Тогда нам не нужно запускать окно просмотра результатов. Для этого до прежних инструкций посылаем главному модулю сообщение:



```
import matplotlib
matplotlib.use('Agg')
```

## Панель управления

Если же вы не только сохраняете рисунок, но и хотите предварительно лучше рассмотреть полученные результаты, в этом вам поможет панель управления, расположенная под полученным графиком. Давайте побольше узнаем об этом инструменте. Панель состоит из семи кнопок, так и будем называть и рассказывать о них, перемещаясь слева направо.

- Первая кнопка, на которой изображен дом, возвращает нас с любого момента просмотра к тому виду, с которого мы начинали, какими их вывел сам matplotlib.
- Вторая и третья кнопки со стрелками позволяют нам перемещаться между видами, то есть в отличие от дома, возвращающего нас исключительно к самому первому виду, не зависящему от нас, дают нам возможность сравнивать, например, разные масштабы приближения к какой-то точке.
- Четвертая кнопка (с голубым крестом) имеет два возможных режима:
- Режим pan — нажав на эту кнопку, а затем зажав в пределах графика левую клавишу мыши, мы можем перемещать график в пределах окна.
- Режим zoom — зажав правую клавишу мыши, мы можем изменять масштаб по горизонтали или вертикали, двигаясь в соответствующей плоскости вправо или влево, вверх или вниз.

- Нажатие пятой кнопки позволяет приближать или удалять выбранную область соответственно выделяя ее левой или правой кнопкой мыши.
- Нажатие шестой кнопки приводит к вызову меню настроек окна.
- Последняя, седьмая кнопка позволяет сохранить рисунок в удобном формате.


Также у окна есть ряд горячих клавиш, заменяющих кнопки панели, а некоторые из предоставляемых ими функций в панели отсутствуют:

Горячая клавиша
|
Что делает
|

h
|
home, первая кнопка |

c или ←
|
вторая кнопка |

v или →
|
третья кнопка |

p
|
pan, четвертая кнопка |

o
|
пятая кнопка |

удерживая x
|
pan и zoom только по горизонтали |

удерживая y
|
pan и zoom только по вертикали |

удерживая Ctrl
|
сохраняются пропорции |

g
|
добавление сетки |

l
|
логарифмическая шкала |