How to define part of a Manipulate control variable definition to reduce code duplication

后端 未结 3 1607
死守一世寂寞
死守一世寂寞 2020-12-04 20:46

This is a little related to this question

Define control as variable in Mathematica

But the above question did not answer my problem, as it talks about the f

相关标签:
3条回答
  • 2020-12-04 20:59

    I was going to give a solution almost the same as Leonid's and use With to insert the code, but he beat me to it, so here's an alternative way. Define a dynamic local function using ControlType -> None that does your styling:

    Manipulate[Plot[{f, g + 1}, {x, -1, 1}], 
     Dynamic[Grid[{{Style["f(x)="], pu[f]}, 
           {Style["g(x)="], pu[g]}}]], 
    {{pu, Function[{f}, PopupMenu[Dynamic[f], {x, x^2, x^3}, ImageSize -> Tiny], 
            HoldFirst]}, None}]
    

    By the way, the Style[] in Style["f(x)="] is redundant, as you are not actually setting any styles...

    0 讨论(0)
  • 2020-12-04 21:01

    What about this

    Manipulate[Plot[f*g, {x, -1, 1}],
     Evaluate@
      With[{styleAndpopup = 
          Function[{st, fun}, 
             {
               Style[st], 
               PopupMenu[Dynamic[fun], {x, x^2, x^3}, ImageSize -> Tiny]
             }, 
             HoldAll]},
        Grid[{styleAndpopup["f(x)=", f], styleAndpopup["g(x)=", g]}]]]
    

    This is actually a tiny example of the code-generation at work, since if you look at the FullForm of the resulting Manipulate, you will see the same expression you originally started with. The styleAndpopup is actually not a function here, but a macro, locally defined using With.

    EDIT

    Per request of the OP - generalizing to many controls. The easiest fix is to insert Sequence@@... as Sequence @@ {First@control1[.... However, there is some extraneous stuff that can be removed as well:

    Manipulate[{x, y}, 
     Evaluate@With[{control1 = 
         Function[{var, initialValue, str, from, to, incr}, 
           Unevaluated@{{var, initialValue, str}, from, to, incr, ImageSize -> Tiny}, 
           HoldAll]}, 
       Sequence @@ {
         control1[x, 0, "x=", 0, 1, .1], 
         control1[y, 0, "y=", 0, 2, .1], 
         control1[z, 0, "z=", 0, 10, .1]}]]
    
    0 讨论(0)
  • 2020-12-04 21:01

    One could do this:

    Manipulate[
      Plot[f*g, {x, -1, 1}]
    , Grid[
        { {Style["f(x)="], PopupMenu[Dynamic[f], opts]}
        , {Style["g(x)="], PopupMenu[Dynamic[g], opts]}
        }
      ]
    ] /. opts -> Sequence[{x, x^2, x^3}, ImageSize -> Tiny]
    

    If one is in the habit of assigning down-values to symbols whose names do not begin with $, then it would be prudent to wrap the whole thing in Block[{x, opts}, ...] in case x and opts have globally-defined values.

    A similar technique is possible for the case of multiple controls:

    Manipulate[
      {x, y, z}
    , Grid[
        { {control1[x, 0, "x=", 0, 1, .1]}
        , {control1[y, 0, "y=", 0, 2, .1]}
        , {control1[z, 0, "z=", 0, 10, .1]}
        }
      ]
    ] /. control1[var_, initialValue_, str_, from_, to_, incr_] :>
           Control[{{var, initialValue, str}, from, to, incr, ImageSize -> Tiny}]
    
    0 讨论(0)
提交回复
热议问题