Message Boards Message Boards

0
|
5275 Views
|
12 Replies
|
2 Total Likes
View groups...
Share
Share this post:

[?] Make a dialog in a manipulate with initial values?

Posted 7 years ago

I am trying to make a dialog with manipulate like this:

If[ DialogInput[
   Column[{"Go on?", 
     ChoiceButtons[{DialogReturn[True], DialogReturn[False]}]}]] == 
  True, DialogInput[{Row[{TextCell[
      "          Value of b                                  "], 
     TextCell["                              Value of c    "]}],
   Row[{InputField[Dynamic[b]], InputField[Dynamic[c]]}],
   DefaultButton[DialogReturn[{}]]}];
 text = Row[{The , values, of, "b", and, "c", are, now, ToString[b], 
    and, ToString[c]}, " "];
 Manipulate[
  Show[Plot[Sin[a*x + b] + c, {x, 0, 2 \[Pi]}], 
   PlotLabel -> Style[text, 15, Black]], {a, 1, 10}]]

But when I evaluate this code for the first time, in the second dialog box the values of b and c are always presented as "b" and "c". For this first trial I would prefer to show them being 1 and 1 though. For the next trials the second dialog box should keep showing them to have the values of the last trial that was carrried out, exactly as is done when the above code is evaluated. How can I make this happen? Another question concerns the possibility that after the above code has been evaluated, I would like a dialog box to appear that asks if a new trial is wanted. I have tried to get this done using the function While instead of If , but then I get in a loop where two dialog boxes alternate and the manipulation box with the sinus curve never shows up. I also tried Label and GoTo, but this does not seem to work either.

POSTED BY: Laurens Wachters
12 Replies

Laurens,

I am glad you found my postings useful. I ran your version and it looks great. I noticed a place where you left in

 ImageSize -> {400, 30}, 

Which should be

 ImageSize -> {w, h}, 

As far as the pure functions go. It is often easier to understand if you define a function and use it in that spot. It may be quicker to use a pure function but often I regret it later when I do that!

For example, you can define

sliderReleaseFunction[x_]:= ...

Regards

Neil

POSTED BY: Neil Singer

Dear Neil, I am sorry. The above code contains an error. It should look like this:

DynamicModule[{data, xmin, xmax, ymin, ymax, ticks, ticknum = 4, int, 
  w = 400, h = 30},
 xmin = AbsoluteTime[{2014, 1, 1}];
 xmax = AbsoluteTime[{2014, 12, 31}];
 data = Partition[
   Riffle[AbsoluteTime /@ DayRange[xmin, xmax, "BusinessDay"], 
    Abs[Accumulate[
      RandomVariate[NormalDistribution[0, 1], 
       Length[DayRange[xmin, xmax, "BusinessDay"]]]]]], 2];
 ymin = Min[data];
 ymax = Max[data];
 int = {xmin, xmax};
 ticks = (xmax - xmin)/5*Range[4] + xmin;
 Column[{Dynamic[
    DateListPlot[data, ImageSize -> w, Joined -> True, 
     FrameTicks -> {Automatic, {ticks, None}}, 
     DateTicksFormat -> {"MonthNameShort", " ", "YearShort"}, 
     GridLines -> Automatic, PlotRange -> {int, Automatic}]], 
   IntervalSlider[
    Dynamic[int, {(int = #) &, (ticks = (int[[2]] - 
              int[[1]])/(ticknum + 1)*Range[ticknum] + 
          int[[1]]) &}], {xmin, xmax, 1}, ImageSize -> {400, 30}, 
    MinIntervalSize -> 1],
   DateListPlot[data, Frame -> False, Axes -> False, 
    ImageSize -> {w, h}, AspectRatio -> h/w, Joined -> True, 
    Epilog -> {Opacity[0.5], Orange, 
      Dynamic[Rectangle @@ Thread[{int, {ymin, ymax}}]]}], 
   Row[{"Number of Ticks: ", 
     PopupMenu[
      Dynamic[ticknum, {(ticknum = #) &, (ticks = (int[[2]] - 
                int[[1]])/(ticknum + 1)*Range[ticknum] + 
            int[[1]]) &}], Range[10]]}]}]]

Kind regards, Laurens

POSTED BY: Laurens Wachters

Thanks a lot Neil for your advice. I have also studied the code with the interval slider that you referred to. It took me some time to understand the working of the two pure functions, but I think I finally did. To test the code I had to find a replacement of the financial data, since these are unfortunately not available at this moment. I used an accumulation of random numbers. To fit this into the original code I also had to learn a bit on DayRange, DateObject and AbsoluteTime. I really enjoyed it. Here is the full code:

