Telling Plot to style vector-valued black-box func

2019-02-06 10:26发布

问题:

Suppose I write a black-box functions, which evaluates an expensive complex valued function numerically, and then returns real and imaginary part.

fun[x_?InexactNumberQ] := Module[{f = Sin[x]}, {Re[f], Im[f]}]

Then I can use it in Plot as usual, but Plot does not recognize that the function returns a pair, and colors both curves the same color. How does one tell Mathematica that the function specified always returns a vector of a fixed length ? Or how does one style this plot ?

EDIT: Given attempts attempted at answering the problem, I think that avoiding double reevalution is only possible if styling is performed as a post-processing of the graphics obtained. Most likely the following is not robust, but it seems to work for my example:

gr = Plot[fun[x + I], {x, -1, 1}, ImageSize -> 250];
k = 1;
{gr, gr /. {el_Line :> {ColorData[1][k++], el}}}

回答1:

One possibility is:

Plot[{#[[1]], #[[2]]}, {x, -1, 1}, PlotStyle -> {{Red}, {Blue}}] &@ fun[x + I]  

Edit

If your functions are not really smooth (ie. almost linear!), there is not much you can do to prevent the double evaluation process, as it will happen (sort of) anyway due to the nature of the Plot[] mesh exploration algorithm.

For example:

fun[x_?InexactNumberQ] := Module[{f = Sin[3  x]}, {Re[f], Im[f]}];
Plot[{#[[1]], #[[2]]}, {x, -1, 1}, Mesh -> All, 
   PlotStyle -> {{Red}, {Blue}}] &@fun[x + I]  



回答2:

I don't think there's a good solution to this if your function is expensive to compute. Plot will only acknowledge that there are several curves to be styled if you either give it an explicit list of functions as argument, or you give it a function that it can evaluate to a list of values.

The reason you might not want to do what @belisarius suggested is that it would compute the function twice (twice as slow).

However, you could use memoization to avoid this (i.e. the f[x_] := f[x] = ... construct), and go with his solution. But this can fill up your memory quickly if you work with real valued functions. To prevent this you may want to try what I wrote about caching only a limited number of values, to avoid filling up the memory: http://szhorvat.net/pelican/memoization-in-mathematica.html



回答3:

If possible for your actual application, one way is to allow fun to take symbolic input in addition to just numeric, and then Evaluate it inside of Plot:

fun2[x_] := Module[{f = Sin[x]}, {Re[f], Im[f]}]

Plot[Evaluate[fun2[x + I]], {x, -1, 1}]

This has the same effect as if you had instead evaluated:

Plot[{-Im[Sinh[1 - I x]], Re[Sinh[1 - I x]]}, {x, -1, 1}]