Math 421  •  Fall 2010

Visualizing complex functions

25 September 2010

Copyright © 2004–2010 by Murray Eisenberg. All rights reserved.

Introduction

This notebook shows how to use David Park's Presentations add-on application to visualize functions f:ℂ->ℂ. The appendix describes how to use, instead, the more limited capabilities provided by the built-in Mathematica function ParametricPlot.

Prerequisites

Mathematica

Most of this notebook requires David Park's Mathematica add-on application Presentations.

Presentations should be loaded by evaluating the expression:
	<<Presentations`
That initialization is done below, in the Initialization section, below.

You should already know about the Presentations functions ComplexPoint, ComplexCurve, ComplexLine, ComplexCircle, etc., that form complex objects as well as the Presentations function Draw2D. See notebooks nthRoots.nb and DrawingComplexObjects.nb.

Mathematics

You should already know the algebra of complex numbers and polar representation of complex numbers as well as the idea of a function f:ℂ->ℂ, that is, a complex-valued function of a complex variable.

Initialization

When you opened this notebook, it should have prompted you whether you want to evaluate Initialization Cells. You should have answered “yes.”
If you did not, then evaluate the following Input cell now. (Even if the cell was already evaluated, it won’t hurt if you evaluate it again.)

<<Presentations`

Example 1: f(z) = (z^2)

Most of this notebook concerns visualizing just the single example f(z) =  (z^2). A couple of other examples are treated more briefly below.

Be sure to evaluate the following input cell before proceeding:

f[z_]:=(z^2)

Plotting real and imaginary parts of a function

The objective is to visualize the composite functions Re ∘f and Im ∘f—the real part and the imaginary part, respectively, of the complex function f. Each is a function from the complex plane ℂ to the real line ℝ. If we regard ℂ as the Cartesian plane (ℝ^2), then the graph of each is a surface in (ℝ^3).

Using Cartesian coordinates to plot real and imaginary parts of a function with built-in Mathematica functions

In this section we use only built-in Mathematica functions, and so we have to resort directly to Cartesian coordinates.

Finding the real and imaginary parts of a function in terms of Cartesian coordinates

Here is the formula for the function f in terms of the real part x and the imaginary part y of an input z = x + i y…

f[x+I y]

…and here is that formula in Cartesian form after the squaring is done:

Expand[f[x+I y]]

(ComplexExpand will give you the same thing there as Expand.)

We humans cannot directly visualize the graph
	{z,f(z):z∈ℂ}
of f:ℂ->ℂ directly. Why not? You shall see in a moment.

Form the "real part" u and "imaginary part" v of the function f. These are the functions u(x,y) and v(x,y) for which
 	f(x+i y)=u(x,y)+i v(x,y)
 when x and y are real. In Mathematica:

u[x_,y_] := ComplexExpand@Re[f[x+I y]]
v[x_,y_] :=ComplexExpand@Im[f[x+I y]]

{u[x,y],v[x,y]}

Exercise . Check that those are really the real and imaginary parts of f by calculating u(x,y)+i v(x,y) by hand and then with Mathematica.

Exercise . Find the real and imaginary parts of g(z)=(z^3) both by hand and with Mathematica.

Strictly in terms of real and imaginary parts, think of f as the following function F:(ℝ^2)->(ℝ^2) from the plane to itself:

F[x_,y_]:={u[x,y],v[x,y]}

F[x,y]

Since F:(ℝ^2)->(ℝ^2), then:
	graph(F) ={ (  (x,y), F(x,y)  )  : (x,y)∈ℂ }   
                        =  { (  (x,y}, ( u(x,y),v(x,y) )  ) : (x,y) ∈ ℂ } ⊂ (ℝ^4) 
Thus the graph of F is a subset of 4-dimensional space. That's why you cannot directly visualize it.

However, you can directly visualize the graphs of
	u:(ℝ^2)->ℝ and v:(ℝ^2)->ℝ,
because these are subsets of 3-dimensional space (ℝ^3) given by:
	 graph(u)={  (x,y,u(x,y) ) : (x,y)∈(ℝ^2) }= {  (x,y,(x^2)-(y^2) ) : (x,y)∈(ℝ^2) } ⊂ (ℝ^3),
	 graph(v)={  (x,y,v(x,y) ) : (x,y)∈(ℝ^2) }= {  (x,y,2x y ) : (x,y)∈(ℝ^2) }⊂ (ℝ^3)

These graphs will be drawn below.

Visualizing the real and imaginary parts of a function in terms of Cartesian coordinates

Here is the graphs of the function u(x,y) and v(x,y) in (ℝ^3), drawn using the built-in Mathematica function Plot3D.  (The option BoxRatios is used so that the scale on the vertical axis appear to be the same as that on the x- and y-axes).

uVSxy=Plot3D[u[x,y],{x,-2,2},{y,-2,2},BoxRatios->{1,1,0.8`}]

vVSxy=Plot3D[v[x,y],{x,-2,2},{y,-2,2},BoxRatios->{1,1,0.8`}]

Although it’s not obvious, the (x,y) plane is parallel to the bottom of the box, and the u- and v-axes, respectively, run perpendicular to the bottom. Labeling the axes will help. So here are the same things but in each case with labels for the axes, as well as a label for the plot:

uVSxy=Plot3D[u[x,y],{x,-2,2},{y,-2,2},
BoxRatios->{1,1,0.8`},
AxesLabel->TraditionalForm/@{x,y,u},PlotLabel->TraditionalForm[Re[f]],
ImageSize->3 72]

You can rotate such a 3D graph by moving the cursor over it and then, while holding down the mouse button, moving the mouse around.

The value for the option ImageSize is specified in printer's points. So with 72 printer's points to the inch, the specified image size is 7 inches.

vVSxy=Plot3D[v[x,y],{x,-2,2},{y,-2,2},AxesLabel->TraditionalForm/@{x,y,v},BoxRatios->{1,1,0.8`},PlotLabel->TraditionalForm[Im[f]],
ImageSize->3 72]

Here are both graphs together:

Row[{uVSxy,Spacer[20],vVSxy}]

To interactively change the size of each drawing, click on the drawing and then drag its "handles".
You may still rotate each of the surfaces in the usual way.

In the list argument of Row above, the middle item, Spacer[20]  inserts extra space; the argument of Spacer is in printer's points (at the usual 72 points per inch).

Next, add an overall label. To do this, stack into a Column the desired text as one item, and the same Row as before as the second item.

Column[{
Style[TraditionalForm@HoldForm[f[z]==(z^2)],FontFamily->"Times"],
Row[{uVSxy,Spacer[20],vVSxy}]
},Alignment->Center]

For cruder labeling, you could eliminate the Style treatment of the text and omit the Alignment option of Column.

Another way to place two drawings next to one another is to use GraphicsRow instead of Row and then just use a PlotLabel option to label the entire figure:

GraphicsRow[{uVSxy,vVSxy},PlotLabel->TraditionalForm@HoldForm[f[z]==(z^2)],ImageSize->7 72]

To interactively change the size of the that overall two-graph figure, click on it and then drag one of the "handles". But you cannot now interactively change the size of just one of the two drawings.
However, you may still rotate each of the surfaces in the usual way.

Exercise . Similarly, visualize the real and imaginary parts of g(z)=(z^3).

Exercise . Visualize together |z| and Arg(z) by using Plot3D.

Evidently, forming the expression with GraphicsRow is easier than with Row—in particular, in constructing the label for the overall figure. So why was it done first by the more complicated method, with Row? For two reasons:
	• GraphicsRow forces both drawings to become the same size, whereas Row keeps the original sizes of both. This behavior of GraphicsRow may be undesirable behavior when you are trying to compare two drawings, e.g., when one shows the domain of a complex function and the other shows the image of that function.
	• When the drawings are made dynamic, so as to depend on one or more control variables, within a Manipulate expression, and when one of those controls is a Locator—see below—then GraphicsRow will not work correctly.

Using Cartesian coordinates to plot real and imaginary parts of a function with Presentations

Using Presentations Draw3D items instead of built-in Mathematica Plot3D

As an alternative to using Mathematica's built-in Plot3D, you may use the Presentations function Draw3DItems. This has two advantages:
	• Draw3DItems uses the same paradigm as Draw2D, where you just form a list of graphics directives and graphics objects (whereas to include additional objects with Plot3D, you need to use Mathematica's Epilog or Prolog options).
	• Among Draw3D items you may include special three-dimensional complex objects involving the "Riemann sphere", as you shall see in the notebook RiemannSphere.nb.

At first we shall still need the expressions u(x,y) and v(x,y) for the real and imaginary parts of f as functions of Cartesian coordinates (u,v).

Here is the same example as above, but now done using Draw3DItems.

uVSxy=Draw3DItems[
{
Draw3D[u[x,y],{x,-2,2},{y,-2,2}]
},
Axes->True,BoxRatios->{1,1,0.8},
AxesLabel->TraditionalForm/@{x,y,u},PlotLabel->TraditionalForm[Re[f]],
ImageSize->3 72]

vVSxy=Draw3DItems[
{
Draw3D[v[x,y],{x,-2,2},{y,-2,2}]
},
Axes->True,BoxRatios->{1,1,0.8},
AxesLabel->TraditionalForm/@{x,y,v},PlotLabel->TraditionalForm[Im[f]],
ImageSize->3 72]

GraphicsRow[{uVSxy,vVSxy},PlotLabel->TraditionalForm@HoldForm[f[z]==(z^2)],ImageSize->7 72]

Exercise . Produce essentially the same figure as the preceding output but by using Row instead of GraphicsRow. (You will need to use a Column in order to produce an overall label over the pair of drawings.)

Exercise . Similarly, visualize the real and imaginary parts of g(z)=(z^3).

Exercise . Visualize together|z| and Arg(z) by using Draw3DItems.

Using Presentations ComplexCartesianSurface

Presentations provides the function ComplexCartesianSurface as another way to plot the real and imaginary parts of a function f∶ℂ->ℂ, that is, to plot the composite functions Re ∘f:(ℝ^2)->ℝ and  Im ∘f:(ℝ^2)->ℝ, so that you do not first have to express things in terms of Cartesian coordinates. In fact, with ComplexCartesianSurface, you can plot other composites g ∘f:(ℝ^2)->ℝ where g:ℝ->ℝ is an arbitrary function! (For example, g could be the modulus or principal argument function.)

As you can discover by inserting a template for ComplexCartesianSurface by using the Surfaces group in the ComplexGraphics section of PresentationsPalette, the syntax of ComplexCartesianSurface is:
	ComplexCartesianSurface[expr,realfunction,{z,zmin,zmax}]
Here expr is the expression for the function of the complex variable z (in our example, f[z]); realfunction is the name of the function g to be composed with the former; z is the variable name; and as usual zmin and zmax give the lower-left corner and upper-right corner of the rectangle in the complex plane.

realPart=Draw3DItems[
{
ComplexCartesianSurface[f[z],Re,{z,-2-2I,2+2I}]
},
Axes->True,BoxRatios->{1,1,0.8},
AxesLabel->{x,y,None},PlotLabel->TraditionalForm[Re[f]],
ImageSize->3 72]

imaginaryPart=Draw3DItems[
{
ComplexCartesianSurface[f[z],Im,{z,-2-2I,2+2I}]
},
Axes->True,BoxRatios->{1,1,0.8},
AxesLabel->{x,y,None},PlotLabel->TraditionalForm[Re[f]],
ImageSize->3 72]

GraphicsRow[{realPart,imaginaryPart},PlotLabel->TraditionalForm@HoldForm[f[z]==(z^2)],ImageSize->7 72]

That's all it takes: no muss, no fuss,no bother!

Of course you may want to enhance the graphs, just as you'll see in some of the Documentation Center examples for ComplexCartesianSurface. Here is an example of doing that.

realPart=Draw3DItems[
{
Opacity[0.8,HTML@DarkSeaGreen],
ComplexCartesianSurface[f[z],Re,{z,-2-2I,2+2I},
Mesh->None]
},
BoxRatios->{1,1,0.8},
Axes->True,AxesLabel->{x,y,None},
NeutralLighting[0.1,0.6,0.1],
PlotLabel->Style[TraditionalForm[Re[f]],Darker@Green],
ImageSize->3 72]

The curves on the surfaces that you saw previously were slices by planes with constant x-coordinates and constant y-coordinates. The option Mesh->None in ComplexCartesianSurface eliminates those.
The NeutralLighting expression in Draw3DItems prevents the normal Mathematica lighting of the surface from overwhelming the color of the surface itself. It controls the strength of the usual red, green, and blue "spotlights" that Mathematica would use by default to illuminate the surface (more specifically, it controls those colored lights' saturation and brightness as well as the ambient light level).
You'll see shortly why the color of the plot label was changed to green.

Here's a similar drawing but now for the imaginary part.

imaginaryPart=Draw3DItems[
{
Opacity[0.8,Orange],
ComplexCartesianSurface[f[z],Im,{z,-2-2I,2+2I},
Mesh->None]
},
BoxRatios->{1,1,0.8},
Axes->True,AxesLabel->{x,y,None},
NeutralLighting[0.1,0.6,0.1],
PlotLabel->Style[TraditionalForm[Im[f]],Darker@Orange],
ImageSize->3 72]

Put the two drawing side-by-side in the usual way:

GraphicsRow[{realPart,imaginaryPart},PlotLabel->TraditionalForm@HoldForm[f[z]==(z^2)],ImageSize->7 72]

Exercise . Similarly, visualize the real and imaginary parts of g(z)=(z^3).

Exercise . Similarly, visualize the real and imaginary parts of h(z)=1/z.

Exercise . Visualize together|z| and Arg(z) by using Draw3DItems and ComplexCartesianSurface.

For an alternative way of displaying the two surfaces graphs, we have one more trick up our sleeves from Presentations: superimpose the two graphs. To help prepare the way for doing that, earlier we made the surfaces somewhat transparent and removed the mesh lines on them was .
Since the rectangular plot region has the same corners for both surfaces, rather than insert the corners explicitly as the same complex numbers for both surfaces, we'll assign those values first to name zmin and zmax; to localize those values, we'll enclose the whole thing in a Mathematica With expression. Then should you want to change the plot regions, you need to do it in only one place, right near the start.

With[{zmin=-2-2I,zmax=2+2I},
Draw3DItems[
{
Opacity[0.8,Green],
ComplexCartesianSurface[f[z],Re,{z,-2-2I,2+2I},
Mesh->None],

Opacity[0.8,Orange],
ComplexCartesianSurface[f[z],Im,{z,-2-2I,2+2I},
Mesh->None]
},
BoxRatios->{1,1,0.8},
Axes->True,AxesLabel->{x,y,None},
NeutralLighting[0.1,0.6,0.1],
PlotLabel->Row[{
Style[Real,Darker@Green]," and ",Style[Imaginary,Darker@Orange]," parts of ",
TraditionalForm[HoldForm[f[z]]," = ",f[z]]
}],
ImageSize->3 72,BaseStyle->12]
]

Exercise . Similarly, visualize the real and imaginary parts of g(z)=(z^3).

Exercise . Similarly, visualize the real and imaginary parts of h(z)=1/z.

Exercise . Draw the graphs of the modulus and principal argument of f(z)=(z^2).

Exercise . Similarly, draw the graphs of the modulus and principal argument of h(z)=1/z.

Using Cartesian coordinates to visualize how f maps the plane

For graphics, this section uses functions from Presentations for visualizing f in terms of Cartesian coordinates. (See Appendix 1 for information on how to do it—albeit not as nicely—with the built-in Mathematica functions.)

Remember that the function f is given by:

f[z_]:=(z^2)

Drawing a Cartesian grid

A common way to visualize a map ℂ->ℂ is to see what it does to a grid of horizontal and vertical lines—a Cartesian (or “rectangular”) grid. So first we need to draw such a grid. Here is the kind of drawing we are after:

The final version of the input to produce the preceding drawing appears in an Input cell later. You may wish to look at that first and evaluate it, then return here to see the step-by-step process leading to it.

To draw such a grid involves two steps: first, constructing the grid using DrawCartesianMap; and second, displaying the grid using Draw2D.

Step 1: Construct the grid. The first argument to DrawCartesianMap is just z, indicating that the horizontal and vertical lines constituting the grid are not to be transformed in way. The second argument is a list of the form
	{z,zmin,zmax}
where zmin and zmax are the complex numbers designating the lower-left corner and the upper-right corner, respectively, of the rectangle for the grid.

Here is the grid we shall use:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I}];