DynamicModule[{data, xmin, xmax, ymin, ymax, ticks, ticknum = 4, int, 
  w = 400, h = 30},
 data = Partition[
   Riffle[AbsoluteTime /@ 
     DayRange[DateObject[{2014, 1, 1}], DateObject[{2014, 12, 31}], 
      "BusinessDay"], 
    Abs[Accumulate[
      RandomVariate[NormalDistribution[0, 1], Length[x]]]]], 2];
 ymin = Min[data];
 ymax = Max[data];
 xmin = xy[[1, 1]];
 xmax = xy[[-1, 1]];
 int = {xmin, xmax};
 ticks = (xmax - xmin)/5*Range[4] + xmin;
 Column[{Dynamic[
    DateListPlot[data, ImageSize -> w, Joined -> True, 
     FrameTicks -> {Automatic, {ticks, None}}, 
     DateTicksFormat -> {"MonthNameShort", " ", "YearShort"}, 
     GridLines -> Automatic, PlotRange -> {int, Automatic}]], 
   IntervalSlider[
    Dynamic[int, {(int = #) &, (ticks = (int[[2]] - 
              int[[1]])/(ticknum + 1)*Range[ticknum] + 
          int[[1]]) &}], {xmin, xmax, 1}, ImageSize -> {400, 30}, 
    MinIntervalSize -> 1],
   DateListPlot[data, Frame -> False, Axes -> False, 
    ImageSize -> {w, h}, AspectRatio -> h/w, Joined -> True, 
    Epilog -> {Opacity[0.5], Orange, 
      Dynamic[Rectangle @@ Thread[{int, {ymin, ymax}}]]}], 
   Row[{"Number of Ticks: ", 
     PopupMenu[
      Dynamic[ticknum, {(ticknum = #) &, (ticks = (int[[2]] - 
                int[[1]])/(ticknum + 1)*Range[ticknum] + 
            int[[1]]) &}], Range[10]]}]}]]
POSTED BY: Laurens Wachters

Laurens,

You may also want to also consider setting the PlotRange manually so the axes do not bounce around. You might benefit from looking at the code I posted here for another forum question.

Regards

Neil

POSTED BY: Neil Singer

You should put the SeedRandom and the generation of the points in the same Dynamic so they are run together. Dynamic is smart about execution and will only run if it sees that something inside changes. It is not aware that changing the seed affects the distribution which does not necessarily need to be updated. When seed changes, you need to force the update of the RandomVariate. This code will run for you:

Panel[Column[{Row[{Slider[Dynamic[seed], {1, 100, 1}], Dynamic[seed]}],
   Dynamic[SeedRandom[seed]; 
    ListPlot[ 
     Accumulate[RandomVariate[NormalDistribution[0, 1], 200]]]]}]]
POSTED BY: Neil Singer

I am sorry. The first code should have been:

Panel[Column[{Row[{Slider[Dynamic[seed], {1, 100, 1}], 
Dynamic[seed]}], Dynamic[SeedRandom[Dynamic[seed]]];
Dynamic[
ListPlot[
Accumulate[RandomVariate[NormalDistribution[0, 1], 200]]]]}]]

It makes no difference in the output though. The problem remains. The slider refuses to control the curve. Laurens

POSTED BY: Laurens Wachters

Dear Neil, I very much like the solution you presented in your last post, since using this I would be able to add several controls for other parameters. But it does not seem to work for plotting an accumulation of random numbers, like in:

Panel[Column[{Row[{Slider[Dynamic[seed], {1, 100, 1}], Dynamic[seed]}],
   Dynamic[SeedRandom[Dynamic[seed]]];
   Dynamic[
    ListPlot[
     Accumulate[
      RandomVariate[NormalDistribution[0, 1], 200]]], {Dynamic[seed], 
     1, 100, 1}]}]]

The curve does not change when I move the thumb of the slider. I would like to make it work like this:

Manipulate[
SeedRandom[seed];
ListPlot[
Accumulate[RandomVariate[NormalDistribution[0, 1], 200]]], {seed, 1,
100, 1}]

Would that be possible? I have tried several things, but did not succeed. I hope you can help me. Thanks in advance. Laurens

POSTED BY: Laurens Wachters

The last, short example can be combined with the other to create the "retention" benefit for b and c:

DynamicModule[{a}, If[! NumberQ[b] || ! NumberQ[c], b = c = 1]; 
 Panel[Column[{Row[{InputField[Dynamic[b], Number], 
      InputField[Dynamic[c], Number]}], Slider[Dynamic[a], {1, 10}], 
    Dynamic[Plot[Sin[a*x + b] + c, {x, 0, 2 \[Pi]}]]}]]]

