Лекция 2. Графика: основные принципы.

II. Графика, порожденная функциями и другими числовыми данными

Двумерная графика

Как уже говорилось в начале, Mathematica  располагает спецальным арсеналом средств, позволяющих визуализировать числовые данные и функции. Самый простой и известный способ визуализировать функцию - это построить ее график. Это делается с помощью уже встречавшейся нам команды Plot.

Plot[Sin[x],{x,-π,π}]

На самом деле, команда Plot генерирует по данной функции графические примитивы, директивы и опции и формирует затем соответствующую команду Graphics.

InputForm[Plot[Sin[x],{x,-π,π}]] //Short

Таким образом, мы видим, что Plot, на самом деле, строит ломаую линию. При желании этим можно воспользоваться.

gg=Plot[Sin[x],{x,-π,π}];
gg[[1,1,3,1]]

Вот мы вычленили директиву, предшествующую собственно ломаной. Ее можно подменить например так.

gg[[1,1,3,1]]=Sequence[Red,Thick,Dashed];
gg

С одной стороны, в командах типа Plot можно использовать опции обычной графики. С другой стороны, есть и специальные способы управления, главные из которых PlotStyle и ColorFunction. Опция PlotStyle служит для использования уже знакомых нам графических директив. Mathematica теперь сама поставит их в нужное место в команде Graphics.

{Plot[{Red,Dashed,Thick,Sin[x]},{x,-π,π}],Plot[Sin[x],{x,-π,π},PlotStyle->{RGBColor[1,0,0], Dashed,Thick}]}

Опция ColorFunction служит для управления цветом изображаемого графика. Переменные этой функции фиксированы (для каждого типа графики - свои, для обычного Plot, например, это x, y). В качестве примера, раскрасим график в соответствие с кривизной соответствующей плоской кривой.

ClearAll[g];
cur[f_][t_]:=((Abs[D[f[t],t,t]])/(((1+((D[f[t],t])^2)))^(3/2)));
g[t_]=cur[Sin][t]; 
{Plot[Sin[x],{x,-π,π},PlotStyle->{Thick},ColorFunction-> Function[{x,y},Hue[((g[x])/1.1)]] ,ColorFunctionScaling-> False],
Plot[g[t],{t,-π,π}]}

Замечание. На самом деле, чтобы картина была реалистичной, надо отмасштабировать кривизну, чтобы она менялась между нулем 0 и 1 и не доходила до 1. Здесь мы пользуемся тем, что кривизна графика синуса меняется он нуля (красный) до единицы (синий).  Опция ColorFunctionScaling -> False отключает автоматическое масштабирование функции, отвечающей за цвет, которое затемняет дело.

Перечислим теперь встоенные возможности функции Plot. Во-первых, можно рисовать сразу несколько графиков, причем они автоматически получаются разноцветными. Можно и самим регулировать их вид (с помощью PlotStyle).

{Plot[{Sin[x],1.2Sin[2x],1.3Sin[3x]},{x,0,10}],Plot[{Sin[x],1.2Sin[2x],1.3Sin[3x]},{x,0,10},PlotStyle->{{Red,Thick},{Dashed,Blue},{Orange}}]}

Можно также закрашивать области, ограниченные графиком (графиками). Это исполняется с помощью опции Filling, значение которой устанавливается в тип заполнения (до оси, подграфик, надграфик).

Plot[{Sin[x],1.2Sin[2x],1.3Sin[3x]},{x,0,10},Filling-> {1->Axis,2->Bottom,3->Top}]

Более хитрый вид заполнения : для  2-го объекта выбрано заполнение до 1-го. Можно также добавить директивы, как именно заполнять.

{Plot[{Sin[x],1.4Sin[2x]},{x,0,10},Filling-> {2->{1}}],Plot[{Sin[x],1.4Sin[2x]},{x,0,10},Filling-> {2->{0,{Red,Blue}}}]}

Можно явно указать сколько точек участвуют в построении ломаной, изображающей кривую.Современные версии Mathematica сами следят за качеством графика, поэтому  PlotPoints  в двумерной графике - это начальное колическтво точек апрокисмации (по умолчанию равен 50). Если картинка Mathematica не нравится, она сама подразобьет кривую столько раз, сколько ей захочется. Чтобы запретить это, нужно ограничить рекурсию с помощью опции MaxRecursion (которая устанавливается в количество итераций). Чтобы увидеть точки, нужно использовать опцию Mesh.

