Keep function range as a variable

Plot[2*x^2 - x + 2, {x, -1, 1}] plots a function of x from -1 to 1. As far as I can see, I cannot "save" this range in a variable:

u = {x, -1, 1};
Plot[2*x^2 - x + 2, u]


Generates Plot::pllim: Range specification u is not of the form {x, xmin, xmax}. Hopefully my intention is obvious, what is the most concise way of accomplishing it?

Because someone will wonder why I could possibly want to do this: I have

NDSolve[..., ..., {t, 0, 100}];
Plot[..., {t, 0, 100}];


I don't want to need to modify both 100's as my desired range changes. Yes, I could use variables t0 and t1, but is what type is the range/domain expression? Why can't I store it directly?

-
 The reason why what you tried did not work is that Plot has the HoldAll attribute (this is to make it work even if x has a value). Unfortunately I see no convenient way to get around this. As MrW pointed it out, Plot[..., Evaluate[u]] is not robust: it won't work if x has a value. Yes, this is annoying, and I'd also like a really convenient way to store these ranges. – Szabolcs Mar 6 at 1:16 How about: With[{lims = Sequence[0, 100]}, NDSolve[...,..., {x, ##}] &@lims; Plot[..., {x, ##}] &@lims ] – rm -rf♦ Mar 6 at 1:26 Maybe I'm missing something, but it seems the key point is to save the limits $-1$ and $1$ in the variable u and that it wouldn't do any harm to re-specify the variable x explicitly in Plot. So why not u={-1,1}; Plot[f[x], Evaluate@Prepend[u,x]]? Or is it important that x be referenced within u itself? If so, why? – whuber Mar 6 at 18:01 @Szabolcs Can you think of better tags for this question than syntax? – Mr.Wizard♦ Mar 9 at 0:41 @Mr.Wizard I tried, please review. I think this is also related to "macro expansion". There were questions about that, but I can't find them now. Maybe they were on SO. This is really about convenience, making it easier to type code. Maybe we should have a tag for things like that? – Szabolcs Mar 9 at 1:20
show 1 more comment

Better methods

My original answer was pretty poor and I'll show you why.

Suppose x has a value assigned: x = 7. This does not bother Plot:

Plot[2*x^2 - x + 2, {x, -1, 1}]  (* outputs graphic *)


It however will prevent my earlier suggestions from working:

Plot[2*x^2 - x + 2, Evaluate@u]


During evaluation of In[23]:= Plot::itraw: Raw object 7 cannot be used as an iterator. >>

Plot[2 x^2 - x + 2, {7, -1, 1}]


Instead you should store your range in a way that holds the plot parameter unevaluated:

u = Hold[{x, -1, 1}];


Then you need a way to put this inside the Plot expression without it evaluating. This can be done with a Function and a hold attribute and Apply:

Function[spec, Plot[2*x^2 - x + 2, spec], HoldAll] @@ u  (* outputs graphic *)


Or more tersely with the "injector pattern":

u /. _[spec_] :> Plot[2*x^2 - x + 2, spec]  (* outputs graphic *)


You just need Evaluate:

u = {x, -1, 1};

Plot[2*x^2 - x + 2, Evaluate @ u]


Or as I often prefer, Function:

Plot[2*x^2 - x + 2, #] & @ u

-

To take a more advanced approach in response to Szabolcs's comment, one can use UpValues. I define a new kind of set function as follows:

SetAttributes[setSpec, HoldAllComplete]

setSpec[s_Symbol, spec__] := s /: h_[pre__, s, post___] := h[pre, spec, post]


Then make an assignment, and use it:

setSpec[u, {x, 0, 10}];

Plot[Sin[x], u, PlotStyle -> Red]


Or with more than one specification:

setSpec[v, {x, -3, 3}, {y, -3, 3}, StreamStyle -> "Pointer"]

StreamPlot[{-1 - x^2 + y, 1 + x - y^2}, v,
PlotLabel -> s,
StreamScale -> {Full, All, 0.03}]

-

I have a simple mind and like simple methods. In this case, I suggest using a formal parameter.

u = {\[FormalX], -1, 1};


The character \[FormalX] can be typed using the keystrokes [esc]\$x]esc].

Using \[FormalX] rather than x is robust because \[FormalX] has the Protected attribute and can not be bound to a value.

\[FormalX] = 42; ValueQ@\[FormalX]


Set::wrsym: Symbol \[FormalX] is Protected.

False

With u defined as above, you can make your plot by evaluating

Plot[2*\[FormalX]^2 - \[FormalX] + 2, Evaluate@u]


or by evaluating

With[{u = u}, Plot[2*\[FormalX]^2 - \[FormalX] + 2, u]]


Should you dislike the extra typing needed to insert \[FormalX] or should you want the freedom to use a parameter name entirely of your own choosing, you can roll your own formal parameters.

SetAttributes[makeFormal, HoldFirst];
makeFormal[u_Symbol] := (Clear[u]; Protect[u];)

Unprotect@x;
x = 42;
makeFormal@x;
Print[Attributes[x]];
ValueQ@x


{Protected}

False

Now x will act just like \[FormalX].

u = {x, -1, 1};
Plot[2*x^2 - x + 2, Evaluate@u]


The above is now safe because x can no longer take a value.

-