As to your second question, this version shown above would not need to have the question to plot a second curve because if you change b or c you get another curve, if you do not, nothing changes and you can move on.

Generally, "While" and "Goto" is highly frowned upon in Wolfram Language. There is almost always a better way.

Please describe the exact sequence you want -- The Dynamic controls can give you almost any behavior you want.

from what I can tell,

  1. you want a dialog to ask if you want to "go on" (I am not sure why because at the beginning there is no need for this-- I'd recommend eliminating this)
  2. A dialog for b and c (retaining last values using defaults first time through)
  3. a Manipulate plot with a slider for a.

Now here is where it gets confusing:

  1. You seem to want to ask whether or not to do another run of it. When would that dialog be triggered? As soon as you let go of the "a" slider? When you hit a "Done" button? Do you need this if b and c are always displayed and available to edit so you only trigger a new run when b or c changes (the code above does this)? Do you want the whole Plot and Manipulate inside of a dialog so it is closed when done?

If you detail the exact behavior you want, it will likely be achievable.

Regards

Neil

POSTED BY: Neil Singer

Thank you Gianluca and Neil for your help. The first solution of Neil does the job I need. The other two give for b and c with each new run the start values, i.e 1 and 1. I want them to keep the values of the previous run though. I did not know the existence of the function NumberQ. That one really does the job. The second code of Neil is nicely short, but I used just a simple example for presenting my problem. The code for which I need the solution is much more complicated.
Alas, neither one of you gave a solution for my second question. This one concerns the possibility of automatically make appear a dialog box that asks if the user wants to go on with another run after the sinus curve has been shown. Could this question maybe appear in the box in which the curve is shown, along with the appropriate OK and Quit buttons? As I said in my post, I tried While and GoTo + Label, but neither one did the job.

POSTED BY: Laurens Wachters

Also,

Note that you do not have to use a dialog for b and c -- you can always add them to the DynamicModule so they are dynamically adjustable along with a, (Have one slider and two dynamic input fields for b and c.

DynamicModule[{a, b = 1, c = 1},
 Panel[Column[{Row[{InputField[Dynamic[b], Number], 
      InputField[Dynamic[c], Number]}], Slider[Dynamic[a], {1, 10}], 
    Dynamic[Plot[Sin[a*x + b] + c, {x, 0, 2 \[Pi]}]]}]]]
POSTED BY: Neil Singer

Laurens,

First, you should read the posting instructions. It really helps if you post code using the code sample button. Your code has several problems. No need to use Show, There are extra brackets around Pi (because of the way you posted the code), Gianluca fixed these in his code. Here is an alternative if you want to retain old values from a previous run

If[DialogInput[
   Column[{"Go on?", 
     ChoiceButtons[{DialogReturn[True], DialogReturn[False]}]}]] == 
  True, If[! NumberQ[b] || ! NumberQ[c], b = c = 1]; 
 DialogInput[{Row[{TextCell[" Value of b "], 
     TextCell[" Value of c "]}], 
   Row[{InputField[Dynamic[b]], InputField[Dynamic[c]]}], 
   DefaultButton[DialogReturn[{}]]}]; 
 text = Row[{The, values, of, "b", and, "c", are, now, ToString[b], 
    and, ToString[c]}, " "]; 
 Manipulate[
  Plot[Sin[a*x + b] + c, {x, 0, 2 Pi}, 
   PlotLabel -> Style[text, 15, Black]], {a, 1, 10}]]

Note that I just Queried if b or c were non-numeric and if so, gave them numbers. For any Mathematica expression you can use a compound instruction by just separating them with semicolons. This enables you to do sequences of operations anywhere (such as testing for values before using them).

Regards

POSTED BY: Neil Singer

I would initialize the values of b and c with a DynamicModule:

DynamicModule[{a, b = 1, c = 1},
 If[DialogInput[Column[{"Go on?",
      ChoiceButtons[{DialogReturn[True], DialogReturn[False]}]}]] == 
   True, DialogInput[{Grid[{{"Value of b",
       "Value of c"},
      {InputField[Dynamic[b]], InputField[Dynamic[c]]}}], 
    DefaultButton[DialogReturn[{}]]}]; 
  text = Row[{"The values of b and c are now ", b, " and ", c}]; 
  Manipulate[
   Plot[Sin[a*x + b] + c, {x, 0, 2 \[Pi]}, 
    PlotLabel -> Style[text, 15, Black]], {a, 1, 10}]]]
POSTED BY: Gianluca Gorni
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract