Mathematica中的嵌套Manipulate

6
请注意:
Function[subID, 
         pointSO[subID] = RandomInteger[{1, 4}, {5, 2}]] /@ {"subA", "subB"};

Manipulate[
           Manipulate[
                      Graphics[{
                                Black, Rectangle[{0, 0}, {5, 5}],
                                White,Point@pointSO[subID][[i]]
                               },
                               ImageSize -> {400, 300}], 
           {i,Range[Length@pointSO[subID]]}], 
{subID, {"subA", "subB"}}]

enter image description here

假设pointSO[subID]实际上返回不同长度的列表,是否有一种方法可以避免使用两个Manipulate,因为其中一个被操纵的变量依赖于另一个变量?


两个列表的长度相同。也许使用listlength["subA"] = 5; listlength["subB"] = 9; Function[subID, pointSO[subID] = RandomInteger[{1, 4}, {listlength[subID], 2}]] /@ {"subA", "subB"};函数说明了单个Manipulate所遇到的问题。 - kglr
我的解决方案在长度不同的列表中运行良好。 i的操作器可以动态调整。我认为主要问题可能是没有为i指定默认值。 - Timo
您需要在内部 Manipulate 中明确设置 ControlType -> SetterBar,以避免 subAsubB 的内部 Manipulate 中出现不同的控件。 - kglr
@Timo,当您从“subB”切换到“subA”时,如果“i”的值大于列表“subA”的长度,则会出现可怕的红色矩形,其中两个列表“subA”和“subB”的长度分别为5和9。 - kglr
我明白了。这可能是不可避免的,我一时想不到如何欺骗Manipulate在切换第一个控件时刷新第二个控件。 - Timo
3个回答

5

我不确定我是否完全理解你的要求,但我想你想要的是以下内容:

给定一个UI界面,有一个变量(例如数组),可以改变其大小,还有另一个(依赖)变量,表示从UI中要使用的当前数组的索引。

但是您不希望在UI中固定索引变量的布局,因为它在运行时取决于数组的大小,而数组的大小可以使用第二个变量进行更改。

这里是一个操作方法,其中有一个UI界面,具有一个索引控制变量,该变量会随着数组大小的更改而动态更新UI界面。

我使用SetterBar来设置索引(依赖变量),但您也可以使用滑块。 SetterBar使UI上正在更改的内容更加清晰。

当您更改数组的长度时,索引控制变量会自动更新其允许使用的最大索引,以匹配当前数组的长度。

当您缩小数组时,索引也将缩小。

我不确定这是否符合您的要求,但如果是,您可以调整此方法以适应您的问题

Manipulate[

 Grid[{
   {Style[Row[{"data[[", i, "]]=", data[[i]]}], 12]},
   {MatrixForm[data], SpanFromLeft}
   },
  Alignment -> Left, Spacings -> {0, 1}
  ],

 Dynamic@Grid[{
    {Text["select index into the array = "],
     SetterBar[Dynamic[i, {i = #} &], Range[1, Length[data]], 
      ImageSize -> Tiny,
      ContinuousAction -> False]
     },

    {
     Text["select how long an array to build = "],
     Manipulator[
      Dynamic[n, {n = #; If[i > n, i = n]; 
         data = Table[RandomReal[], {n}]} &],
      {1, 10, 1}, ImageSize -> Tiny, ContinuousAction -> False]
     , Text[Length[data]], SpanFromLeft
     }
    }, Alignment -> Left
   ],

 {{n, 2}, None},
 {{i, 2}, None},
 {{data, Table[RandomReal[], {2}]}, None},
 TrackedSymbols -> {n, i}
 ]

输入图像描述

输入图像描述

更新 8:30 PM 提醒一下,刚刚对上述代码进行了修复,添加了必要的额外逻辑。


不知道这是否是原帖作者想要的,但对我很有用!:D - telefunkenvf14

2
为了避免在切换列表时 i 太大的问题,您可以在 Manipulate 开头添加一个 If [] 语句,例如:
Clear[pointSO];
MapThread[(pointSO[#] = RandomInteger[{1, 4}, {#2, 2}]) &, 
  {{"subA", "subB"}, {5, 7}}];

Manipulate[
 If[i > Length[pointSO[subID]], i = Length[pointSO[subID]]];
 Graphics[{Black, Rectangle[{0, 0}, {5, 5}], White, 
   Point@pointSO[subID][[i]]}, ImageSize -> {400, 300}],
 {{subID, "subA"}, {"subA", "subB"}, SetterBar},
 {{i, {}}, Range[Length@pointSO[subID]], SetterBar}]

也许更好的方法是在切换列表时重置i。可以通过执行以下操作来实现:
Manipulate[
 Graphics[{Black, Rectangle[{0, 0}, {5, 5}], White, 
   Point@pointSO[subID][[i]]}, ImageSize -> {400, 300}],
 {{subID, "subA"}, 
   SetterBar[Dynamic[subID, (i = {}; subID = #) &], {"subA", "subB"}] &},
 {{i, {}}, Range[Length@pointSO[subID]], SetterBar}
]

2
一种保留每个数据集选择设置的替代实现:
listlength["subA"] = 5; listlength["subB"] = 9; 
Function[subID, 
pointSO[subID] = 
RandomInteger[{1, 4}, {listlength[subID], 2}]] /@ {"subA", "subB"};

Manipulate[
 Graphics[{Black, Rectangle[{0, 0}, {5, 5}], 
 Dynamic[If[subID == "subA", Yellow, Cyan]], PointSize -> .05, 
 Dynamic@Point@pointSO[subID][[k]]}, ImageSize -> {400, 300}], 
Row[{Panel[
SetterBar[
Dynamic[subID, 
(subID = #; k = If[subID == "subA", j, i]) &],{"subA", "subB"}, 
 Appearance -> "Button", Background -> GrayLevel[.8]]], "      ", 
PaneSelector[{"subA" -> 
  Dynamic@Panel[
    SetterBar[Dynamic[j, (k = j; j = #) &], 
     Range[Length@pointSO["subA"]], Appearance -> "Button", 
     Background -> Yellow]], 
 "subB" -> 
  Dynamic@Panel[
    SetterBar[Dynamic[i, (k = i; i = #) &], 
     Range[Length@pointSO["subB"]], Appearance -> "Button", 
     Background -> Cyan]]}, Dynamic[subID]]}]]

输出示例:

数据集 subB

数据集 subA


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接