Введение в научный Python-1. Введение в научный Python
Скачать 6.2 Mb.
|
Axes3D.plot(x,y,z[,...]) , которая принимает вектора x,y,z координат узлов ломаной. При большом количестве узлов ломаная неотличима от кривой. fig = plt.figure() ax=Axes3D(fig) t=np.linspace( -4*np.pi,4*np.pi,100) r=t**2/80+1 x=r*np.cos(t) # праметрическое уравнение кривой y=r*np.sin(t) z=t/(2*np.pi) ax.plot(x,y,z,linewidth=4) Задание свойств кривой и параметров оформления трехмерного графика аналогичны двумерным графикам. График поверхности строится с помощью функции Axes3D.plot_surface(X,Y,Z,rstride=1, cstride=1[,...]), где X,Y,Z двумерные массивы, содержащие x, y и z координаты узлов многогранной поверхности, а параметры rstride=1 и cstride=1 определяют шаг по индексам (row и column) этих массивов. Единицы означают выбор всех значений в двумерных массивах X,Y,Z. При большом размере матриц многогранная поверхность неотличима от криволинейной. fig=plt.figure() ax=Axes3D(fig) u=np.linspace( -4*np.pi,4*np.pi,50) x,y=np.meshgrid(u,u) r=np.sqrt(x**2+y**2) z=np.sin(r)/r surf=ax.plot_surface(x,y,z,rstride=1,cstride=1,linewidth=0, cmap=mpl.cm.hsv) fig.colorbar(surf, shrink=0.75, aspect=15) 145 Опция cmap=mpl.cm.hsv задает hsv способ раскраски в зависимости от z координаты точек поверхности. Метод fig.colorbar(...) рисует справа от графика цветовую полосу (палитру). Ее аргумент shrink задает коэффициент сжатия (по высоте) полосы относительно рисунка, а аргумент aspect определяет пропорцию высоты и ширины полосы. Каркасная поверхность строится с помощью функции Axes3D.plot_wireframe(X,Y,Z,rstride=1, cstride=1[,...]), где X,Y,Z двумерные массивы, содержащие x, y и z координаты узлов многогранной поверхности, а параметры rstride=1 и cstride=1 определяют шаг по индексам этих массивов. Удалите в предыдущем примере две последние инструкции и добавьте одну команду . . . # вместо многоточия стоит 6 первых строк предыдущего примера ax.plot_wireframe(x, y, z, rstride=1, cstride=1) Версии графических библиотек постоянно обновляются. Объекты Axes3D в последней версии matplotlib рекомендуется создавать с использованием ключевого слова projection=„3d‟ парой следующих команд: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') Вместо последней инструкции также можно использовать следующую: ax = plt.axes(projection='3d') В общем случае функция add_subplot(...) предназначена для построения нескольких графиков в различных областях одного окна. Но ее можно использовать и для создания единственного графика. Построение одного трехмерного графика не отличается от того, что мы делали выше. Покажем, как использовать эту функцию так, чтобы в разных областях находились как двумерные, так и трехмерные графики. # Построение 4-х графиков в одном графическом окне 146 # Левый верхний график (сфера) fig = plt.figure(figsize=(8,6),facecolor='white', num='Примеры построения графиков') ax = fig.add_subplot(2, 2, 1, projection='3d') u = np.linspace(0, 2 * np.pi, 51) v = np.linspace( -np.pi/2, np.pi/2, 51) x = np.outer(np.cos(u), np.cos(v)) y = np.outer(np.sin(u), np.cos(v)) z = np.outer(np.ones(np.size(u)), np.sin(v)) ax.plot_surface(x, y, z, rstride=2, cstride=4, color='0.75') # правый верхний график u=np.linspace( -4*np.pi,4*np.pi,50) X, Y = np.meshgrid(u, u) r = np.sqrt(X**2 + Y**2) Z=np.sin(r)/r ax = fig.add_subplot(2, 2, 2, projection='3d') ax.plot_surface(X,Y,Z, rstride=1, cstride=1, linewidth=0,color=(0.5,0.5,1)) # левый нижний график (каркасная поверхность) pt=np.linspace(-3,3,31) X,Y=np.meshgrid(pt,pt) Z=X*Y*np.exp(-X**2-Y**2) ax = fig.add_subplot(2, 2, 3, projection='3d') ax.plot_wireframe(X, Y, Z, rstride =1, cstride=1,color='k') # правый нижний график (залитый контурный график) ax = fig.add_subplot(2, 2, 4) plt.contourf(X, Y, Z, 12, cmap='jet') plt.axis('image') 147 Приведенный код удобнее всего оформить в виде Python программы. Мы набирали его в редакторе Spyder. При этом, во время отладки выполняли код по частям, выделяя желаемый блок и выполняя его, нажав клавишу F9. Обсудим некоторые функции из этого кода. Команде plt.figure(...) переданы аргументы: figsize=(8,6) – задает размер графического окна в дюймах; facecolor='white' – задает белый фон графического окна num='текст' – если аргументу num передана строка, то она задает заголовок графического окна. Команда fig.add_subplot(2, 2, 1, projection='3d') создает в графическом окне 4 области, организованные в 2 строки и 2 столбца (2 x 2), и делает активной первую из них. Также для этой области задается трехмерный «тип проекции» (projection='3d'), который позволяет соответствующему объекту Axes отображать трехмерные данные. Если вы хотите расположить графические области (подокна) вручную, например «мозаикой», используйте команду axes(), которая позволяет задать положение осей (графических областей) как axes([left, bottom, width, height]) , где все значения изменяются от 0 до 1. Выглядеть это может так: import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def f(t): return np.exp(-t) * np.cos(2*np.pi*t) def g(x,y): return np.sin(np.pi*x)*np.sin(np.pi*y) fig = plt.figure(facecolor='white') # верхний правый график t = np.arange(0.0, 5.0, 0.1) plt.axes([0.55, 0.55, 0.4, 0.4]) plt.plot(t, f(t), 'bo', t, f(t), 'k') # график плотности слева x = np.linspace(-1,1,101) X,Y=np.meshgrid(x,x) Z=g(X,Y) ax=plt.axes([0.0, 0.4, 0.5, 0.5]) plt.imshow(Z,interpolation='nearest') ax.axis('off') # правый нижний график (тор) t=np.linspace(0,2*np.pi,50) th,ph=np.meshgrid(t,t) r=0.2 x,y,z=(1+r*np.cos(ph))*np.cos(th), (1+r*np.cos(ph))*np.sin(th), 148 r*np.sin(ph) ax=Axes3D(fig,rect=[0.3,0.15,0.6,0.25]) ax.plot_surface(x,y,z,rstride=2,cstride=1) ax.azim, ax.elev=160,45 # азимут и угловая высота точки наблюдения Цвет поверхности задается опцией color=цвет. Сам цвет можно задать строкой его названия, например, color='lightblue' (светло синий), или для основных цветов сокращенно одной буквой, например, color='k' (черный). Яркость серых цветов можно задать с помощью строки, содержащей число в интервале от 0 до 1 (1 – белый, 0 – черный), например, color='0.75'. Кроме того, цвет можно задавать RGB строкой, содержащей шестнадцатеричное число, перед которым стоит символ '#' (решетка). Например, color='#E0FFFF'. Первые две цифры задают яркость красной составляющей, вторые – зеленой, третьи – синей. Также цвет в формате RGB можно задавать кортежем, состоящим из трех чисел из интервала [0, 1], например, color=(0.9,0.5,1). Также можно использовать цветовые карты, с помощью которых можно по– разному окрашивать участки трехмерной поверхности. График рассеяния строится функцией Axes3D.scatter(x, y, z[,...]). Функция рисует множество точек, абсциссы которых передаются в векторе x, ординаты – в векторе y, аппликаты – в векторе z. # следующий рисунок слева x=y=z=np.arange(-3,4) fig = plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') ax.scatter(x, y, z, s=200, color='r', c='g') # следующий рисунок в центре n = 60 xs = np.random.rand(n) ys = np.random.rand(n) zs = np.random.rand(n) fig = plt.figure(facecolor='white') ax = fig.add_subplot(111, proje ction='3d') 149 ax.scatter(xs, ys, zs, c='r', marker='o',s=200) plt.show() # следующий рисунок справа fig = plt.figure(facecolor='white') ax = plt.axes(projection='3d') z = np.linspace(0, 1, 100) x = z * np.sin(20 * z) y = z * np.cos(20 * z) c = x + y ax.scatter(x, y, z, c=c) Одномерные массивы координат точек также использует функция Axes3D.plot3D(...) . Она имеет следующий формат: Axes3D.plot3D(x,y,z[,...]), где x, y и z одномерные массивы, содержащие координаты узлов. Используя функцию numpy.ravel(), можно двумерные массивы координат точек поверхности преобразовать в одномерные массивы и, используя их, построить поверхность. В следующем примере кроме поверхности, построенной по таким одномерным массивам, мы строим график рассеяния по тем же точкам. u = np.linspace(0, 2 * np.pi, 51) v = np.linspace( -np.pi/2, np.pi/2, 51) x = np.outer(np.cos(u), np.cos(v)) y = np.outer(np.sin(u), np.cos(v)) z = np.outer(np.ones(np.size(u)), np.sin(v)) fig=plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot3D(np.ravel(x),np.ravel(y),np.ravel(z)) # след. рисунок слева ax.scatter3D(np.ravel(x),np.ravel(y),np.ravel(z)) # след. рисунок справа ax.set_xlim(-1,1) ax.set_ylim(-1,1) ax.set_zlim(-1,1) 150 Контурный график создается функцией Axes3D. contour(X,Y,Z, zdir=‟dir‟,offset=val[,...]), где X,Y,Z двумерные массивы, содержащие координаты узлов многогранной поверхности. При большом размере матриц контурные линии неотличимы от кривых. Строка „dir‟ может принимать значения „x‟, „y‟ или „z‟. Она задает направление проецирования. Соответствующие линии постоянного значения рисуются на плоскости x=val (y=val или z=val), положение которой задается опцией offset=val . Необязательный параметр cmap задает цветовую палитру. Необязательный аргумент levels задает вектор значений, для которых строятся контурные линии. pt=np.linspace(-3,3,41) X,Y=np.meshgrid(pt,pt) Z=Y*np.exp(-X**2-Y**2) fig=plt.figure() ax = fig.add_subplot(111, projection='3d') # следующий график слева ax.plot_surface(X,Y,Z,rstride=1,cstride=1,alpha=0.3) xlevels = np.array([0.,0.25,0.5,0.75,1,1.25,1.5,2]) ylevels = np.linspace( -0.5,0.5,20) zlevels = np.linspace( -0.5,0.5,20) ax.contour(X,Y,Z,zdir='x',offset= -3,cmap=mpl.cm.coolwarm, levels=xlevels) ax.contour(X,Y,Z,zdir='y',offset=3,cmap=mpl.cm.coolwarm, levels=ylevels) ax.contour(X,Y,Z,zdir='z',offset= -0.5,cmap=mpl.cm.coolwarm, levels=zlevels) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') Если заменить три инструкции предыдущего кода, содержащие функции ax.contour(...) следующими инструкциями: ax.contourf(X,Y,Z,zdir='x',offset=-3,cmap=mpl.cm.coolwarm, levels=xlevels,alpha=0.4) ax.contourf(X,Y,Z,zdir='y',offset=3, cmap=mpl.cm.coolwarm, levels=ylevels,alpha=0.2) 151 ax.contourf(X,Y,Z,zdir='z',offset= -0.5,cmap=mpl.cm.coolwarm, levels=zlevels) то будет построено изображение, показанное на предыдущем рисунке справа. Использованные здесь функции ax.contourf(...) аналогичны функциям ax.contour(...), но рисуют залитые контурные графики. Напомним также, что опция alpha=a, где 1 a 0 , задает прозрачность поверхности. Контурные линии (линии постоянного значения) в пространстве рисует функция Axes3D. contour3D(X,Y,Z,[,...]), где X,Y,Z двумерные массивы, содержащие координаты узлов многогранной поверхности. Аналогичная функция Axes3D. contourf3D(X,Y,Z,[,...]), рисует «сплошные» плоские контурные области в пространстве. Если функция Axes3D.contourf(X,Y,Z,N[,...]) не использует опцию offset, то она подобно функции contourf3D(...) рисует N «сплошных» плоских контурных областей в пространстве pt=np.linspace(-3,3,41) X,Y=np.meshgrid(pt,pt) Z=Y*np.exp(-X**2-Y**2) fig=plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') ax.contour3D(X,Y,Z, levels=zlevels) # след. рисунок слева Если вместо предыдущей инструкции выполнять по одной следующие строки, то вы получите другие рисунки. ax.contourf3D(X,Y,Z, levels=zlevels) # след. рисунок справа ax.contourf(X, Y, Z, 10) # след. рисунок слева ax.contourf(X, Y, Z, 10, offset=-0.5) # след. рисунок справа У функции Axes3D. contourf3D(X,Y,Z,[,...]) есть опция extend3d. Если ее установить в True, то она позволяет рисовать пространственные линии 152 уровня в форме полос (а не кривых). Совместно с ней используется опция stride=шаг, которая задает шаг по матрицам данных при рисовании полос уровня. pt=np.linspace(-3,3,61) X,Y=np.meshgrid(pt,pt) Z=Y*np.exp(-X**2-Y**2) fig=plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') cset = ax.contour(X,Y, Z,15,extend3d=True, cmap=mpl.cm.coolwarm, stride=1, zdir='z') # следующий рисунок слева Если графические функции вызываются общим объектом Axes3D, то и графики рисуются в общей трехмерной области. Удалите в предыдущем коде последнюю инструкцию и введите следующие: ax.contour(X, Y, Z, 15, stride=1, zdir='x') ax.contour(X, Y, Z, 15, stride=1, zdir='y') ax.contour(X, Y, Z, 15, stride=1, zdir='z') ax.set_title('3 contour sets ') Выполните пример, и получите изображение, показанное на предыдущем рисунке справа. Функция Axes3D.set_title(...) печатает заголовок графика. Функция Axes3D.quiver(X, Y, Z, U, V, W[, ...]) рисует трехмерное векторное поле. Здесь X, Y, Z являются трехмерными массивами, содержащими x, y и z координаты опорных точек (точек, к которым будут «привязаны» вектора), а U, V, W являются массивами того же размера, содержащие компоненты векторного поля. Опция length=число задает длину стрелок векторного поля. Опция pivot может принимать значения „tail‟, 'middle' и 'tip', и задает положение опорных точек векторов (начало, середина или конец). x, y, z = np.meshgrid(np.arange( -1, 1.5, 0.5), np.arange(-1, 1.5, 0.5), np.arange(-1, 1.5, 0.5)) u=x; v=y; w=z fig = plt.figure(facecolor='white') ax = fig.gca(projection='3d') ax.scatter3D(np.ravel(x),np.ravel(y),np.ravel(z),c='r') ax.quiver(x, y, z, u, v, w, length=0. 3,pivot='tail') 153 Пример. Несложно нарисовать двумерные графики на гранях параллелепипеда, например, плоские кривые. Для этого достаточно построить графики трехмерных кривых, третья координата которых равна константе. В следующем примере мы рисуем куб и на его гранях две синусоиды. Вначале создаются три функции, представляющие параметрическое уравнение поверхности куба. Поскольку у пользователя функция абсолютного значения может обозначаться по–разному (например, abs(x), np.abs(x), numpy.abs(x)), то эти функции xc(), yc() и zc() в качестве первого аргумента принимают ссылку Abs на эту функцию. Затем на гранях куба дорисовываются две синусоиды. # параметрическое уравнение куба def xc(Abs,u,v): return Abs(u)-Abs(u-1)-Abs(u-2)+Abs(u-3) def yc(Abs,u,v): return 1+Abs(v)-Abs(v-1) def zc(Abs,u,v): return 1-Abs(Abs(u -1)-Abs(u-2)-Abs(u-3)+Abs(u-4)+\ Abs(v-1)-Abs(v-2)+Abs(v)-Abs(v+1))/2+\ Abs(2+Abs(u-1)-Abs(u-2)-Abs(u-3)+\ Abs(u-4)+Abs(v-1)-Abs(v-2)+Abs(v) - Abs(v+1))/2 # изображение куба u=np.linspace(0,4,41) v=np.linspace( -1,2,31) U,V=np.meshgrid(u,v) X=xc(np.abs,U,V) Y=yc(np.abs,U,V) Z=zc(np.abs,U,V) fig=plt.figure(facecolor='white') ax=Axes3D(fig) surf=ax.plot_surface(X,Y,Z,rstride=1,cstride=1,color='0.75',alpha=0.85) ax.axis('image') # изображение синусод на гранях куба x = np.linspace(0, 2, 100) y = np.sin(8*np.pi*x) / 2 + 1 zer=np.zeros(np.size(x)) 154 ax.plot(x, y, 2,linewidth= 2) ax.plot( x, zer, y, 'r',linewidth= 2) Вообще то, кривые на параметрической поверхности следует строить, используя ее уравнения. Если уравнение поверхности имеет вид v u z z v u y y v u x x , , , , , , то для построения кривой на этой поверхности следует задать ее уравнение в виде t v v t u u , и подставить в уравнение поверхности: t v t u z t z t v t u y t y t v t u x t x , , , , , Результирующие функции t z t y t x , , будут представлять параметрическое уравнение кривой в пространстве, но кривая будет расположена на поверхности. Пример. В следующем примере мы реализуем эти построения графическими инструментами библиотеки matplotlib. Вначале мы создаем функции, представляющие параметрическое уравнение сферы v u zs v u ys v u xs , , , , , , затем задаем уравнение кривой функциями t vc t uc , . После этого мы создаем массивы X,Y,Z координат вершин многогранной поверхности, приближающей сферу, и строим ее. Затем создаем одномерные массивы XC, YC, ZC с координатами вершин ломаной, моделирующей кривую на поверхности, и строим ее. import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D xs=lambda u,v: np.cos(u)*np.cos(v) ys=lambda u,v: np.sin(u)*np.cos(v) zs=lambda u,v: np.sin(v) uc=lambda p: p vc=lambda p: p # построение поверхности u = np.linspace(0, 2 * np.pi, 51) v = np.linspace( -np.pi/2, np.pi/2, 51) U,V=np.meshgrid(u,v) X=xs(U,V) Y=ys(U,V) 155 Z=zs(U,V) fig=plt.figure(facecolor='white') ax=Axes3D(fig) surf=ax.plot_surface(X,Y,Z,rstride=2,cstride=2,color='0.75',alpha=0.85) ax.axis('im age') # построение кривой t = np.linspace(0, 2 * np.pi, 51) XC=xs(uc(t),vc(t)) YC=ys(uc(t),vc(t)) ZC=zs(uc(t),vc(t)) ax.plot(XC,YC,ZC,'y',linewidth=3) Вот еще несколько способов представления поверхностей Пример (X,Y,Z из предыдущего примера сферы) fig=plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') ax.contour3D(X,Y,Z, extend3d=True,stride=1) ax.axis('image') Пример (X,Y,Z из предыдущего примера сферы) fig=plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') # Следующий рисунок слева ax.contour3D(X,Y,Z,zdir='y') ax.contour3D(X,Y,Z,zdir='y') ax.contour3D(X,Y,Z,zdir='z') ax.axis('image') Добавьте в конце предыдущего примера следующие строки и выполните код. 156 fig=plt.figure(facecolor='white') # новый рисунок ax = fig.add_subplot(111, projection='3d') ax.contourf3D(X,Y,Z,zdir='z') # следующий рисунок справа ax.axis('image') В следующем коде дважды вызывается функция contour(X,Y,Z,...), где массивы X,Y,Z взяты из предыдущего примера сферы. В первом вызове функции опция offset не используется, и поэтому рисуются контурные линии на поверхности сферы. Во втором вызове использование опции offset=1 приводит к тому, что линии рисуются на плоскости z=1. fig=plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') ax.contour(X,Y,Z,20,zdir='z') # 3D контурные линии на сфере ax.contour(X,Y,Z,20,zdir='z',offset=1) # контурные линии на плоскости z=1 ax.axis('image') Кроме функций, строящих графики, в пакете matplotlib имеется ряд модулей с функциями, которые могут нарисовать в пространстве многоугольники, круги, напечатать текст, построить диаграмму и т.д. В следующем примере мы демонстрируем использование функций LineCollection и PolyCollection для построения ломаных линий и многогранных поверхностей в пространстве. import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib.collections import PolyCollection, LineCollection verts=[[(0,0),(1,1),(2,0.5),(3,2),(3,0)],[(0,2),(1,3),(2,0.75),(3,1), (4,0),(0,0)]] poly = PolyCollection(verts,closed=False, facecolors=[[1,0,0,0.5],[0,1,0,0.7]]) 157 lin = LineCollection(verts,linewidths=[3,4], colors=['r','g']) verts2=[[(0,1),(1,4),(2,3),(1,2),(0,1)]] lin2 = LineCollection(verts2,linewidths=[4], colors=['m']) fig = plt.figure(facecolor='white') ax = fig.gca(projection='3d') ax.add_collection3d(poly,zs=[1,2],zdir='y') ax.add_collection3d(lin,zs=[3,4],zdir='y') ax.add_collection3d(lin2,zs=[[1,0,1,2,1]]) ax.set_xlim3d(0, 4) ax.set_ylim3d(0, 4) ax.set_zlim3d( -1, 3) Вначале фигуры создаются как двумерные, используя функции LineCollection и PolyCollection. Затем при добавлении коллекций на трехмерные оси функция add_collection3d(...) использует опцию zs, которая может быть числом z 0 (фигуры в плоскости z=z 0 ), а для ломаных может быть массивом третьих координат. Функция Axes3D.bar(...) строит столбчатую диаграмму (набор столбиков) в пространстве. Она имеет следующий синтаксис: Axes3D.bar(x,y,z=0,zdir=‟z‟,color=массив_цветов, width=число[,...]) Опция zdir задает ориентацию прямоугольников (столбиков) диаграммы. Например, значение zdir=‟y‟ означает, что плоскости всех прямоугольников будут ортогональны оси Y. Вектор x задает абсциссу левых нижних углов столбиков, вектор y задает высоту столбиков, вектор z определяет аппликату (z–координату) левых нижних углов столбиков. Опция width определяет ширину столбиков, которая по умолчанию равна 0.8. Опция/вектор color задает цвет каждого столбика. В следующем примере мы строим три пространственные диаграммы. Первая и вторая расположены в плоскостях y=0 и y=1. Плоскости столбиков третьей диаграммы меняются от y=0.05 до 1. from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import numpy as np 158 fig = plt.figure(facecolor='white') ax = fig.add_subplot(111, projection='3d') xs1 = np.arange(20) # x координаты левых нижних углов столбиков ys1 = np.random.rand(20) # массив 20 чисел из диапазона [0,1) zs1=np.zeros(len(xs)) # z координаты столбиков cs1 = ['c'] * len(xs) # цвет столбиков ax.bar(xs1, ys1, zs=zs1, zdir='y', color=cs1, alpha=0.8 , width=0.9) xs2 = np.arange(20) ys2 = np.random.rand(20) # массив 20 чисел из диапазона [0,1) zs2=np.ones(len(xs)) # z координаты столбиков cs2 = ['g'] * len(xs) # цвет столбиков ax.bar(xs2, ys2, zs=zs2, zdir='y', color=cs2, alpha=0.8) xs3 = np.arange(20) ys3 = np.random.rand(20) zs3 = np.linspace(0.05,1,20) # z координаты столбиков cs3 = ['r'] * len(xs) # цвет столбиков ax.bar(xs3, ys3, zs=zs3, zdir='y', color=cs3, alpha=0.8) Трехмерные изображения, аналогично двумерным, могут содержать множество графических примитивов. Ими могут быть пространственные ломаные, прямоугольники, многоугольники, круги и т.д. |