Three-Dimensional Mathematica Graphics (Section 6.1)

Extract from Mathematica Graphics: An Intensive Tutorial

by Tom Wickham-Jones



This HTML document is based on Mathematica Graphics: An Intensive Tutorial by Tom Wickham-Jones. It was adapted by Martin Kraus for non-commercial use.

Mathematica and MathLink are registered trademarks, and MathReader, MathSource and 3-Script are trademarks of Wolfram Research, Inc.

All other product names mentioned are trademarks of their producers.

Copyright 1992 by Wolfram Research, Inc.

All rights reserved. No part of this document may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording or otherwise, without the prior written permission of the copyright holder.



6.1 Introduction to Mathematica Programming

One of the most powerful aspects of Mathematica graphics is the availability of the rest of the system. This provides many capabilities and functions which are not normally present in a graphics application. One can use the built-in Mathematica functions which implement a wide range of numerical techniques such as root-finding, function minimization, numerically solving differential equations or quadrature, and then graph the results. Further still one can write code to construct primitives which draw a special type of picture.

For more information on Mathematica programming consider the book Mathematica: A System for Doing Mathematics by Computer, Third Edition, by Stephen Wolfram, Mathematica conference notes which are available from Wolfram Research or books on the subject such as Programming in Mathematica, Third Edition by Roman Maeder or Mathematica: A Practical Approach by Nancy Blachman.

Mathematica Patterns and Rules

One of the unique things about Mathematica programming is the ease and economy with which rules are given to describe how a function should behave. If you do not like the way it works, add a rule to make it work just as you desire.

f[1] matches exactly f[1]
f[_] matches f[ thing ]
f[x_] matches f[ thing ] and gives thing a name
Some simple Mathematica patterns.
This gives a rule for f[1]. In[1]:= f[1] := foo
 
This evaluates since a rule matches the input. In[2]:= f[1]

Out[2]= foo
 
This does not evaluate since there is no rule to match it. In[3]:= f[2]

Out[3]= f[2]
 
This will match f[ thing ]. In[4]:= f[_] := bar
 
Now this matches a pattern and the result is returned. In[5]:= f[2]

Out[5]= bar
 
This does not match since a pattern has only been given for f of one argument. In[6]:= f[2, 3]

Out[6]= f[2, 3]
 
This will clear all the rules of f. In[7]:= Clear[f]
 
This gives thing a name, namely x. In[8]:= f[x_] := x^3 - x^2
 
This matches. In[9]:= f[5]

Out[9]= 100
 
And this matches the pattern as well. In[10]:= f[(a+b)]

Out[10]= -(a + b)^2 + (a + b)^3
 

More complex patterns can be given to match multiple arguments, to refer to particular types of inputs and to accept conditions. The book Mathematica: A System for Doing Mathematics by Computer, Third Edition describes patterns in considerably more detail.

Delayed Evaluation

Often in these notes we see = and := which are the assignments functions. The first evaluates the right-hand side before the assignment is made. The second, := which is delayed assignment, does not evaluate the right-hand side until the left-hand side is evaluated.

= evaluate and then assign
:= assign but do not evaluate
This evaluates before assignment. In[11]:= f1 = Random[]

Out[11]= 0.0560708
 
These are all the same since f1 has been set to the value of the random number. In[12]:= Table[f1, {5}]

Out[12]= {0.0560708, 0.0560708, 0.0560708, 0.0560708, 0.0560708}
 
This makes a delayed assignment. In[13]:= f2 := Random[]
 
We now see a list of different and random numbers. This is because the evaluation was delayed. In[14]:= Table[f2, {5}]

Out[14]= {0.6303, 0.359894, 0.871377, 0.858645, 0.584579}
 
In[15]:= ??f1

Global`f1

f1 = 0.05607079483486153
 
The settings of the ?? clearly show the difference. In[15]:= ??f2

Global`f2

f2 := Random[]
 

Delayed assignment avoids evaluating the right-hand side. There are a number of other functions which do not evaluate their arguments. An example is ParametricPlot3D which possesses the attribute HoldAll delaying the evaluation of its arguments. An attribute is a property of a symbol which affects it behavior. In the example here the attribute HoldAll controls expressions of which the symbol is the head. Attributes are discussed in further detail in The Mathematica Book.