The output there was suppressed by the semicolon at the end. Here's just a part of it:

grid//Short

The <<898>> and <<1>> denote the 898 parts of grid the one part at the end omitted from the output display.

The value of grid has a rather complicated structure. Ordinarily you won’t want to see the value as output. But the essence of the value is that its first part is a list of coordinates of points where the horizontal and vertical lines of the grid intersect—along with points one the lines between those intersections so as to permit more precise drawing.

Step 2: Display the grid. For this, use Draw2D as usual.

Draw2D[{
DrawCartesianMap[z,{z,-2-2I,2+2I}]
},ImageSize->3 72]

It is OK to insert the DrawCartesianMap expression like that directly into the Draw2D argument. But when you add options to DrawCartesianMap or include additional complex graphics objects in the Draw2D argument, you will probably want to form the grid first and then refer to it by name inside Draw2D—like this:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I}];

Draw2D[{grid},
ImageSize->3 72]

To change the number of grid lines in each direction, use the Mesh option to DrawCartesianMap. And to do that, you may either specify the actual number of lines in each direction or, instead, specify the (horizontal or vertical) coordinates of those lines:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
Mesh->{5,5}];

Draw2D[{grid},
ImageSize->3 72]

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
Mesh->{{-1.5,-1,0,1,1.5},5}];

Draw2D[{grid},
ImageSize->3 72]

Probably the default gray background color of the grid itself is too dark.
To change the background of a grid, in the Draw2D argument precede the DrawCartesianMap expression with a color directive.

Draw2D[{
HTML@Wheat,
grid
},ImageSize->3 72]

Unfortunately, that makes the square formerly bounding the whole grid disappear. 
To change the appearance of the boundary, include a  BoundaryStyle option to DrawCartesianMap.

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black]];

Draw2D[{
HTML@Wheat,
grid
},ImageSize->3 72]

To make the background color of the grid more transparent—hence lighter in appearance—use an Opacity graphics directive (against the notebook's overall background color, the effect here will be subtle):

Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},ImageSize->3 72]

You can tell just by looking which grid line segments are horizontal and which are vertical. But later, when those lines are mapped by f, you will want to know which images are of the horizontal segments and which of the vertical segments.

To distinguish the horizontal segments in the grid from the vertical ones, use the MeshStyle option to DrawCartesianMap.

You may use different colors, or gray scale, or thickness, or dashing treatments, etc., for the horizontal and vertical segments. We shall use different colors.

Below is our final version of the Cartesian grid. To enhance it we:
	• style the grid lines by using a MeshStyle option to DrawCartesianMap;
	• style the boundary of the rectangular region by using a BoundaryStyle option to DrawCartesianMap;
	• include axes;
	• label the whole drawing.
And we assign a name, domain, to the whole drawing, so that we can display it later alongside a drawing of the image of the grid under f.

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72]

Constructing the PlotLabel value as a Row allows Mathematica to display the "z" automatically in a traditional mathematical style.

Exercise . Try the same drawing except that, instead of axes, you put the tick marks along sides of a frame for the drawing. (In some of your own drawings, you may want to do that for clarity.)

In your own drawings, you will doubtless want to use MeshStyle to distinguish the horizontal from the vertical lines. But how far you want to go with changing other colors, etc., depends on what is necessary for clarity. And the more artistic your inclination, the nicer you can make the drawing look.

Image of a Cartesian grid under a function

Here again is the code to form the Cartesian grid:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

The set of images of the horizontal and vertical lines of a Cartesian grid under f is included in the output of a DrawCartesianMap[f[z],…] expression. Here is just the beginning of the output:

DrawCartesianMap[f[z],{z,-2-2I,2+2I}]//Short[#,4]&

The pure function Short[#,4]& is a version of Short with a second argument requesting approximately 4 lines of output.

For example, two points of the original grid are (-2,-2) and, approximately, (-1.71429,-2). The values of f at these points are:

{f[-2-2I],f[-1.71429-2I]}

And those values have as coordinates the entries {0.,8.} and {-1.06121,6.85714} that you see at the beginning of the output from the DrawCartesianMap[f[z],…] expression.

Then the images of the lines of the original Cartesian grid are as shown below. Notice that the only changes to the code for the Cartesian grid to this code is to change z to f[z]and to change the PlotLabel! Of course you could change various directives and options here. But surely you would not want to change the MeshStyle.

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72]

Exercise . Create a similar drawing to visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise by for h(z)=1/z.

A two-panel Cartesian plot showing how a function maps a grid

Here again is the code to produce the drawings of the original Cartesian grid and its image. Output is suppressed.

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

Now put everything together to see how the squaring function maps the Cartesian grid.

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

The two-panel plot shown above is visually misleading, in that the image appears too small compared with the domain. This is an artifact of how Mathematica resizes the two drawings in the GraphicsRow, so as to make the width of each drawing the same.

To preserve the same scale for drawings in a GrahicsRow, one way is to include the same PlotRange for both the domain and the image.

domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Oops! Although the range on the real axis is OK, the range for the imaginary axis needs to be increased.

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotRange->{{-4,4},{-8,8}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

To maintain the same scale for the drawings in a GraphicsRow , another way is to use Row instead of GraphicsRow:. With that way, you no longer have to specify the same PlotRange for the drawings. But you will have to display a label for the overall figure by stacking up the label and the figure into a Column:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

Column[{
Style[Row[{"Mapping ",z," ⟶ ",f[z]}],FontFamily->"Times"],
Row[{domain,Spacer[10],image}]
},Alignment->Center]

Exercise . But exactly what's going on there in the way the squaring function f maps the complex plane? To help answer that question, see howf maps a grid just in the first quadrant.

Exercise . In a two-panel plot such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Exercise . Encapsulate in a function TwoPanelCartesianPlot the entire process of creating such a drawing of how a complex function maps a Cartesian grid. The arguments to TwoPanelCartesianPlot should include at least:
	• the variable name z;
	• a function name f; and
	• a list {zmin,zmax} indicating the lower-left and upper-right corner of the grid.
(You may wish to include additional arguments to specify grid segment coloring, etc.)
For example, to reproduce the preceding drawing of the squaring function, after having defined f[z_]:=(z^2), you would invoke:
	TwoPanelCartesianPlot[z,f,{-2-2i,2+2i}]

When you print your work on a black-and-white printer, the color treatments are probably not going to show up very well. In that case, you will want to try something else, such as:
	• for the grid background, include a White color directive before grid in the Draw2D argument; and
	• for the mesh lines, use shades of gray—using the Gray or GrayLevel directives—or solid vs. dashing, using thickness or dashing directives.
Moreover, you will want to keep in mind the width of paper when you set ImageSize. (If you set an ImageSize option in the final GraphicsRow expression, then you don't need them in the individual Draw3D expressions—although that will scale both panels to have the same overall size.)

For example, here is the code for the same visualization of f(z)=(z^2) but modified with black-and-white printing in mind.

grid={
DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],MeshStyle->{Directive[Gray],Directive[Gray,Dashed]}]
};
domain=Draw2D[{White,grid},
Axes->True,PlotLabel->Row[{"Domain: ",z}]];

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Directive[Gray],Directive[Gray,Dashed]}];
image=Draw2D[{White,imageGrid},
Axes->True,PlotLabel->Row[{"Image: ",f[z]}]];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],ImageSize->7 72]

Exercise . Similarly, provide complete input to produce a two-panel Cartesian plot suitable for black-and-white printing, but now using Row instead of GraphicsRow for the overall figure.

Exercise . Modify your function TwoPanelCartesianPlot from Exercise  so as to produce output suitable for printing on a black-and-white printer. Perhaps name the modified function TwoPanelCartesianPlotPrintVersion. 
Or instead, modify TwoPanelCartesianPlot so as to include an optional argument specifying whether to produce output suitable for printing or, instead, ordinary output with all the pretty color treatments.
For example, to produce output for viewing on-screen, you would invoke TwoPanelCartesianPlot exactly as before. But to produce output suitable for black-and-white printing, you would now invoke the function like this:
	TwoPanelCartesianPlot[z,f,{-2-2i,2+2i},Printing->BW]
(For this alternative version with an optional argument, you'll need to consult the Documentation Center about how to handle optional arguments.)

Highlighting geometric objects and their images

Still the function is:

f[z_]:=(z^2)

To better understand how a complex function maps the plane, you will often want to highlight some particular points or line segments and to see their images in a two-panel Cartesian plot. Here is the kind of figure we want to produce:

The underlying idea is: within the domain Draw2D expression include the complex graphics objects representing those points or segments; calculate the images; and within the image Draw2D expression include the complex graphics objects representing those images.

Fortunately, Presentations provides the function ComplexMap that relieves you of the work of first calculating the images and then forming the corresponding complex graphics objects. The syntax is:
	ComplexMap[f][{lis}]
where f is the function name and lis is a list of complex graphics objects, including DrawCartesianMap objects, and graphics directives. Thus ComplexMap has a single argument, f. And the value of ComplexMap[f] is then a Mathematica function which in turn takes an argument, the list lis.
To avoid the back-to-back brackets, it is common to use ComplexMap[f] in postifx form:
	{lis}//ComplexMap[f]

From the code to create domain, extract the list argument of Draw2D—without any of the options to Draw2D (output is suppressed below):

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}];

{Opacity[0.5,HTML@Wheat],grid};

Now we are going to include in that list a two points and the line segment from 0 to 1+i. But there's a twist here: you need parameterize the line segment. (The reason for doing that will become clear later.)

The line segment from 0 to 1+i. is parametrized by z=(1-t)(0)+t(1+i)=t(1+i) for 0≤t≤1. The corresponding complex graphics object is ComplexCurve[t(1+i),{t,0,1}].

domainObjects={
Opacity[0.5,HTML@Wheat],
grid,
Directive[Thick,Red],ComplexCurve[t(1+I),{t,0,1}],
Directive[PointSize@Large,Blue],ComplexPoint/@{1+I,I}
};

Next, use that as the list argument to Draw2D:

domain=Draw2D[{domainObjects},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72]

Now just apply ComplexMap[f] to the domain objects and draw that:

