Главная страница

Введение в научный Python-1. Введение в научный Python


Скачать 6.2 Mb.
НазваниеВведение в научный Python
Дата09.01.2020
Размер6.2 Mb.
Формат файлаpdf
Имя файлаВведение в научный Python-1.pdf
ТипДокументы
#103229
страница14 из 22
1   ...   10   11   12   13   14   15   16   17   ...   22
Пример. Рисование трехмерных графических примитивов. import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.patch es as patches import mpl_toolkits.mplot3d.art3d as a3d from matplotlib.patches import Circle from mpl_toolkits.mplot3d.art3d import Poly3DCollection ax = Axes3D(plt.figure(facecolor='white'))
# три круга c1= Circle((0, 0), 1,alpha=0.6,facecolor='r') c2= Circle((2, 0), 1,alpha=0.6,facecolor='g') c3= Circle((2, 0), 1,alpha=0.6,facecolor='b')

159 ax.add_patch(c1) ax.add_patch(c2) ax.add_patch(c3) a3d.pathpatch_2d_to_3d(c1, z=2, zdir='x') a3d.pathpatch_2d_to_3d(c2, z=0, zdir='y') a3d.pathpatch_2d_to_3d(c3, z=0, zdir='z')
# пирамида fc1=[[1,1,0],[0,0,3],[1, -1,0]] fc2=[[1,-1,0],[0,0,3],[-1,-1,0]] fc3=[[-1,-1,0],[0,0,3],[-1,1,0]] fc4=[[-1,1,0],[0,0,3],[1,1,0]] fc5=[[1,1,0],[1,-1,0],[-1,-1,0],[-1,1,0]] pir=Poly3DCollection([fc1,fc2,fc3,fc4,fc5], facecolors=['r','g','c','m','y'],alpha=0.75) ax.add_collection3d(pir)
# ломаные (контур куба) lc=a3d.Line3D((1, -1,-1,1,1,1,-1,-1,1,1),
(1,1,-1,-1,1,1,1,-1,-1,1),
(-1,-1,-1,-1,-1,-3,-3,-3,-3,-3), c='b',ls='-',linewidth=3) ax.add_line(lc) ax.add_line(a3d.Line3D((1,1),( -1,-1),(-1,-3),c='b',ls=' -',linewidth=3)) ax.add_line(a3d.Line3D(( -1,-1),(-1,-1),(-1,-3),c='b',ls='-',linewidth=3)) ax.add_line(a3d.Line3D(( -1,-1),(1,1),(-1,-3),c='b',ls=' -',linewidth=3))
# правильный многоугольник (здесь квадрат) sq=patches.RegularPolygon((0,0), 4, 1,color='#337777',alpha=0.5) ax.add_patch(sq) a3d.pathpatch_2d_to_3d(sq, z=2, zdir='z')
ax.set_xlim(-3,3) ax.set_ylim(-3,3) ax.set_zlim(-3,3)

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

160
4.3
Анимация
Анимация – это последовательность изображений, которые быстро сменяют друг друга, в результате чего появляется движение. Для ее создания в matplotlib предназначен модуль matplotlib.animation. В этом параграфе мы опишем две функции этого модуля: FuncAnimation и ArtistAnimation. Функция matplotlib.animation.FuncAnimation(...) имеет следующий синтаксис:
FuncAnimation(fig, func, frames=count [,init_func=None, fargs=None, interval=ms, repeat=True,...])
Анимация создается путем многократного вызова функции func(...), которая должна рисовать кадры. В простейшем случае опция frames задает количество кадров, а функция func(номер_кадра[,fargs]) в качестве первого аргумента принимает номер кадра. Функции func, если нужно, можно передавать аргументы через опцию fargs. Тогда fargs=[arg1,...] является списком.
Функция, заданная необязательной опцией init_func= funcname, используется для рисования стартового кадра и инициализации графических объектов. Она вызывается один раз перед построеним первого кадра. Опция interval задает время в миллисекундах между кадрами. Опция repeat=True
(значение по умолчанию) включает режим повторения анимации. В этом случае функция funcname будет вызываться в начале каждой «анимационной сессии».
Ниже приведен пример, создающий анимацию кривой.
Пример. Анимация кривой. import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation fig = plt.figure(facecolor='white') ax = plt.axes(xlim=(0, 8), ylim=( -1, 1) ) line, = ax.plot([ ], [ ], lw=3)
# line = объект кривой ax.grid(True) def redraw(i): x = np.linspace(0, 8, 200) y = np.sin(i * x/10)/(1+x**2) line.set_data(x, y)
# результат обязательно присваивать переменной anim =animatio n.FuncAnimation(fig,redraw,frames=100, interval=50) plt.show()
Три различных кадра анимации показаны ниже.

161
Вначале загружаются необходимые модули и создается графическое окно fig с графической областью ax. Затем рисуется «пустая» ломаная. Она не имеет данных, но для нее сразу устанавливается толщина линии. Функция plot возвращает объект этой линии line класса Line2D. Напомним, что если кривых строится несколько, то функция plot возвращает кортеж (или список) таких объектов, например, line1, line2 = plot(x1, y1, x2, y2)
Если возвращаемый объект один, то в инструкции line, = ax.plot(...) после имени line нужно ставить запятую (признак кортежа). Используя методы set_linestyle(), set_marker(), set_drawstyle() объекта line, можно менять стили оформления кривой и маркеров.
Функция redraw(i) рисует i – й кадр. Для рисования кривой используется объект line, созданный ранее. У него есть метод line.set_data(x,y)
, который меняет его данные (массивы x и y координат вершин ломаной).
Функция animation.FuncAnimation(...) первым аргументом принимает графическое окно fig, в котором создается анимация. Второй аргумент является именем функции redraw, которая рисует кадры. Затем мы указываем количество кадров и интервал времени между ними.
Для добавления фона (если в функции FuncAnimation не используется опция blit=True) можно создать функцию инициализации анимации.
Добавьте в предыдущий код следующие инструкции. from matplotlib.patches import Circle, Rectangle def initpict(): rect=Rectangle((1, -0.5),4, 1, facecolor='cyan',fill=True) ax.add_patch(rect)
# добавление прямоугольника на графическую область circle = Circle((2, 0), 0.5, color='r') ax.add_artist(circle)
# добавление круга на графическую область ax.set_aspect('equal')
И измените следующую инструкцию, добавив вызов функции initpict(). anim=animation.FuncAnimation(fig, redraw,init_func=initpict, frames=100, interval=50)

162
В нашем примере функция initpict() не должна ничего возвращать.
В результате анимация будет содержать рисунок фона, состоящий, в данном случае, из прямоугольника и круга. Однако, если мы хотим иметь неизменный рисунок фона, то его можно создать проще, используя обычные графические инструкции до вызова функции FuncAnimation(...).

В предыдущем примере мы использовали объект, возвращаемый функцией plot. Все графические функции matplotlib возвращают графические объекты различных классов и эти объекты можно впоследствии использовать для изменения их свойств. В частости функция plot возвращает список объектов класса matplotlib.lines.Line2D. Например, следующие инструкции строят кривую (ломаную), ссылка на которую помещается в переменную line. Затем обращение к методу объекта line изменяет его атрибут сглаживания. line, = plt.plot(x, y, '-') line.set_antialiased(False) # выключение сглаживания
Здесь plt синоним имени модуля matplotlib.pyplot.
Используя функцию setp(), можно менять свойства всего списка объектов, возвращаемых графической функцией, Например, lines = plt.plot(x1, y1, x2, y2) plt.setp(lines, color='b', linewidth=3.0)
Функции setp() и getp() модуля matplotlib.pyplot предназначены для установки и чтения свойств графических объектов. Функция setp() обрабатывает один объект или целый список объектов, которые ей передаются первым аргментом.
Обычно, возвращаемые графические объекты имеют метод, с помощью которого можно поменять данные, используемые для их построения. В предыдущем примере для объекта line класса Line2D использовался метод line.set_data(x,y)
. Он заменяет массивы x и y координат вершин ломаной и, тем самым, меняет форму ломаной/кривой.
Объект, возвращаемый функцией FuncAnimation, должен существовать постоянно все время работы анимации. Поэтому функция FuncAnimation должна возвращать значение в глобальную переменную, которая будет представлять ссылку на этот объект.
Важным аргументом функции FuncAnimation(...) может быть опция blit. Установка опции blit=True гарантирует, что только изменяемая часть битового массива, представляющего изображение, будет перерисовываться.
Это ускоряет и улучшает качество анимации.

163
Если используется опция blit=True, то функции func(...) и init_func(...) должны возвращать последовательность графических объектов (iterable of artists). Это необходимо для того, чтобы сообщить функции
FuncAnimation
, какие графические объекты меняются. Тогда они рисуются в памяти (вне экрана) и только потом очень быстро переносятся в графическую область. Если объекты непосредственно рисуются в графическом окне, то возникает «торможение» и может возникнуть мерцание. Обычно функция инициализации графики (в примере это initpict) возвращает те объекты, которые должны присутствовать только на стартовом кадре, а функция анимации (в примере это redraw) возвращает только объекты, которые перерисовываются в каждом кадре.
Пример. Движение бильядного шара. В следующем примере по прямоугольному полю движется круг (модель бильярдного шара), который отражается от бортов (границ) прямоугольника. В программе используется функция initpict, которая возвращает объект, представляющий круг. Этот же объект возвращает функция redraw, сообщая функции анимации, что его изображение меняется и требует перерисовки. import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib.patches import Circle,Rectangle def initpict(): pc.center=(x0,y0) ax.add_patch(pc) return pc,
# return [ ] оставляет стартовый шар нарисованным def redraw(i): global x,y,dx,dy if x+r>rbod: x=rbod -r; dx=-dx elif x-rubod or y+dy+r>ubod: y=ubod -r; dy=-dy; elif y-rfig = plt.figure(facecolor='white') fig.set_dpi(100) rbod=4; lbod=0; ubod=4; dbod=0 # границы области ax = plt.axes(xlim=(lbod, rbod), ylim=(dbod, ubod) ) ax.set_aspect('equal')
# начальное положение и радиус шара x0=3; y0=1; r=0.35; dx=0.03; dy=0.0125
# вектор начальной скорости (направления) x=x0; y=y0

164 pc = plt.Circle((x, y), r, fc='b')
anim =animation.FuncAnimation(fig, redraw, init_func=initpict, frames=400, interval=20,blit=True) plt.show()
Повторим еще раз. Если используется опция blit=True, то функции initpict и redraw должны возвращать последовательность графических объектов или пустой список. При этом, если функция init_func()возвращает пустой список, то создаваемые ею графические объекты будут присутствовать на всех кадрах.

В предыдущем примере функция redraw в качестве аргумента принимала номер кадра. Однако, она может иметь больше аргументов. Тогда их ей можно передавать через опцию fargs функции FuncAnimation. Например, пусть функция redraw, кроме номера кадра, вторым аргументом принимает ссылку на объект line ломаной, которую она перерисовывает. Передачу ей такого аргумента можно выполнить следующим набором команд: def redraw(frameNum, line):
# использует аргумент line для изменения данных ломаной. line, = ax.plot([], []) anim = animation.FuncAnimation(fig, redraw, fargs=(line,), interval=20)
Пример. Анимация движения кривошипно – шатунного механизма.
Кривошипно – шатунный механизм является устройством, которое вращательное движение преобразует в поступательное или наоборот.
Смоделируем движение этого механизма, изобразив его в виде ломаной. import numpy as np import matplotlib.pyplot as plt import matplotlib.anima tion as animation from matplotlib.patches import Circle,Rectangle def redraw(i, lin): alph=np.pi*i/50
# угол поворота кривошипа в i-ом кадре
# приращения координат узлов ломаной

165 dx=np.array([0, a*np.cos(alph),np.sqrt(b**2 -a**2*np.sin(alph)**2),
0,dl,0,-dl, 0]) dy=np.array([0,a*np.sin(alph), -a*np.sin(alph),-dh,0,2*dh,0, -dh])
# массивы координат узлов ломаной x=np.cumsum(dx) y=np.cumsum(dy) lin.set_data(x, y)
fig = plt.figure(facecolor='white') fig.set_dpi(100) a=1; b=3; dl=1; dh=0.25
# геометрические размеры ax = plt.axes(xlim=( -1.2, 5.2), ylim=(-1.5, 1.5)) line, = ax.plot([ ], [ ], lw=3) ax.set_aspect('equal')
ax.set_xticks([])
# удаляем засечки и метки с оси X ax.set_yticks([])
# удаляем засечки и метки с оси Y anim =animation.FuncAnimation(fig, redraw, fargs=(line,), frames=100, interval=50) plt.show()
На следующем рисунке показаны три кадра анимации в последовательные моменты времени.
Заметим, что использование второго аргумента функции redraw(i,lin) в данном примере необязательно.

Приведем еще несколько примеров использования функции FuncAnimation.
Пример. Циклоида. Траектория фиксированной точки окружности, которая катится по прямой, называется циклоидой. Если радиус окружности равен 1 и скорость движения ее центра
1

v
, то параметрическое уравнение циклоиды будет иметь вид
 
 
t
t
y
t
t
t
x
cos
1
,
sin




. Следующий код строит катящуюся окружность, движение фиксированной точки на окружности, и заметаемую точкой траекторию (циклоиду). import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib.patches import C ircle def initpict(): line1.set_data([], []) line2.set_data([], []) pc.center=(xC,yC) ax.add_patch(pc) pp.center=(xP,yP)

166 ax.add_patch(pp) return pc,pp,line1,line2
def redraw(i): global xC, xP, yP n=i/10 t=np.linspace(0,n,100) x=t-np.sin(t) y=1-np.cos(t) line1.set_data(x, y) xC=n pc.center=(xC,yC) xP=n-np.sin(n) yP=1-np.cos(n) pp.center=(xP,yP) line2.set_data([n,xP], [1,yP]) return pc,pp,line1,line2
fig = plt.figure(facecolor='white') fig.set_dpi(100) a=1; b=3; dl=1; dh=0.25 ax = plt.axes(xlim=(0, 12), ylim=(0, 3)) ax.set_yticklabels(['0',' ','1',' ','2',' ','3'])
# меняем текст меток верт. оси line1, = ax.plot([], [] ,lw=2) line2, = ax.plot([], [] ,'r') xC=0;yC=1; xP=0; yP=0 pc = plt.Circle((xC, yC), 1, fc='c') pp = plt.Circle((xP, yP), 0.1, fc='k') ax.set_aspect('equal')
anim =animation.FuncAnimation(fig, redraw, init_func=initpict, frames=120, interval=50, blit=True) plt.show()
Обратите внимание на то, что при использовании опции blit=True функции initpict и redraw возвращают кортеж (или список) графических объектов.
Функция initpict возвращает те объекты, которые должны присутствовать только на стартовом кадре. А функция redraw должна возвращать только объекты, которые перерисовываются в каждом кадре. Кроме того, порядок возвращаемых (перерисовываемых) объектов существенен. Попробуйте заменить инструкцию return pc,pp,line1,line2 функции redraw на

167 инструкцию return line1,line2, pc,pp, и на кадрах анимации не будут видны участки траектории внутри круга и отрезок радиуса.

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








y
k
h
k
y
k
y
k
h
k
y
k
e
e
e
x
k
t
w
a
V
e
e
e
x
k
t
w
a
U










2 2
cos
,
sin где U и V мгновенные значения смещений частицы жидкости с равновесными координатами x, y в направлениях осей x и y. Здесь предполагается, что дно водоема находится на уровне
h
y


, а поверхность – на уровне
0

y
. Точки поверхности жидкости будут иметь координаты
 
 
0
,
0
,
0
,
x
V
Y
x
U
x
X




В примере нам удобнее считать, что дно водоема находится на уровне
0

y
, а поверхность – на уровне
h
y

. Поэтому координаты точек поверхности жидкости в момент времени t будут равны:








h
k
h
k
e
x
k
t
w
a
h
Y
e
x
k
t
w
a
x
X
2 2
1
cos
,
1
sin










В следующем коде мы моделируем движение жидкости в соответствии с этими уравнениями. Двумерную волну изображаем с помощью залитой области между кривой (X,Y) и осью Ох (дном водоема). import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation def xs(u,t): return u+a*np.sin(w*t -k*u)*(1+np.exp( -2*k*h)) def ys(u,t): return a*np.cos(w*t-k*u)*(1-np.exp(-2*k*h))
def redraw(i): t=i/10
# момент времени текущего кадра u=np.linspace( -2*L,2*L,100)
X=xs(u,t)
Y=ys(u,t)+h
# начальная и конечная точки области заливки должны находиться на оси x!
X=np.insert(X,0,X[0])
Y=np.insert(Y,0,0)
X=np.append(X,X[ -1])
Y=np.append(Y,0)
# для изменение данных передается массив из двух столбцов,
# например, ptch.set_xy([[0,0],[3,-5],[6,-9],[9,0]])
# преобразуем одномерные массивы координат в двумерный массив pp
XY=np.vstack((X,Y)) pp=XY.T

168 ptch.set_xy(pp)
# меняем данные Polygon–а
L=6; w=1; a=1; h=6; k=0.4
# параметры задачи fig = plt.figure(facecolor='white') fig.set_dpi(100) ax = plt.axes(xlim=( -2*(L-1), 2*(L-1)), ylim=(0, h+2)) ax.set_yticklabels(['0','','2','','4','','6','','8'])
# подписи меток верт. оси ptch, = ax.fill([0,5,10], [0,0,0],'c' )
# создаем пустой объект;
# fill возвращает список/кортеж объектов класса Polygon ax.add_patch(ptch) ax.set_aspect('equal')
anim =animation.FuncAnimation(fig, redraw, frames=120, interval=50) plt.show()
Один из кадров анимации показан на следующем рисунке.

Заметим, что если опция init_func в функции FuncAnimation не используется, то для создания стартового кадра анимации применяется первый кадр функции redraw . Точнее вызывается функция redraw(0) с нулевым номером кадра. В результате вызов redraw(0) выполняется два раза подряд.
Чтобы этого не происходило можно создать пустую функцию initpict и использовать ее в опции init_func=initpict функции FuncAnimation.
Функция FuncAnimation не ограничена двумерной графикой. Кадры анимации могут состоять из трехмерных рисунков.
1   ...   10   11   12   13   14   15   16   17   ...   22


написать администратору сайта