4

V 8.04. This is in the context of Manipulate use only.

Here is a simple example of using an Item to place controls in different places in the UI using Manipulate

Manipulate[Plot[Sin[z], {z, -Pi, Pi}, ImageSize -> 100],
 Item[Control[{{x, 0, "x="}, 0, 10, 1,ImageSize->Tiny}],ControlPlacement->Left],
 Item[Control[{{y, 0, "y="}, 0, 10, 1,ImageSize->Tiny}],ControlPlacement->Right]
 ]

enter image description here

However, I am using Leonid's macro method (link here ) to help me build my UI controls, so I'd like to do something like

 Manipulate[Plot[Sin[z], {z, -Pi, Pi}],

 Evaluate@With[{im = ImageSize -> Tiny},

   Item[Control[{{x, 0, "x="}, 0, 10, 1, im}],ControlPlacement -> Left],
   Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], ControlPlacement -> Right]

   ]    
 ]

The above does NOT work, because we no longer have ONE expression to make With happy, which has the syntax

 With[{x=x0}, expression ]

And in the above, the 2 Items are now not ONE expression, but 2.

This problem shows up only when I want to use Item to control placement. Otherwise, I would use Grid[] and combine my different things inside the Grid, and then the problem is solved.

But I can't of course use Item inside grid for purposes of making each Item locate in different place. The whole Grid has to be in one place.

I thought wrapping the 2 Items inside a Sequence[] might work but it does not.

question is: Any trick to combine the above 2 Items into ONE expression to make With happy?

Currently I solve this problem in my UI by simply breaking things into 2 separate Withs like this:

Manipulate[Plot[Sin[z], {z, -Pi, Pi}],

 Evaluate@With[{im = ImageSize -> Tiny},
   Item[Control[{{x, 0, "x="}, 0, 10, 1, im}], 
    ControlPlacement -> Left]
   ],

 Evaluate@With[{im = ImageSize -> Tiny},
   Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], 
    ControlPlacement -> Right]
   ]

 ]

And it works fine.

But of course, in the above, I lose some of the benefits of using macro names to share among many control construction code.

update 12/26/11 8:37 PM

Here is an example, using one macro inside another. I think it is a Hold issue. The trick shown below is not working for this. Will try to figure it out: (In practice, I use 2 levels macros, as I define some macros at one level, and use them to build a higher level macros in the second level. here I only show very simple example of what I mean)

Manipulate[Plot[Sin[z], {z, -Pi, Pi}],

 Evaluate@With[{im = ImageSize -> Tiny},

   Evaluate@With[{},

     ## &[
      Item[Control[{{x, 0, "x="}, 0, 10, 1, im}], ControlPlacement -> Left],
      Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], ControlPlacement -> Right]
      ]

     ]
   ]
 ]

I am almost sure I need a HoldAll thing to insert in the right place to sort this one out. Will try to figure it out and report here. Coffee is almost done ;)

update 9 pm

Ok, MrWizard showed me the problem with above. I should not have an Evaluate on the inner macros. I forgot about this. Here it is now, it works fine:

Manipulate[Plot[Sin[z], {z, -Pi, Pi}],

 Evaluate@With[{},

   With[{},
    ## &[
     Item[Control[{{x, 0, "x="}, 0, 10, 1}], ControlPlacement -> Left], 
     Item[Control[{{y, 0, "y="}, 0, 10, 1}], ControlPlacement -> Right]
     ]

    ](*close second With*)
   ](*close first With*)

 ](*close Manipulate*)

Thanks for the answer, both very useful.

Community
  • 1
  • 1
Nasser
  • 12,849
  • 6
  • 52
  • 104

2 Answers2

7

Use Sequence, perhaps like:

Manipulate[
   Plot[Sin[z], {z, -Pi, Pi}], 
   Evaluate@With[{im = ImageSize -> Tiny}, 
      Sequence @@ {
         Item[Control[{{x, 0, "x="}, 0, 10, 1, im}], ControlPlacement -> Left], 
         Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], ControlPlacement -> Right]
         }
      ]
   ]

Edit

Same approach, but with a different macro (warning, this way leads to madness...)

Manipulate[
   Plot[Sin[z], {z, -Pi, Pi}], 
   Evaluate @ With[{
      control = Function[{var, name, place}, 
         Item[Control[{{var, 0, name <> "="}, 0, 10, 1, ImageSize -> Tiny}],  ControlPlacement -> place], 
         HoldAll
         ]}, 
   Sequence @@ {control[x, "x", Left], control[y, "y", Right]}
   ]]
Brett Champion
  • 8,497
  • 1
  • 27
  • 44
  • Interesting variation. Are there benefits or disadvantages to either version? – Mr.Wizard Dec 27 '11 at 01:47
  • @Mr.Wizard I don't think there's an advantage one way or the other. My first attempt was similar to yours except I was trying to avoid parentheses and brackets, and `Evaluate@Sequence@@With[...]` has the wrong precedence. – Brett Champion Dec 27 '11 at 02:01
  • If nothing else it had the advantage of getting me thinking about putting `Sequence` inside `With` which allowed me to see what I believe is the "correct" way to do this. (See my updated answer.) – Mr.Wizard Dec 27 '11 at 02:04
6

Don't forget about Sequence and Apply.

Manipulate[Plot[Sin[z], {z, -Pi, Pi}],
 Evaluate[
  Sequence @@ With[{im = ImageSize -> Tiny},
    Hold[
     Item[Control[{{x, 0, "x="}, 0, 10, 1, im}], ControlPlacement -> Left],
     Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], ControlPlacement -> Right]
    ]
   ]
]]

Mathematica graphics

Brett's answer made me realize the same thing can be done more tersely like this:

Manipulate[
 Plot[Sin[z], {z, -Pi, Pi}],
 Evaluate @ With[{im = ImageSize -> Tiny},
   ## &[
    Item[Control[{{x, 0, "x="}, 0, 10, 1, im}], ControlPlacement -> Left], 
    Item[Control[{{y, 0, "y="}, 0, 10, 1, im}], ControlPlacement -> Right]
   ]
  ]
] 

Since With does not have SequenceHold attribute we cannot do simply Sequence[Item, Item], but we can use ## &[Item, Item] because & delays the evaluation.

Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • @MrWizard, +100, I am not sure now how this works, I need to surgically break it up and study it to figure out, but it works! thanks. – Nasser Dec 27 '11 at 01:49
  • @Nasser, it's the same thing as Brett's method, except I put the `Sequence` outside of `With` and used `Hold` to make sure that nothing evaluated prematurely, though I am not sure that is actually needed. Please see my update, as I think that is the cleaner approach as it does without `Apply`. – Mr.Wizard Dec 27 '11 at 01:56
  • @MrWizard, I am now trying to get your `##&` method to work for embeded macros, which what I really have, and not one level, but need more time. I am making coffee now and should I hope be able to figure it out soon. my example was one level, since I thought it will make no difference. I put an example of what I mean in my update. But I will try to resolve this myself if I can, it is a challenge :) – Nasser Dec 27 '11 at 02:36
  • 1
    @Nasser, just get rid of your inner `Evaluate` -- I can add an example if it's needed. – Mr.Wizard Dec 27 '11 at 02:52
  • @MrWizard, Thanks! you are right. I was bitten by this before (putting an Evaluate on the inner macro) and forgot all about it. Yes, that was it. It now works very well. I'll add this to my big cheat sheet for Mathematica now. – Nasser Dec 27 '11 at 02:59