image=Draw2D[{domainObjects//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72]

(It's a bit hard to see the vertical segment in the image drawing; to fix that, you might want to change the thickness of the segment in the domain drawing.)

Finally, combine the domain and image drawings into a two-panel plot:

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

In summary, here is all the code—aside from the definition of f— that produced the preceding two-panel Cartesian plot .

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}];
 domainObjects={
Opacity[0.5,HTML@Wheat],
grid,
Directive[Thick,Red],ComplexCurve[t(1+I),{t,0,1}],
Directive[PointSize@Large,Blue],ComplexPoint/@{1+I,I}
};
domain=Draw2D[{domainObjects},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

image=Draw2D[{domainObjects//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

Exercise . (a) Use the two-panel Cartesian plot output to describe what the images of horizontal lines and vertical lines under f(z)=(z^2) seem to be.
(b) Through appropriate calculations, with or without Mathematica, make your description quantitatively precise and prove that it is correct. (You may wish to see notebook CalculatingImages.nb.)

Exercise . In a two-panel plot with highlighting such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Exercise . Modify the definition of TwoPanelCartesianPlot from Exercise  so as to handle not just the grids, but additional graphical objects such as points, line segments, circles, and other curves that are to be highlighted.

For the line segment, why was ComplexCurve used rather than the simpler ComplexLine, as in the following modification of the preceding code?
See what happens if in the preceding code you replace the ComplexCurve expression with the simpler ComplexLine expression:

domainObjects={
Opacity[0.5,HTML@Wheat],
grid,
Directive[Thick,Red],ComplexLine[{0,1+I}],
Directive[PointSize@Large,Blue],ComplexPoint/@{1+I,I}
};
domain=Draw2D[{domainObjects},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];
image=Draw2D[{domainObjects//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];
GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

That seems to give exactly the same plot as when ComplexCurve was used to parameterize the line segment. So why all the bother to parameterize? The explanation comes in the following subsubsection.

Exercise . Modify the definition of TwoPanelCartesianPlot from Exercise  so as to handle not just the grids, but additional graphical objects such as points, line segments, circles, and other curves that are to be highlighted.

Why parameterize the curves to be mapped?

The short answer to the question is:

It just so happened that, as you saw, the image of the line segment from 0 to 1+i is, in fact, another line segment. But try a different line segment—do the following exercise.

Exercise . (a) By direct calculation determine the image under  f(z)=(z^2) of the line segment from -1+i to 1+i.
(b) Draw a two-panel plot of f(z)=(z^2) again, but now also highlight and map that line segment as well as its endpoints and its midpoint i. Use ComplexCurve to parameterize the line segment.
(c) Repeat (b) but instead use ComplexLine for the line segment.
(d) Which output gives the correct image of the line segment, from (b) or from (c)?

Exercise . Repeat the preceding exercise but instead of the line segment, highlight the circle with center i and radius 1/2.

Why you must parameterize line segments and circles, using ComplexCurve, to obtain correct images under mapping? Here's the long answer.

The answer lies in the way that ComplexMap[f] calculates the images of the complex graphics objects. In case those objects are defined by means of the graphics primitive ComplexLine, the function ComplexMap[f] merely takes the particular points determining the graphics objects (here, the endpoints of the lines); calculates the images of those particular points; and finally forms the same kind of primitive graphics objects—lines, again—using those image points. (But under the squaring function, the image of a horizontal or vertical line does not need to be another line!)

The same sort of thing happens with ComplexMap[f] in case you use ComplexCircle.

On the other hand, as you saw earlier, the result of a ComplexCurve expression involves a whole long list of points along the curve. Then ComplexMap[f] calculates the images of all those points and connects the image points to obtain a new curve. So the displayed image is correct.

Interactively moving objects under a map

Still use the function:

f[z_]:=(z^2)

And use the same Cartesian grid as before:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}];

But now, instead of a fixed geometric object such as a point or a line, use a parameterized point and line and then change the drawings of the domain and the image as you vary the parameters. This will be implemented by using the Mathematica function Manipulate.

For example, we are going to move a horizontal line segment upwards in the grid, from bottom to top. At a height b, such as segment is given by:
	ComplexCurve[(1-t)(-2+b i)+t(2+b i),{t,0,1}]

Draw2D[{
Directive[Thick,Red],
ComplexCurve[(1-t)(-2+b I)+t(2+b I)/.b->0.5,{t,0,1}]},
Axes->True,PlotRange->{{-2,2},{-2,2}}]

Now just take out the particular value of b there, wrap the entire expression with Manipulate, and let b vary from -2 to 2.

Manipulate[
Draw2D[{
Directive[Thick,Red],
ComplexCurve[(1-t)(-2+b I)+t(2+b I),{t,0,1}]},
Background->Opacity[0.5,HTML@Wheat],
Axes->True,PlotRange->{{-2,2},{-2,2}}],
{b,-2,2}]

Before putting that together with the grid, it's probably a good idea to isolate the definition of the horizontal segment as a function of b:

horizontal[b_]:=ComplexCurve[(1-t)(-2+b I)+t(2+b I),{t,0,1}]

Since we want to recycle the names domain, image, and domainObjects—which were formerly (rather complicated) fixed Mathematica graphics objects—so as to become names of function, it is essential to clear those names:

Clear[domain,image,domainObjects]

Just remember now that the list of all the objects in the domain, among which will be the parametrized horizontal segment, will then have to be a function of b as well. And to anticipate using GraphicsRow to display the domain and image in a single dynamic two-panel plot, specify a suitable PlotRange option for each drawing.

domainObjects[b_]:={
Opacity[0.5,HTML@Wheat],
grid,
Directive[Thick,Red],
horizontal[b]
};

domain[b_]:=Draw2D[
{
domainObjects[b]
},
Axes->True,PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->2.5 72];

Manipulate[domain[b],{b,-2,2}]

Next, parameterize the image, too, by b:

image[b_]:=Draw2D[{domainObjects[b]//ComplexMap[f]},
Axes->True,PlotRange->{{-4,4},{-8,8}},
PlotLabel->Row[{"Image: ",z}],
ImageSize->2.5 72]

Manipulate[image[b],{b,-2,2}]

And finally put the parametrized domain and parameterized image together inside a manipulate:

Manipulate[GraphicsRow[{domain[b],image[b]},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]],
{b,-2,2}]

Here's all the code at once (except for the definition f[z]:=((z )^2)):

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}];

horizontal[b_]:=ComplexCurve[(1-t)(-2+b I)+t(2+b I),{t,0,1}]

 domainObjects[b_]:=
{Opacity[0.5,HTML@Wheat],grid,
Directive[Thick,Red],horizontal[b]}

domain[b_]:=Draw2D[{domainObjects[b]},
Axes->True,PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->2.5 72]

image[b_]:=Draw2D[{domainObjects[b]//ComplexMap[f]},
Axes->True,PlotRange->{{-4,4},{-8,8}},
PlotLabel->Row[{"Image: ",z}],
ImageSize->2.5 72]

Manipulate[
GraphicsRow[{domain[b],image[b]},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]],
{b,-2,2}]

As usual, you may want to use a Row instead of a GraphicsRow in order to maintain the same scale in both panels.

Exercise . Similarly, manipulate a vertical segment in the domain and its corresponding image. This time, call the parameter a rather than b.

In order to vary both horizontal and vertical segments in the domain and image, you would change the definition of the functions domainObjects, domain, and image that you saw above for the horizontal segments so as to become functions of both a and b; and likewise change the definitions of the Mathematica functions you defined in Exercise  for the vertical segments. Then you would use a Manipulate of the form:
	Manipulate[GraphicsRow[{domain[a,b],image[a,b]},…,{a,-2,2},{b,-2,2}]

That will create interactive output with two sliders, one for the value of a and the other for the value of b. You can then move each slider separately.

Exercise . Do what is outlined in the immediately preceding discussion about interactive output with two sliders.

Exercise . In a two-panel plot with dynamically highlighted horizontal and vertical segments in the domain, and their images in the codomain, similarly visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

If, though, you want to simultaneously vary both a and b, instead of the default separate slider controls, you could include the option ControlType->Slider2D to Manipulate. However, as you move the 2D slider, the input is going to give points in the plane. Now for a 2D slider, Manipulate expects a single variable, not two. Hence you will need to use such a single point variable, say p, and then you must convert all the functions except horizontal and vertical) whose arguments were formerly both a and b into functions of the single argument p.

Imaging points with locators

If you want to freely move a point around in some domain of a complex function, a good way is to use a Locator in the domain, and then a ComplexPoint in the image. (For more information about using Locator with Presentations, see notebook DrawingComplexObjects.nb.)

Stick with the squaring function:

f[z_]:=(z^2)

And continue to use the same Cartesian grid as before:

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}];

domainObjects[p_]:={
Opacity[0.5,HTML@Wheat],
grid,
Directive[Blue,PointSize@Large],ComplexPoint[p]
};

domain[p_]:=Draw2D[{domainObjects[p]},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

image[p_]:=Draw2D[{domainObjects[p]//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

Manipulate[Column[{
Row[{"Mapping: ",z," ⟶ ",f[z]}],
Row[{ToComplex[pt],"  ↦  ",f[ToComplex[pt]]}],
Row[{domain[ToComplex@pt],Spacer[20],image[ToComplex@pt]}]
},
Alignment->Center],
{{pt,ToCoordinates[1+I]},Locator},
BaseStyle->{FontFamily->"Times"}]

Exercise . What happens if you use a GraphicsRow instead of a Row above?

Exercise . In a dynamic two-panel plot with a locator, such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Using polar coordinates to visualize how f maps the plane

The function being used is again:

f[z_]:=(z^2)

Expressing a function in polar form

For a polar-form (that is, exponential) r (e^(i θ)) input, the function value is:

f[r Exp[I θ]]

To separate this into a sum U+i V, evaluate ComplexExpand at that function value:

ComplexExpand[f[r Exp[I θ]]]

Then f is described in polar form (for the domain) by
	f(r (e^(i θ)))=U(r,θ) +i V(r,θ),
where the functions U and V are given as below by Mathematica:

U[r_,θ_]:=ComplexExpand@Re[f[r Exp[I θ]]]
V[r_,θ_]:=ComplexExpand@Im[f[r Exp[I θ]]]

{U[r,θ],V[r,θ]}

(There's a shorter way to form both U and V at the same time, using Mathematica's Through function. See the Appendix for details.)

Drawing a polar grid

The sort of grid appropriate to polar form r (e^(i θ)) is one with constant values of r—concentric circles centered at the origin—and with constant values of θ—segments of rays emanating from the origin. In other words, the sort of thing you would see on polar graph paper (if you can find pads of that kind).

Actually, in order to understand the effect of the squaring map, we want a polar grid only in the first quadrant. The following is the drawing we want to produce.

To create a polar grid, use the Presentations function DrawPolarMap. To specify a polar grid radiating from the origin, you give two points in polar form, using ComplexPolar: 
	ComplexPolar[(Subscript[r, mim]),(Subscript[θ, min])], ComplexPolar[(Subscript[r, max]),(Subscript[θ, max])]
Then the grid will cover the region described in polar coordinates (r,θ) by
	(Subscript[r, min])≤r≤(Subscript[r, max]),  (Subscript[θ, min])≤θ≤(Subscript[θ, max])
 a point on an inner circular arc bounding the region; a point on an outer circular arc bounding the region.

For example, here is a polar grid consisting of the disk inside the circle r=2:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,2π]}];
Draw2D[{polargrid},Axes->True,ImageSize->3 72]

