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$
6
  • 1
    $\begingroup$ Options[myPlot] = Sort[Append[Options[Plot], "CommonZero" -> True]] and use OptionValue[] and FilterRules[] as necessary. $\endgroup$ Commented Jul 30, 2015 at 11:35
  • $\begingroup$ @Guesswhoitis. Is the edited solution what you meant? $\endgroup$
    – Phab
    Commented Jul 30, 2015 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$ Commented Jul 30, 2015 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
    Commented Jul 31, 2015 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
    Commented Jul 31, 2015 at 7:28

2 Answers 2

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$
2
  • $\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
    Commented Jul 31, 2015 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
    Commented Jul 31, 2015 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 and acknowledge you have read our privacy policy.

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