{Plot[Sin[x],{x,-π,π},Mesh->All,MaxRecursion->0],Plot[Sin[x],{x,-π,π},PlotPoints->5,Mesh->All,MaxRecursion->0],
Plot[Sin[x],{x,-π,π},PlotPoints->5,Mesh->All,MaxRecursion->1],Plot[Sin[x],{x,-π,π},PlotPoints->5,Mesh->All]}

Иногда полезно исключить из рассмотрения какие - нибудь точки. Для этого служит опция Exclusions, которая устанавливается в условие.

{Plot[Tan[x],{x,-2π,2π}],Plot[Tan[x],{x,-2π,2π},Exclusions->{Cos[x]==0}]}

К двумерным способам представления числовых данных относятся также ListPlot, ListLinePlot, ArrayPlot, 
PolarPlot, ParametricPlot, 
ContourPlot, DensityPlot 
и RegionPlot.
Первые три служат для изображения дискретных данных (одномерных или двумерных). Вот одномерные данные.

data=Table[Random[],{20}];
 {ListPlot[data,Filling->Axis],ListLinePlot[data,Filling->Axis]}

А вот -  двумерные. Обратите внимание, что ListLinePlot просто соединяет последовательные точки линией.

data=Table[{Cos[#],Sin[#]}&[Random[Real,2π]],{i,1,40}];
{ListPlot[data,AspectRatio->Automatic],ListLinePlot[data, AspectRatio->Automatic]}

ArrayPlot изображает числа строки в виде раскрашенных квадратиков. По умолчанию они черно-белые, но можно их и раскрасить.

ArrayPlot[Transpose[data]]

Можно задать цвета явно с помощью правил ColorRules, можно использовать ColorFunction. Мы нарисуем число π.

curpet[x_,m_,n_]:=Module[{res,xx,i}, (* Эта программа вычисляет цифры числа x и организовывает их в массив*)
xx=N[x,m n];
res={RealDigits[xx,10,m][[1]]};
xx=xx/(10^(RealDigits[xx,10,m][[2]]));
For[i=1,i≤n-1,i++,
res=res~Join~{RealDigits[xx,10,m,-m i-1][[1]]}
];
res
];
rules={0->Red,1->Pink,2->Orange,3->Brown,4->Yellow,5->Green,6-> Cyan,7->Blue,8->Magenta,9->Purple};

{ArrayPlot[curpet[π,40,40],ColorRules->rules],ArrayPlot[curpet[π,40,40],ColorFunction->"Pastel"],ArrayPlot[curpet[π,40,40],ColorFunction->"Rainbow"]}

PolarPlot удобен для рисования кривых, заданных в полярных координатах. Имеется также его модификация ListPolarPlot.

PolarPlot[{1,1+1/2 Sin[10t],1/2},{t,0,2Pi},PlotStyle->{Green,{Dashed,Thick,Orange},{Thickness[0.005],Green}}]

Универсальный инструмент для рисования кривых - это, конечно, ParametricPlot. Он теперь сразу позволяет рисовать однопараметрические семейства или области.

{ParametricPlot[{Cos[x],Sin[2x]},{x,0,2π}],ParametricPlot[r{Cos[x],Sin[2x]},{x,0,2π},{r,0.5,1.5}],ParametricPlot[r{Cos[x],Sin[2x]},{x,0,2π},{r,0.5,1.5},Mesh->None]}

Можно использовать это для рисования, например, координатных линий.

{ParametricPlot[{x,y},{x,-1,1},{y,-1,1},Axes->False,Frame->False],ParametricPlot[{r Cos[φ],r Sin[φ]},{φ,0,2π},{r,0,1},Axes->False,Frame->False]}

Или для наглядного изображения отображений из плоскости в плоскость.

F[u_,v_]:={Re[(((u +I v))^(1/3))],Im[(((u+I v))^(1/3))]};
{ParametricPlot[{u,v},{u,-1,1},{v,-1,1},Frame->False,MeshStyle->{Orange,Green}],ParametricPlot[F[u,v],{u,-1,1},{v,-1,1},Frame->False,MeshStyle->{Orange,Green},AxesOrigin->{0,0}]}

FF[r_,φ_]:={Re[(r^(1/3))(E^(I (φ/3) ))],Im[(r^(1/3))(E^(I (φ/3) ))]};
{ParametricPlot[{r Cos[φ],r Sin[φ]},{r,0,1},{φ,-π,π},Frame->False,MeshStyle->{Orange,Green}],ParametricPlot[FF[r,φ],{r,0,1},{φ,-π,π},Frame->False,MeshStyle->{Orange,Green},AxesOrigin->{0,0}]}

DLP[r_,φ_]:=Module[{z,z0,w},
z=r (E^(I φ));
z0=1/2;
w=((z-z0)/(1-z Conjugate[z0]));
{Re[w],Im[w]}
];
{ParametricPlot[{r Cos[φ],r Sin[φ]},{r,0,1},{φ,-π,π},Frame->False,MeshStyle->{Orange,Green}],ParametricPlot[DLP[r,φ],{r,0,1},{φ,-π,π},Frame->False,PlotPoints->50,MeshStyle->{Orange,Green},AxesOrigin->{0,0}]}

Снова можно задавать осмысленные функции для раскраски кривой. Например, кривизну. Напомним, что красный соответствует нулю, и цвет меняется в синюю сторону при возрастании.

cur[x_,y_][t_]:=((Abs[D[x[t],t,t]D[y[t],t]-D[y[t],t,t]D[x[t],t]])/(((((D[x[t],t])^2)+((D[y[t],t])^2)))^(3/2)));

ClearAll[gg];
xx[t_]:=Log[t ]Cos[t]; yy[t_]:=Log[t] Sin[t];
gg[t_]=cur[xx,yy][t] ;

mm=NMaximize[gg[t],t][[1]]

Plot[gg[t],{t,0.1,2π}]

ParametricPlot[{xx[t],yy[t]},{t,1/2,7π},PlotStyle->Thick,ColorFunction->Function[{x,y,u},Hue[((gg[u])/(1.2 mm))]],ColorFunctionScaling->False]

Команды ContourPlot и DensityPlot служат для рисования неявно заданных кривых и функций.

{ContourPlot[Cos[x]+Cos[y],{x,0,4Pi},{y,0,4Pi}],ContourPlot[Cos[x]+Cos[y]==1/2,{x,0,4Pi},{y,0,4Pi}],
DensityPlot[Cos[x]+Cos[y],{x,0,4Pi},{y,0,4Pi}]}

Наконец, RegionPlot изображает области, заданные неравенствами.

RegionPlot[1/4≤x^2+(2y)^2≤1 &&x+y≤1/2,{x,-1,1},{y,-1,1},AspectRatio->Automatic]

Трехмерная графика

Практически все команды двумерной графики имеют аналоги в трехмерной. Снова рассторим сначала простейшую команду рисования графика функции двух переменных Plot3D.

Plot3D[ y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π}]

Эта команда порождает графический комплекс с заданными нормалями вершин.

InputForm[Plot3D[ y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π}]]//Short

Точнее

Plot3D[ y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π},PlotStyle-> FaceForm[Red,Blue],PlotPoints->2,Mesh->All,MaxRecursion->0]

InputForm[Plot3D[ y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π},PlotPoints->2,Mesh->All,PlotStyle-> MaxRecursion->0]]

Снова можно пользоваться стандартными опциями трехмерной графики, снова есть PlotStyle для директив. Из новых опций обратим внимание на BoundaryStyle (приписывается графическая директива, описывающая граничную линию), Exclusions и ExclusionStyle (исключения из рисунка условие и способ прорисовки ограничивающей линии) и RegionFunction (функция от стандартного набора переменных), MeshFunction (приписывается функция или функции, линии уровня которых задают линии на поверхности), Mesh приписывается количество линий.

Plot3D[y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π},MeshFunctions-> {#3&},MeshStyle->{Orange},PlotStyle->FaceForm[Directive[Red,Specularity[White,2]],Blue],BoundaryStyle-> {Thick,Red}]

Plot3D[y Sin[x]+y Sin[x],{x,-π,π},{y,-π,π},PlotStyle->FaceForm[Directive[Red,Specularity[White,2]],Blue],BoundaryStyle-> {Thick,Red},MeshFunctions-> {(((#1)^2)+((#2)^2))&},Mesh->5,RegionFunction-> Function[{x,y,z},1/2<(x^2)+(y^2)<3]]

Из других способов рисования отметим, прежде всего, ParamrtricPlot3D, позволяющий рисовать параметрически заданные поверхности и кривые, его частные случаи RevolutionPlot3D и SphericalPlot3D, неявно заданные поверхности ContourPlot3D, трехмерные области заданные неравенствами RegionPlot3D, а также трехмерные рисовалки дискретных данных, такие как ListPlot3D, ListPointPlot3D, ListSurfacePlot3D.

В качестве примера рассмотрим знаменитую поверхность Боя - параметризацию проективной плоскости. Явные формулы взяты из задачника А.С.Мищенко, Ю.П.Соловьев, А.Т.Фоменко.

ClearAll;
f1[θ_,φ_]:= (1/2)((2(x^2)-(y^2)-(z^2))((x^2)+(y^2)+(z^2))+2 y z ((y^2)-(z^2))+z x((x^2)-(z^2))+x y ((y^2)-(x^2)))/.{x-> Cos[θ]Cos[φ],y-> Cos[θ]Sin[φ],z-> Sin[θ]};
f2[θ_,φ_]:= ((Sqrt[3])/2)(((y^2)-(z^2))((x^2)+(y^2)+(z^2))+z x((z^2)-(x^2))+x y ((y^2)-(x^2)))/.{x-> Cos[θ]Cos[φ],y-> Cos[θ]Sin[φ],z-> Sin[θ]};
f3[θ_,φ_]:=(x+y+z)((((x+y+z))^3)+4(y-x)(z-y)(x-z))/.{x-> Cos[θ]Cos[φ],y-> Cos[θ]Sin[φ],z-> Sin[θ]};
r[θ_,φ_]:={f1[θ,φ],f2[θ,φ],0.1f3[θ,φ]};

Сначала нарисуем эту сложную самопересекающуюся поверхность, разрезая ее на горизонтальные слои и выбрасывая каждый второй, чтобы можно было лучше рассмотрть самопересечения. Это делается с помощью опций MeshFunctions (устанавливается в функцию от стандартных переменных), MeshShading (определяет что рисовать между Mesh-линиями, присваивается список (списки) цикличекски повторяющихся директив; None соответствует ничего не рисованию) и Mesh или количество равномерно распределенных линий, или явные значения MeshFunction.

ParametricPlot3D[r[θ,φ],{θ,-π/2,π/2},{φ,0,π},MeshFunctions->{#3&},MeshShading-> {Directive[{Orange,Opacity[0.9],Specularity[White,2]}],None},PlotPoints-> 30,Mesh-> {{-0.05,0.05,0.1,0.2,0.3,0.4}}]

Выделить наиболее сложный фрагмент можно с помощью опции RegionFunction (функция, условие).

ParametricPlot3D[r[θ,φ],{θ,-π/2,π/2},{φ,0,π},PlotStyle-> Directive[{Orange,Opacity[0.9]}],Mesh->None,PlotPoints-> 30,RegionFunction-> Function[{x,y,z},0.05<z<0.2],Boxed->False,Axes->None]

Координатные линии на поверхности можно увидать, сменив MeshFunctions. Заодно разрежем ее в шахматном порядке.

ParametricPlot3D[r[θ,φ],{θ,-π/2,π/2},{φ,0,π},MeshFunctions->{#4&,#5&},MeshShading-> {{Directive[{Orange,Opacity[0.9],Specularity[White,2]}],None},{None,Directive[{Orange,Opacity[0.9],Specularity[White,2]}]}},PlotPoints-> 30,PlotStyle->{Opacity[0.5]},MeshStyle->{{Thick,Red},{Thick,Brown}}]

Наконец, чтобы лучше себе представить параметризацию, выбросим края параметризующего прямоугольника. Граница выделяется с помощью BoundaryStyle.

ParametricPlot3D[r[θ,φ],{θ,-π/2+0.1,π/2-0.1},{φ,0.1,π-0.1},MeshFunctions->{#4&,#5&},PlotPoints-> 30,PlotStyle->{Orange,Opacity[0.9],Specularity[White,2]},BoundaryStyle->{Red,Thick}]

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

gr={ParametricPlot3D[r[θ,φ],{θ,-π/2,-π/2+0.1},{φ,0,π},BoundaryStyle->{Red,Thick},Mesh->None,PlotRange->1.2],ParametricPlot3D[r[θ,φ],{θ,π/2-0.1,π/2},{φ,0,π},BoundaryStyle->{Red,Thick},Mesh->None,PlotRange->1.2],
ParametricPlot3D[r[θ,φ],{θ,-π/2,π/2},{φ,0,0.1},BoundaryStyle->{Red,Thick},Mesh->None,PlotRange->1.2],
ParametricPlot3D[r[θ,φ],{θ,-π/2,π/2},{φ,π-0.1,π},BoundaryStyle->{Red,Thick},Mesh->None,PlotRange->1.2]};

А теперь посмотрим все сразу с помощью Show и окончатльно увидим лист Мёбиуса, заклеивающий границу диска.

Show[gr]

Наконец, раскрасим поверхность ее гауссовой кривизной. Сначала вычислим ее.

iForm[r_][u_,v_]:=Module[{ru,rv}, 
ru=D[r[u,v],u];rv=D[r[u,v],v];
(({{ru.ru, ru.rv}, {ru.rv, rv.rv}}))
];
norm[r_][u_,v_]:=Module[{ru,rv,nn},
ru=D[r[u,v],u];rv=D[r[u,v],v];nn=Cross[ru,rv];
(nn/(Sqrt[nn.nn]))
];
iiForm[r_][u_,v_]:=Module[{ruu,ruv,rvv,n},
n=norm[r][u,v]; 
ruu=D[r[u,v],u,u];ruv=D[r[u,v],u,v];rvv=D[r[u,v],v,v];
(({{ruu.n, ruv.n}, {ruv.n, rvv.n}}))
];
k[r_][u_,v_]:=((Det[iiForm[r][u,v]])/(Det[iForm[r][u,v]]));

Параметризуем тор.

ClearAll[R,r];
res=(({{Cos[φ], -Sin[φ], 0}, {Sin[φ], Cos[φ], 0}, {0, 0, 1}})).({0,R,0}+{0,r Cos[ψ],r Sin[ψ]})//Simplify;
R=3;r=1;
torus[φ_,ψ_]:={-(R+r Cos[ψ]) Sin[φ],Cos[φ] (R+r Cos[ψ]),r Sin[ψ]};

Масштабируем кривизну так, чтобы она принимала значения от 1 до 1/2.

g[u_,v_]=k[torus][u,v]//Simplify;
kMax=Maximize[g[u,v],{u,v}][[1]];
kMin=Minimize[g[u,v],{u,v}][[1]];
kRescaled[u_,v_]:=((g[u,v]-kMin)/(1.2(kMax-kMin)));

Теперь раскрашиваем тор с помощью ColorFunction.

ParametricPlot3D[torus[φ,ψ],{φ,0,2π},{ψ,0,2π},Boxed->False,Axes->False,ColorFunction->Function[{x,y,z,u,v},Hue[kRescaled[u,v]]] ,ColorFunctionScaling->False,Mesh->None]

Или седловую поверхность.

sadd[x_,y_]:={x,y,(x^2)-(y^2)};
kM[x_,y_]:=k[sadd][x,y]//Simplify;
kMax=Maximize[kM[u,v],(u^2)+(v^2)≤2,{u,v}][[1]];
kMin=Minimize[kM[u,v],{u,v}][[1]];
kRes[u_,v_]=((kM[u,v]-kMin)/(1.4(kMax-kMin)));
ParametricPlot3D[sadd[x,y],{x,-2,2},{y,-2,2},Boxed->False,Axes->False,RegionFunction->Function[{x,y,z,u,v},((x^2)+(y^2)<1/2)],ColorFunction->Function[{x,y,z,u,v},Hue[kRes[x,y]]],ColorFunctionScaling-> False,Mesh->False,BoundaryStyle->{Thick,Blue}]

Поверхности уровня удобно рисовать с помощью ContourPlot3D (функция, интервалы значения переменных, какие (или сколько именно) значения функции рисовать (Contours приписывается количество значений или их список), директивы, описывающие как именно рисовать поверхности (ContourStyle приписывается список директив))

ContourPlot3D[(x^2)+(y^2)-(z^2),{x,-2,2},{y,-2,2},{z,-2,2},Contours-> {-1,0,1},ContourStyle->Map[{#,Opacity[0.5]}&,{Blue,Red, Yellow}],Mesh->None,RegionFunction->(((#1)^2)+((#2)^2)<2&)]

Следующие команды  ListPlot3D, ListPointPlot3D, ListSurfacePlot3D служат для визуализации дискретных наборов чисел.

{ListPlot3D[{{1,2,3,4},{1,1,1,1},{4,3,2,1},{4,4,4,4}},Mesh->All],ListPlot3D[{{1,2,3,4},{1,1,1,1},{4,3,2,1},{4,4,4,4}},Mesh->None,InterpolationOrder->0],ListPlot3D[{{1,2,3,4},{1,1,1,1},{4,3,2,1},{4,4,4,4}},Mesh->None,InterpolationOrder->3]}

{ListPointPlot3D[Table[(i^2)-(j^2),{i,-1,1,0.1},{j,-1,1,0.1}]],ListPointPlot3D[Table[(i^2)-(j^2),{i,-1,1,0.1},{j,-1,1,0.1}],Filling->Bottom]}

Наконец, ListSurfacePlot3D служит для визуализации набора точек в пространстве.

ListSurfacePlot3D[Flatten[Table[{i,j,(i^2)-(j^2)},{i,-1,1,0.1},{j,-1,1,0.1}],1]]

RegionPlot3D[-1≤x≤1&&-1≤y≤1&&-0.2≤z≤0.2&& Not[-1/2≤x≤1/2&&-1/2≤y≤1/2],{x,-2,2},{y,-2,2},{z,-2,2},Mesh->None,PlotPoints->50,Axes->None,Boxed->False,PlotStyle-> {Pink}]