2
$\begingroup$

I know, this is very close to Functions with Options and/or Function with custom Options and modified Options for built-in Symbols, but I don't get it.

My function looks like this one:

myPlot[data1_, data2_, opts : OptionsPattern[]] :=
 Module[{Rescaled, dataRescaled},
  Rescaled[x_, commonZero_: False] :=
   If[commonZero,
    (* for an common zero line *)
    x - 5,
    (* normal *)
    x
    ];
  dataRescaled = Rescaled[data2];
  ListLinePlot[{data1, dataRescaled},
   FilterRules[{opts}, Options[ListLinePlot]],
   PlotLegends -> {"should not", "be the legend"}]
  ]

And this is how I want to call it:

myPlot[
 Sin[Range[51, 100, .1]],
 Cos[Range[51, 100, .1]] + 5,
 PlotLegends -> Automatic
 ]

enter image description here

But how can I add an option "CommonZero->True"?

EDIT:

I edited my function this way

myPlot[data1_, data2_, 
  opts : OptionsPattern[{ListLinePlot, Rescaled}]] :=
 Module[{Rescaled, dataRescaled},
  Options[Rescaled] = {CommonZero -> False};
  Rescaled[x_, OptionsPattern[]] :=
   If[OptionValue[CommonZero],
    (* for an common zero line *)
    x - 5,
    (* normal *)
    x
    ];
  dataRescaled = 
   Rescaled[data2, CommonZero -> OptionValue[CommonZero]];

  ListLinePlot[{data1, dataRescaled},
   FilterRules[{opts}, Options[ListLinePlot]],
   PlotLegends -> {"should not", "be the legend"}]
  ]

But I doubt this is the right or a nice way to do.

$\endgroup$
  • 1
    $\begingroup$ Options[myPlot] = Sort[Append[Options[Plot], "CommonZero" -> True]] and use OptionValue[] and FilterRules[] as necessary. $\endgroup$ – J. M. will be back soon Jul 30 '15 at 11:35
  • $\begingroup$ @Guesswhoitis. Is the edited solution what you meant? $\endgroup$ – Phab Jul 30 '15 at 12:01
  • 1
    $\begingroup$ If you'll pardon me for being frank, your implementation looks a bit more fragile (unless this is a toy example and your actual routine has good reasons for having a function definition within a function definition). Maybe separate out Rescaled, and set up an option default list the way I did in my previous comment. $\endgroup$ – J. M. will be back soon Jul 30 '15 at 12:05
  • $\begingroup$ I gave this answer to illustrate a different issue, but it is a pretty good example of handling options in a function definition. $\endgroup$ – m_goldberg Jul 31 '15 at 2:38
  • $\begingroup$ @Guesswhoitis. I don't mind you being frank, on contrary. As I would call myself still a beginner in Mathematica, I'm thankful for every suggestion for improvement. But yes, it's just a toy function :-) But I was not aware one should not define functions in functions (if they should be 'private'). So I guess building a own package would be a good way?! Or is there another way to have private functions? $\endgroup$ – Phab Jul 31 '15 at 7:28
1
$\begingroup$

If we can pull the function Rescaled outside of myPlot, as Guess who it is suggests, then it can be done in a fairly straightforward way. (If Rescaled is to depend on the arguments to myPlot, perhaps Rescaled can be written so that any needed parameters can be passed to it through the function call instead coded in its definition. Then the following method could be used.)

ClearAll[Rescaled, myPlot];
Options[Rescaled] = {"CommonZero" -> False};
Rescaled[x_, OptionsPattern[]] := 
  If[TrueQ@OptionValue["CommonZero"],  (*for an common zero line*)
   x - 5,                              (*normal*)
   x];
myPlot[data1_, data2_, opts : OptionsPattern[{ListLinePlot, Rescaled}]] := 
 Module[{dataRescaled},
  dataRescaled = Rescaled[data2, FilterRules[{opts}, Options[Rescaled]]];
  ListLinePlot[{data1, dataRescaled}, 
   FilterRules[{opts}, Options[ListLinePlot]], 
   PlotLegends -> {"should not", "be the legend"}]
  ]

myPlot[Sin[Range[51, 100, .1]], Cos[Range[51, 100, .1]] + 5, 
 PlotLegends -> Automatic, "CommonZero" -> True]

Mathematica graphics

$\endgroup$
  • $\begingroup$ My idea with the neasted function was to have a kind of a 'private' function because I dont want to have a lot userdefined functions around. $\endgroup$ – Phab Jul 31 '15 at 7:31
  • 1
    $\begingroup$ @Phab (1) The way Mathematica does that for its own functions is usually through Contexts. Use foo`Rescaled instead of just Rescaled, where foo is a name you choose. (2) Otherwise you can move the Rescaled defs (both Options and Rescaled) inside the module (without change) and add Options[myPlot] = Join[Options[ListLinePlot], {"CommonZero" -> False}]; before the definition of myPlot. (3) If it's truly a lot of functions, consider Packages. $\endgroup$ – Michael E2 Jul 31 '15 at 10:17
0
$\begingroup$

If I follow this, the central issue is how to have the main function accept a list of options that need to be separately dispersed to different functions internally.

After messing around a good bit, I've given up on even using OptionsPattern for the main input

myf[a_, opts : OptionsPattern[commonZero -> 42]] :=
    Print[Row[{"myf option is ", OptionValue[commonZero]}]]
f[fn_, opts_List: {}] := (
    myf[0, Evaluate[
          Cases[ opts , x_Rule /; MemberQ[{commonZero}, First@x]]]];
    Plot[fn, {x, 0, 1}, 
         Evaluate[
           Cases[ opts , 
              x_Rule /; MemberQ[First /@ Options[Plot], First@x]]]])

f[x]
f[Sqrt[x] + 1/2, {PlotRange -> {1/2, 3/2}, commonZero -> 1}]

enter image description here

This obviously needs work to make robust (A single option must be in {} for one thing ).

$\endgroup$

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.