Here is a polar grid consisting of just the portion of that disk that lies in the first quadrant:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]}];
Draw2D[{polargrid},Axes->True,ImageSize->3 72]

For a grid that is an annulus, or part of an annulus, do something like this:

polargrid=DrawPolarMap[z,{z,ComplexPolar[1,0],ComplexPolar[2,2π]}];
Draw2D[{polargrid},Axes->True,ImageSize->3 72]

Exercise . Draw a polar grid consisting of the portion of the preceding annulus that lies in the upper half-plane.

Usually for understanding how functions map the plane in polar coordinates, you will want to use a polar region radiating from the origin. But to specify a polar grid radiating from some point other than the origin, you include that point as an optional third item in the specification list. For example:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,2π],1+I}];
Draw2D[{polargrid},Axes->True,AxesOrigin->{0,0},ImageSize->3 72]

Exercise . Draw a polar grid consisting of the portion of the preceding disk whose points z have Im(z)≥1.

As with Cartesian grids, to change the number or location of the grid rays and arcs, use the Mesh option to DrawPolarMap. For example:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
Mesh->{5,4}];
Draw2D[{polargrid},Axes->True,ImageSize->3 72]

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
Mesh->{5,{(π/8),(π/4),((3π)/8)}}];
Draw2D[{polargrid},Axes->True,ImageSize->3 72]

Often you will want to use coloring for a polar grid. Do that essentially the same way as for a Cartesian grid:
	• change the style of the radial line segments and concentric circles by using a MeshStyle option to DrawPolarMap;
	• change the style of the boundary of the polar region by using a BoundaryStyle option to DrawPolarMap; and
	• change the style of the background by a color directive in Draw2D.

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

polardomain=Draw2D[{
Opacity[0.5,HTML@Wheat],
polargrid
},
Axes->True,
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72]

Image of a polar grid under a function

Still we use:

f[z_]:=(z^2)

Mapping a polar grid by a function works essentially the same way as did mapping a Cartesian grid: in the DrawPolarMap expression, replace the first argument z by f[z]. That's all!

