Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am a little bit confused by the documentation for Apply (@@).

I want to define a list of parameters, for instance:

parameters = {{1/2, 1/2}, {1, 1/3}, {2, 1/4}, {0.5, 1/5}};

Then I have a function:

(b/a)*((a/x)^(b+1))

Now I want to map the pair (a,b) to the values defined in parameters and generate a plot for each pair of parameters in the same graph.

Now the plot syntax would look something like this:

p = Plot[Evaluate[myfunction /@ parameters], {x, 0, 3},
         AxesOrigin -> {0, 0}, AxesLabel -> {x, f}, PlotStyle -> styles]

What I struggle with, is getting the syntax right in the following part:

myfunction /@ parameters

How do I need to define this so I get a proper map of (a,b) to my list of parameters? To be honest, I am not very satisfied with the documentation for Map. Are there better tutorials?

share|improve this question
2  
Though old and extremely limited in scope , there's always the Flash tutorials. –  Brett Champion May 6 '12 at 4:33
add comment

4 Answers

up vote 4 down vote accepted

There are two main ways of accomplishing this, both have their merits, but Map may be easier to understand initially. For instance, using (b/a)*((a/x)^(b+1)) I would do the following,

(#[[2]]/#[[1]])(#[[1]]/x)^(#[[2]]+1)& /@ parameters

where #[[1]] and #[[2]] are a and b, respectively. But, this makes it difficult to read, alternatively you can use With to improve the readability, as follows,

With[{a = #[[1]], b = #[[2]]}, (b/a)*((a/x)^(b+1))]& /@ parameters

It is longer, but it is more readable. I tend to use With in this way. The second method is to use Apply, as outlined by R.M. Here With can also be used,

With[{a = #1, b = #2}, (b/a)*((a/x)^(b+1))]& @@@ parameters

but it is less likely to be confusing when you come back to the code a month later.

share|improve this answer
    
Ok! Does the "#" in front designate it as a parameter? Does the number designate the order, so that the program knows which value from {number1, number2} to map? Why do we have 3 @'s. How does this "level" theory work? –  Chris May 6 '12 at 3:15
    
@Chris The # is a formal parameter known as a Slot. # is shorthand for #1. In my example using Map, #[[1]] refers to the first element of the first parameter. As noted by RM, Apply differs in that it replaces the Head of an expression, so Apply[f, {x,y}] (shorthand f@@{x,y}) becomes f[x,y]. The @@@ is shorthand for Apply[f, {{1,2},{3,4}}, {1}] which results in {f[1,2], f[3,4]}. Because the elements become arguments, #1 becomes a and #2 becomes b in your question. –  rcollyer May 6 '12 at 3:20
1  
For the last approach (using @@@) you could use Function[{a, b}, (b/a)*((a/x)^(b + 1))] instead of With. –  Brett Champion May 6 '12 at 4:19
add comment

Here's another way:

parameters = {{1/2, 1/2}, {1, 1/3}, {2, 1/4}, {0.5, 1/5}};

myfunction[{a_, b_}] := (b/a)*((a/x)^(b + 1))

Plot[myfunction /@ parameters, {x, 0, 3}, Evaluated -> True]

Mathematica graphics


Using plain x here is not local; you should consider using \[FormalX] instead. The example above is "safe" because x is localized by Plot (it would not be if you used Plot[ Evaluated @ ... ] instead of Evaluated -> True). On the other hand if you accidentally assign a value to x and then try something like myfunction[{1, 1/3}] /. x -> 5 it will not behave as expected. Formal Symbols are symbols that Mathematica will not let you assign a value to, protect you from yourself in a case like this. It is a good idea to use them if you are going to create a definition with a "floating" undefined symbol like x in the example above.

share|improve this answer
    
Can you expand upon \[FormalX] and why it is useful? Why does it work here, when x would not? –  rcollyer May 6 '12 at 3:14
1  
@rcollyer well here it is not needed because Evaluated -> True rather than Evaluated @ localizes x anyway, but generally speaking it's a bad idea to float around a global variable that's not supposed to have a value, because at some point it might be assigned one accidentally. That's what the Formal Symbols are for. (I know you know this.) –  Mr.Wizard May 6 '12 at 3:23
1  
Well, it does change, but I can't think of an instance where I have not desired this behaviour... –  rm -rf May 6 '12 at 5:22
2  
Incidentally, the Evaluated trick is on Szabolcs' web page. It is about 1/3 the way down the page. –  rcollyer May 6 '12 at 14:02
1  
@rcollyer outside of SE I can track it back to at least this. –  Mr.Wizard May 6 '12 at 18:33
show 7 more comments

You can define your function as an anonymous function and use Apply at level 1 or @@@:

myfunction[x_] := #2/#1 ((#1/x)^(#2 + 1)) &
Plot[Evaluate[myfunction[x] @@@ parameters], {x, 0, 3},  
    AxesOrigin -> {0, 0}, AxesLabel -> {x, f}]

enter image description here


Think of Apply as something that replaces the Head of an expression. For example, the head of g[a, b] is g. Now if you apply f to that expression, you get:

f @@ g[a, b]
(* Out= f[a, b] *)

You see that the head has been replaced with f. The long form of Apply also takes a third argument, where you can specify the Level that you want it to act on i.e., you can write Apply[f, expr, {level}].

Apply at level 1 is used very often, that it has its own shorthand, which is @@@ and is what I've used above. Here's an example showing the difference between @@ and @@@:

f @@ g[h[a, b], h[c, d]]
(* Out= f[h[a, b], h[c, d]] *)

f @@@ g[h[a, b], h[c, d]]
(* Out= g[f[a, b], f[c, d]] *)
share|improve this answer
    
I was working so hard to include both methods, but you stole my thunder, +1. :) –  rcollyer May 6 '12 at 3:09
    
Is that & at the end of the line where myfunction is defined necessary? Why can't I defined the function, put a ; at the end and then run the plot? –  Chris May 6 '12 at 3:25
    
@Chris he's being clever. As pointed out by Mr.Wizard, x is global, and within the bounds of Evaluate it would take on it's global value. What that construct does is localize x to the local form. –  rcollyer May 6 '12 at 3:29
    
@Chris Yes, it is necessary. The & is what completes the pure function definition and it won't work without it. My definition above is a mix of named patterns (x_) which localizes the variable x and slots (#) which take the parameter values when you apply at level 1. –  rm -rf May 6 '12 at 3:30
add comment

Here's another solution, which uses replacement rules, and is syntactically closest to your original code (and, unlike most other solutions, doesn't require you to rewrite either myfunction or parameters).

p = Plot[Evaluate[myfunction /. {a->#1, b->#2}& @@@ parameters], {x, 0, 3},
                  AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]

However, in case you can rewrite myfunction, the simplest solution would be to make it a function of the parameters:

myfunction[a_, b_] := (b/a)*((a/x)^(b+1))
p = Plot[Evaluate[myfunction @@@ parameters], {x, 0, 3},
                  AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]

Or maybe cleaner (but slightly more verbose):

myfunction[a_, b_, x_] := (b/a)*((a/x)^(b+1))
p = Plot[Evaluate[myfunction[##,x]& @@@ parameters], {x, 0, 3},
                  AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]

On the other hand, if you cannot change myfunction, but can change how your parameters are written, you could directly write the latter as rules:

parameters = {{a->1/2, b->1/2}, {a->1, b->1/3}, {a->2, b->1/4}, {a->0.5, b->1/5}};

Then your plot call would just read

p = Plot[Evaluate[myfunction /. parameters], {x, 0, 3},
                  AxesOrigin -> {0,0}, AxesLabel -> {x,f}, PlotStyle -> styles]
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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