This one should be simple, but I can't figure it out. I would like to define a transformation (function) such that $r$ maps to $m.r + r$

The help file on AffineTransformation says that


maps $r$ to $m.r + v$

so for example

tt = AffineTransform[{d*IdentityMatrix[2], {a, b}}]

But how would I define a transformation such that it would return


for any ${x,y}$?

And that it could be applied to graphics objects, e.g,

Graphics[GeometricTransformation[Rectangle[], tt[d]]

where I have added a function argument d which is a parameter of the transformation function.



There are several things going on here:

  1. The a and b in the expression are fixed parameters and don't substitute for your inputs. Try a pure function or a standard function using SetDelayed as shown below.
  2. What you are trying to create is not an AffineTransformation.
  3. It's not immediately obvious how to pass the coordinates back into the transformation function (to this economist, it's not even clear if this works geometrically).

Part of the answer (item 1) lies in the difference between a function and a TransformationFunction. What you want is to substitute a and b for whatever values you pass it. Try this instead:

ttt[{a_, b_}] := 
 AffineTransform[{d*IdentityMatrix[2], {a, b}}][{a, b}]

ttt[{x, y}]
(* {x + d x, y + d y} *)

What's going on here? Looking at the output of your original tt function, reveals a TransformationFunction, which defines a function much like a pure function that can then be applied to some data.

(*TransformationFunction[{{d, 0, a}, {0, d, b}, {0, 0, 1}}]*)
TransformationFunction[{{d, 0, a}, {0, d, b}, {0, 0, 1}}][{p,q}]
(* {a + d p, b + d q} *)

But the a and b are fixed parameters, not variables that are substituted by the data passed to the function. That's why you need to do it as per the ttt function above, using SetDelayed (:=).

An alternative way to do what you want would be to define your function as a pure function. Notice the ampersand and the Slot (#) notation.

ttpure = AffineTransform[{d*IdentityMatrix[2], {#1, #2}}][{#1, #2}] &

But watch out, the syntax of the expected input is a bit different now - it expects two arguments, not inside curly braces (List expression):

ttpure[x, y]
(* {x + d x, y + d y} *)

If you have a pair of variables inside a list, then you need to use Apply (@@).

ttpure @@ {x, y}
(* {x + d x, y + d y} *)

Alternatively, you can restore the behaviour of ttt in taking a two-element list as the input by having a single Slot argument and accessing its Parts like this:

ttp2 = AffineTransform[{d*
  IdentityMatrix[2], {#[[1]], #[[2]]}}][{#[[1]], #[[2]]}] &

Personally I find the #[[]] notation to be quite ugly, but it works as required as long as you actually pass an argument that is a list with at least two elements:

ttp2[{x, y}]
(* {x + d x, y + d y} *)


Part::partw: Part 2 of {x} does not exist. >>
Part::partw: Part 2 of {x} does not exist. >>

(* {x + d x, {x}[[2]] + d {x}[[2]]} *)

ttp2[{x, y, z}]
(* {x + d x, y + d y} *)

Edit in response to comment

To actually make this work on a graphic, you need everything to be numeric. Notice I've added a third argument (#3) here.

ttpure = AffineTransform[{#3*IdentityMatrix[2], {#1, #2}}][{#1, #2}] &

 ttpure[0.3, 0.6, 0.2]], PlotRange -> 1]

enter image description here

However, this isn't quite what you want, since the actual coordinates aren't passed into the TransformationFunction, only the parameters you pass. (This will have to wait for a later update.)

| improve this answer | |
  • $\begingroup$ Fantastic! This works exactly. Thanks for your quick reply. $\endgroup$ – ShaunH Sep 4 '12 at 3:42
  • $\begingroup$ I'm not sure if I understand quite correctly. Does this mean ttt is not a TransformationFunction? I.e, it doesn't seem like I can use it to transform a graphics object (e.g. a Rectangle) using GeometricTransformation. I.e. Graphics[GeometricTransformation[Rectangle[], ttt]] $\endgroup$ – ShaunH Sep 4 '12 at 3:52
  • $\begingroup$ You are welcome @ShaunH - have a look at my edit. It might be helpful. And by the way, welcome to Mathematica.SE! $\endgroup$ – Verbeia Sep 4 '12 at 3:52
  • $\begingroup$ ttt is a function that applies a TransformationFunction to the input, rather than just defining the function. Hopefully my addition, especially ttpure clarifies the difference. For the case you mention in comments, try ttpure. $\endgroup$ – Verbeia Sep 4 '12 at 3:53
  • $\begingroup$ Thanks for the edit @Verbeia, but I don't quite understand why you would have to specify the coordinates x and y. Is there a way to make d the (only) argument, so for example, Framed@Graphics[GeometricTransformation[Rectangle[], ttpure[0.2]] where the 0.2 is the chosen d? $\endgroup$ – ShaunH Sep 4 '12 at 4:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.