HoldAll a HoldAll function will delay argument evaluation
Evaluation[ expr ] evaluates this even if in a HoldAll function
Hold[ expr ] do not evaluate expr
ReleaseHold[ expr ] remove Hold if present
Other ways to delay evaluation.
This shows that ParametricPlot3D delays evaluation of the arguments. In[15]:= Attributes[ParametricPlot3D]

Out[15]= {HoldAll, Protected}
 
This would not plot three functions without the Evaluate. In[16]:= ParametricPlot3D[Evaluate[Table[{x, x^n, x^(2 n)}, {n, 3}]], {x, 0, 1}]
Out[16]= - Graphics3D -
 
This does not evaluate due to Hold. In[17]:= Hold[1 + 5]

Out[17]= Hold[1 + 5]
 
ReleaseHold removes the Hold and evaluation proceeds. In[18]:= ReleaseHold[%]

Out[18]= 6
 

Working with Lists

Mathematica lists are fundamental to the whole system. A good understanding of the power of list manipulations is a key to an understanding of Mathematica itself. There are many functions which work with lists and here we review some of the most basic.

Table construct a list
Map[f, list] travel down list applying f to each element
Apply[f, list] make f the head of list
Transpose[{list1, list2}] transpose {list1, list2}
Some useful commands for working with lists.
Make a list. In[19]:= list = Table[i, {i, 5}]

Out[19]= {1, 2, 3, 4, 5}
 
This travels down the list applying g to everything. It returns a list as the result. In[20]:= Map[g, list]

Out[20]= {g[1], g[2], g[3], g[4], g[5]}
 
In[21]:= Map[Sqrt, list]

Out[21]= {1, Sqrt[2], Sqrt[3], 2, Sqrt[5]}
 
This exchanges the head of list with g. In[22]:= Apply[g, list]

Out[22]= g[1, 2, 3, 4, 5]
 
Of course the result may evaluate further. Using Times will multiply all the numbers together. In[23]:= Apply[Times, list]

Out[23]= 120
 
In[24]:= list1 = {a, b, c}

Out[24]= {a, b, c}
 
In[25]:= list2 = {1, 2, 3}

Out[25]= {1, 2, 3}
 
This is an extremely useful way to collect things together. In[26]:= Transpose[{list1, list2}]

Out[26]= {{a, 1}, {b, 2}, {c, 3}}
 

Pure Functions

A command like Map will march down a list and apply a function to each element of the list. The examples were all of things like Sqrt and were deliberately chosen to be functions which only took one argument which was used to build an expression. For example Sqrt would build things of the type Sqrt[4] which will evaluate further. But what do you do if you have a function which takes two arguments or one which uses its argument at a deeper level?

For an example let us say we want to go down a list and record whether the elements are greater or less than some number. We could make a function to do this.

This is my function. In[27]:= newfun[x_] := Greater[x, 5]
 
This does the job. In[28]:= Map[newfun, {2, 4, 6, 8}]

Out[28]= {False, False, True, True}]
 

However this is not very satisfactory. I may want to compare my list with many different numbers and not just 5 as in this example. One solution is to use a pure function. This is a function which will put its argument at any level.

This is a pure function. It is labeled as a pure function by the & and the # shows where the argument will go. In[29]:= Greater[#, 5]&

Out[29]= #1 > 5 &
 
This applies the pure function. When this is evaluated the 10 will replace the #, called the slot, and this evaluates. In[30]:= Greater[#, 5]& [10]

Out[30]= True
 
This combines the pure function with Map. In[31]:= Map[Greater[#, 5]&, {2, 4, 6, 8}]

Out[31]= {False, False, True, True}]
 

Blocks and Modules

If you have lines of code with a common purpose and wish to group them together this may be done with either Block or Module. These allow you to collect commands together and provide tools for local variables.

The result of Block is the last evaluation. In[32]:= blockfun[n_] := Block[{i, res}, res = Table[i, {i, n}]; res = Partition[res, 2]; Transpose[res]]
 
In[33]:= blockfun[10]

Out[33]= {{1, 3, 5, 7, 9}, {2, 4, 6, 8, 10}}
 
Module is very similar to Block. The difference is the treatment of local variables. In[34]:= modfun[n_] := Module[{i, res}, res = Table[i, {i, n}]; res = Partition[res, 2]; Transpose[res]]
 
In[35]:= modfun[12]

Out[35]= {{1, 3, 5, 7, 9, 11}, {2, 4, 6, 8, 10, 12}}
 

next page: 6.2 Function Plotting back to table of contents