imagepolargrid=DrawPolarMap[f[z],{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Opacity[1],Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

polarimage=Draw2D[{
Opacity[0.5,HTML@Wheat],
imagepolargrid
},
Axes->True,
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72]

A two-panel polar plot showing how a function maps a grid

GraphicsRow[{polardomain,polarimage},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Once again, using GraphicsRow forces different scales in the two drawings because it makes the widths of the two drawings the same.

There are two ways to preserve the same scale for the drawings: 
	(1) use Row instead of GraphicsRow.
	(2) still use GraphicsRow, but specify the same PlotRange for both drawings.

In our example, use Row instead of GraphicsRow:

Row[{polardomain,polarimage}]

Then to label the entire figure, stack the pair of drawings and a label into a Column:

Column[{
Style[Row[{"Mapping ",z," ⟶ ",f[z]}],FontFamily->"Times"],
Row[{polardomain,polarimage}]
},Alignment->Center]

The preceding two-panel polar plot suggests that f(z)=(z^2) doubles arguments and squares moduli.

Exercise . Prove that f(z)=(z^2) does actually double arguments (up to a multiple of 2π) and square moduli, first by hand calculation and then by using Mathematica—in both ways using arbitrary complex numbers and not just particular numeric ones.

The second way to preserve the same scale for the drawings, is to include the same PlotRange for both the domain and the image.

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];
polardomain=Draw2D[{
Opacity[0.5,HTML@Wheat],
polargrid
},
Axes->True,
PlotLabel->Row[{"Domain: ",z}],
PlotRange->{{-4,4},{0,4}},
ImageSize->4 72];

imagepolargrid=DrawPolarMap[f[z],{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Opacity[1],Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];
polarimage=Draw2D[{
Opacity[0.5,HTML@Wheat],
imagepolargrid
},
Axes->True,
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->4 72];

GraphicsRow[{polardomain,polarimage},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Exercise . (a) Visualize g(z)=(z^3) by making a drawing in polar coordinates.
(b) Use the drawing to conjecture what g does to arguments and moduli.
(c) As in Exercise , confirm your conjecture.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Exercise . Encapsulate in a function TwoPanelPolarPlot the entire process of creating such a drawings such as above of how a complex function maps a polar grid. This function should be an analog of the function TwoPanelCartesianPlot requested in Exercise  should include at least:
	• the variable name z;
	• a function name f; and
	• a list {zmin,zmax} indicating the lower-left and upper-right corner of the grid.
(You may wish to include additional arguments to specify grid segment coloring, etc.)
For example, to reproduce the preceding drawing of the squaring function, after having defined f[z_]:=(z^2), you would invoke:
	TwoPanelCartesianPlot[z,f,{-2-2i,2+2i}]

Exercise . Modify your function TwoPanelPolarPlot from Exercise  so as to produce output suitable for printing on a black-and-white printer. Perhaps name the modified function TwoPanelPolarPlotPrintVersion. (See Exercise , where the same thing was requested but for Cartesian plots instead.)

Highlighting geometric objects and their images

To highlight particular points, line segments, and circular arcs, and to see their images in a two-panel polar plot, proceed in the same way as for Cartesian plots.

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];
polardomainObjects={
Opacity[0.5,HTML@Wheat],
polargrid,
Directive[Thick,Darker@Legacy@CobaltGreen],ComplexCurve[t 1.5Exp[Pi I/3],{t,0,1}],
Directive[PointSize@Large,Legacy@CadmiumOrange],
ComplexPoint[1.5Exp[Pi I/3]]
};
polardomain=Draw2D[{polardomainObjects},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
PlotRange->{{-4,4},{0,4}},
ImageSize->3.5 72];

polarimage=Draw2D[{polardomainObjects//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3.5 72];

GraphicsRow[{polardomain,polarimage},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

The input for the preceding output is readily modified so as to highlight a particular circular arc of the polar grid, a particular ray of the polar grid, and their images (the definition of polargrid remains unchanged). We'll define the additional objects first.

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

ray=ComplexCurve[t(2Exp[I π/3]),{t,0,1}];
arc=ComplexCurve[1.5 Exp[I θ],{θ,0,π/2}];

polardomainObjects={
Opacity[0.5,HTML@Wheat],
polargrid,
Directive[Thick,Darker@Legacy@CobaltGreen],arc,
Directive[Thick,Legacy@CadmiumOrange],ray
};

polardomain=Draw2D[{polardomainObjects},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

polarimage=Draw2D[{polardomainObjects//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

GraphicsRow[{polardomain,polarimage},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]]

Again, remember that you must use ComplexCurve, and not ComplexLine or ComplexCircle, in order that the images of the highlighted objects be calculated correctly.

Exercise . (a) Use the two-panel polar plot output to describe what the images of rays from the origin and circles centered at the origin are under f(z)=(z^2) seem to be.
(b) Through appropriate calculations, with or without Mathematica, make your description quantitatively precise and prove that it is correct. (You may wish to see notebook CalculatingImages.nb.)

Exercise . In a two-panel polar plot with highlighting of a ray and an arc such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Interactively moving objects under a map

Still use the function:

f[z_]:=(z^2)

And use the same polar grid as before:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

But now, instead of a fixed geometric object such as a line segment or a circular arc, use a parameterized point and line and then change the drawings of the domain and the image as you vary the parameters. To implement this, use the Mathematica function Manipulate.

We are going to rotate a ray counterclockwise around the origin and move circular arcs outward from the origin. At an angle θ, a ray is given by:
	ComplexCurve[(1-t)0 + t 2 Exp[i θ],{t,0,1}]
And at a radius r, a circular arc is given by:
	ComplexCurve[r Exp[i θ],{θ,0,π/2}]

Draw a particular ray and a particular circular arc:

Draw2D[{
Directive[Thick,Darker@Legacy@CobaltGreen],
ComplexCurve[t 2Exp[I θ]/.θ->π/3,{t,0,1}],
Directive[Thick,Legacy@CadmiumOrange],
ComplexCurve[r Exp[I θ]/.r->1,{θ,0,π/2}]
},
Axes->True]

Now just replace the particular values of θ and r above by variables, wrap the entire expression with Manipulate, and let θ vary from 0 to π/2 and r vary from 0 to 2. But since θ is being used as the control variable for the ray, change the name of the parameter of the arc to something other than θ—say, α.

Manipulate[
Draw2D[{
Directive[Thick,Darker@Legacy@CobaltGreen],
ComplexCurve[t 2Exp[I θ],{t,0,1}],
Directive[Thick,Legacy@CadmiumOrange],
ComplexCurve[r Exp[I α],{α,0,π/2}]
},
Background->Opacity[0.5,HTML@Wheat],
Axes->True,
PlotRange->{{0,2},{0,2}}],
{{θ,π/12},0,π/2},{{r,0.5},0,2}]

Before putting that together with the grid, in order it's probably a good idea to isolate the definition of the horizontal segment as a function of θ:

Because ray and arc named fixed objects before but are now about to name functions, it is essential to clear those names:

Clear[ray,arc]

ray[θ_]:=ComplexCurve[t 2Exp[I θ],{t,0,1}]
arc[r_]:=ComplexCurve[r Exp[I α],{α,0,π/2}]

And since we want to recycle the names polardomain, polarimage, and polaromainObjects—which were formerly (rather complicated) fixed Mathematica graphics objects—so as to become names of function, it is essential to clear those names:

Clear[polardomain,polarimage,polardomainObjects]

Just remember now that the list of all the objects in the domain, among which will be the parameterized ray and arc, will then have to be a functions of θ and r:

polardomainObjects[θ_, r_]:={
Opacity[0.5,HTML@Wheat],
polargrid,
Directive[Thick,Darker@Legacy@CobaltGreen],
ray[θ],
Directive[Thick,Legacy@CadmiumOrange],
arc[r]
};

polardomain[θ_,r_]:=Draw2D[
{
polardomainObjects[θ,r]
},
Axes->True,PlotLabel->Row[{"Domain: ",z}],
ImageSize->2.5 72];

Manipulate[polardomain[θ,r],
{{θ,π/12},0,π/2},{{r,0.5},0,2}]

Next, parameterize the image, too, by b:

polarimage[θ_,r_]:=Draw2D[{polardomainObjects[θ,r]//ComplexMap[f]},
Axes->True,PlotLabel->Row[{"Image: ",z}],
ImageSize->2.5 72]

Manipulate[polarimage[θ,r],
{{θ,π/12},0,π/2},{{r,0.5},0,2}]

And finally put the parametrized domain and parameterized image together inside a manipulate:

Manipulate[GraphicsRow[{polardomain[θ,r],polarimage[θ,r]},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]],
{{θ,π/12},0,π/2},{{r,0.5},0,2}]

Once again, the scales of the domain and image drawings are adjusted by GraphicsRow so as to force the drawings to have the same width. And so once again, if you wish, you may force Mathematica to preserve the same scale in either of the two usual ways.

Here, doing that with a GraphicsRow, is all the code at once (except for the definition f[z]:=((z )^2)):

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

ray[θ_]:=ComplexCurve[t 2Exp[I θ],{t,0,1}]
arc[r_]:=ComplexCurve[r Exp[I α],{α,0,π/2}]

polardomainObjects[θ_, r_]:={
Opacity[0.5,HTML@Wheat],
polargrid,
Directive[Thick,Darker@Legacy@CobaltGreen],
ray[θ],
Directive[Thick,Legacy@CadmiumOrange],
arc[r]
}
polardomain[θ_,r_]:=Draw2D[
{
polardomainObjects[θ,r]
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

polarimage[θ_,r_]:=Draw2D[{polardomainObjects[θ,r]//ComplexMap[f]},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72]

Manipulate[GraphicsRow[{polardomain[θ,r],polarimage[θ,r]},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}]],
{{θ,π/12},0,π/2},{{r,0.5},0,2}]

Exercise . Produce the same kind of output as what precedes, but now by using Row instead of GraphicsRow.

Exercise . Modify the input for the preceding figure so that the output will be suitable for black-and-white printing.

Exercise . Use a single Slider2D control to produce the same output. The two-dimensional slider input of course represents values of the pair {θ,r} (or vice versa, as you choose).

Exercise . In a two-panel polar plot with dynamic highlighting of rays and arcs such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Imaging points with locators

Just as for Cartesian drawings, so for polar drawings, if you want to freely move a point around in some domain of a complex function, you may use a Locator in the domain, and then a ComplexPoint in the image. (For more information about using Locator with Presentations, see notebook DrawingComplexObjects.nb.)

Stick with the squaring function:

f[z_]:=(z^2)

Without any ray or arc to move, polardomainOjects, polardomain, and polarimage are going to be functions of the manipulated point. So clear those names.

Clear[polardomainObjects,polardomain,polarimage]

Continue with the same polar grid as before.

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

polardomainObjects[p_]:={
Opacity[0.5,HTML@Wheat],
polargrid,
Directive[Blue,PointSize@Large],ComplexPoint[p]
}

polardomain[p_]:=Draw2D[
{
polardomainObjects[p]
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

polarimage[p_]:=Draw2D[{polardomainObjects[p]//ComplexMap[f]},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72]

Manipulate[Column[{
Row[{"Mapping: ",z," ⟶ ",f[z]}],
Row[{ToComplex[pt],"  ↦  ",f[ToComplex[pt]]}],
Row[{polardomain[ToComplex@pt],Spacer[20],polarimage[ToComplex@pt]}]
},
Alignment->Center],
{{pt,ToCoordinates[1+I]},Locator},
BaseStyle->{FontFamily->"Times"}]

Exercise . In a dynamic two-panel polar plot with a locator, such as above, visualize how g(z)=(z^3) maps the complex plane.

Exercise . Repeat the preceding exercise but for h(z)=1/z.

Example 2: adding 2 + i

The function in this section is:

f[z_] := z + (2 + I)

From the interpretation of complex addition as vector addition, this function is going to be a translation of the plane. So a Cartesian grid will give a better picture  than will a polar grid as to how the function maps the plane.

The Cartesian grid here will be the same as before.

grid=DrawCartesianMap[z,{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
domain=Draw2D[{
Opacity[0.5,HTML@Wheat],
grid
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

imageGrid=DrawCartesianMap[f[z],{z,-2-2I,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];
image=Draw2D[{
Opacity[0.5,HTML@Wheat],
imageGrid
},
Axes->True,
PlotRange->{{-4,4},{-4,4}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Exercise . Make the output more instructive by highlighting a horizontal segment, a vertical segment, and their images.

Exercise . Make the output more instructive by dynamically highlighting a horizontal segment, a vertical segment, and their images.

Exercise . Make the output more instructive by dynamically highlighting a point, a vector from the origin to the point, and the images of both.

Example 3: multiplication by i

The new function now is:

f[z_] := I z

Look first at how f maps a rectangular grid in the first quadrant and the line segment from the origin to the far corner of that rectangle. First form the line segment and mark its far end with a point.

lineAndPoint={Thick,Blue,ComplexCurve[t(2+2I),{t,0,1}],
PointSize[Large],Red,ComplexPoint[2+2I]};

grid=DrawCartesianMap[z,{z,0,2+2I},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{HTML@SeaGreen,Darker@Brown}
];

domainObjects={
Opacity[0.5,HTML@Wheat],grid,
lineAndPoint
};
domain=Draw2D[{
domainObjects
},
Axes->True,
PlotRange->{{-2.25,2.25},{-2.25,2.25}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3 72];

image=Draw2D[{domainObjects//ComplexMap[f]},
Axes->True,PlotRange->{{-2.25,2.25},{-2.25,2.25}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3 72];

GraphicsRow[{domain,image},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Now look at how f maps a polar grid in the first quadrant and a ray:

polargrid=DrawPolarMap[z,{z,ComplexPolar[0,0],ComplexPolar[2,π/2]},
BoundaryStyle->Directive[Thick,Black],
MeshStyle->{Legacy@AlizarinCrimson,Legacy@CobaltGreen}];

lineAndPoint={Thick,Blue,ComplexCurve[t((Sqrt[2])+(Sqrt[2])I),{t,0,1}],
PointSize[Large],Red,ComplexPoint[(Sqrt[2])+(Sqrt[2])I]};

polardomainObjects={
Opacity[0.5,HTML@Wheat],polargrid,
lineAndPoint
};
polardomain=Draw2D[{
polardomainObjects
},
Axes->True,PlotRange->{{-2.25,2.25},{-0.25,2.25}},
PlotLabel->Row[{"Domain: ",z}],
ImageSize->3.25 72];

polarimage=Draw2D[{polardomainObjects//ComplexMap[f]},
Axes->True,PlotRange->{{-2.25,2.25},{-0.25,2.25}},
PlotLabel->Row[{"Image: ",f[z]}],
ImageSize->3.25 72];

GraphicsRow[{polardomain,polarimage},
PlotLabel->Row[{"Mapping ",z," ⟶ ",f[z]}],PlotRange->All]

Exercise . In this example, would it be "safe" to use ComplexLine instead of ComplexCurve (for both the two-panel Cartesian plot and the two-panel polar plot). Why or why not?

Exercise . (a) Using either or both of the two-panel plots obtained above, describe geometrically how the complex function f(z)=i z maps the complex plane.
(b) By doing appropriate calculations, with or without Mathematica, prove that your description is correct.

Exercise . Create a two-panel Cartesian plot and a two-panel polar plot for the function f(z)=z*, where z* denotes the conjugate. Include other suitable geometric objects so as to better indicate how f maps the complex plane.

Exercise . Using the figures you produce in Exercise , repeat Exercise  for the function f(z)=z*.

Appendix: Visualizing by using the built-in ParametricPlot

There is an alternative way to visualize complex maps that does not use Presentations at all, with built-in Mathematica functions only.

Although this may be a handy way to do things when you don't have access to Presentations, it is clumsier to handle because you must deal directly with the real and imaginary parts of complex numbers. Moreover, you must also handle highlighted objects by using Prolog (or Epilog) options, or through other means of combining graphics.

Mapping in terms of Cartesian coordinates—using ParametricPlot

Return here to the function of example 1:

f[z_] := (z^2)

First we create a Cartesian grid using the built-in Mathematica function ParametricPlot. The parameters will be x and y when z is expressed in Cartesian form as x+y i.

dom=ParametricPlot[{Re[x+y I],Im[x+y I]},{x,-2,2},{y,-2,2},PlotRange->All,ImageSize->3 72]

You can shorten the code a bit by using Mathematica's Through function. For two functions g and h, the expression Through[{g,h}][arg] means the same thing as {g[arg],h[arg]}. Thus Through avoids repeating the same argument. For example:

Through[{Exp,Sin}[π I]]

The way we shall exploit it is with {Re,Im}. For example:

Through[{Re,Im}[(E^2)+3(I^3)]]

To avoid parentheses nested too deeply, we shall use prefix syntax, with @. For example:

Through@{Re,Im}[(E^2)+3(I^3)]

dom=ParametricPlot[Through@{Re,Im}[x+y I],{x,-2,2},{y,-2,2},PlotRange->All,PlotLabel->"domain",ImageSize->3 72]

Now form the image merely by replacing x+y i with f[x+i y] in the input for the domain.

image=ParametricPlot[Through@{Re,Im}[f[x+y I]],{x,-2,2},{y,-2,2},PlotRange->All,PlotLabel->"domain",ImageSize->3 72]

As when Presentations is used, you may now use a GraphicsRow to display the two drawings side-by-side

Mapping in terms of polar coordinates—using ParametricPlot

Still use here to the function of example 1:

f[z_] := (z^2)

The trick is to use the trig form x+y i=r cos θ + i r sin θ for complex numbers and then regard the latter as Cartesian coordinates parameterized by x and y. Thus parameterizing for the domain plot is straightforward:

dom=ParametricPlot[{r Cos[θ],r Sin[θ]},{θ,0,π/2},{r,0,π/2},PlotRange->All,PlotLabel->"domain",ImageSize->3 72]

To parameterizing the image plot, express the function f in polar form,
	f(r (e^(i θ)))=U(r,θ) +i V(r,θ),
as was done in an earlier section. Recall that in Mathematica, the functions U and V are given by:

U[r_,θ_]:=ComplexExpand@Re[f[r Exp[I θ]]]
V[r_,θ_]:=ComplexExpand@Im[f[r Exp[I θ]]]
{U[r,θ],V[r,θ]}

Now use the values of U and V as the x- and y-coordinates for the parametric plot of the image:

ParametricPlot[{U[r,θ],V[r,θ]},{θ,0,π/2},{r,0,2},PlotRange->All,PlotLabel->"domain",ImageSize->3 72]

Actually, there is no need to define U and V first, as above. Instead, do it directly:

{ComplexExpand@Re[f[r Exp[I θ]]],ComplexExpand@Im[f[r Exp[I θ]]]}

That expression is rather long, though. As in the preceding subsection, Mathematica's Through can shorten that:

ComplexExpand/@Through[{Re,Im}[f[r Exp[I θ]]]]

ParametricPlot[ComplexExpand/@Through[{Re,Im}[f[r Exp[I θ]]]],{θ,0,π/2},{r,0,2},
PlotRange->All,PlotLabel->"domain",ImageSize->3 72]