Mathematica dynamic to plot matrix data

青春壹個敷衍的年華 提交于 2020-01-02 04:44:47

问题


I am trying to dynamically plot data contained in a matrix with Mathematica 7. The data is contained in it like this, obtained via a chemical model.

[year  H    He     Li     C     ...  C8H14+,Grain- ]
[0     0    0.03   0.009  1E-3  ...  0             ]
[100   .1   0.03   0.009  1E-3  ...  0             ]
[200   .2   0.03   0.009  1E-3  ...  0             ]
[300   .2   0.03   0.009  1E-3  ...  0             ]
[...   ...  ...   ...     ...   ...  ...           ]
[1E6   .5   0.03   0.003  1E-8  ...  1E-25         ]

The truth is, the matrix dimensions are 2001*1476 (2000 steps and first line for name, and 1475 compounds + 1 column for year), very heavy. I am trying to plot any compound with a concentration / year plot. This works

Manipulate[
  ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]] ], 
  {{i, 2, "Compound"}, 2, compounds, 1}
]

where data is the matrix, and compounds a variable set at the number of modelized compounds (1475 here). "compound" is a label for the slider. The problem is, the slider moves much to fast as a few centimeters browse through 1400+ items. I tried to do a drop-down menu with

MenuView[
  Table[
    ListLogLogPlot[data[[All, {1, i}]],PlotLabel -> data[[1, i]]], {i, 2, compounds}
  ]
]

It also works, but this is a processor killer process (10+ minutes on a Xeon 16-core server executing 16 kernels), as Mathematica try to graph all plots before displaying any of them. Also the drop-down has no name, just a series of numbers (1 for hydrogen to 1475 for C8H14N+,Grain-), even though the plot has a name.

What I am searching a way to plot a graph only on demand, with a name display in the drop-down list (and if required H by default). OR a field where I can enter the name of the compound. This seems to be possible with Dynamic[ ] command, but I don't manage to make it work properly.

Thanks


回答1:


Mike's suggestion is a good one but if you don't want to go to the effort of putting it in a database, use the ContinuousAction->False option.

testdata = 
  Join[{Table[ToString[series[i-1]], {i, 1475}]}, 
   RandomReal[{1., 100.}, {2000, 1476}]];

Manipulate[
 ListLogLogPlot[testdata[[All, {1, i}]], 
  PlotLabel -> testdata[[1, i]]], {{i, 2, "Compound"}, 2, 1475, 1}, 
 ContinuousAction -> False]

To get a popup menu, use the {i,listofvalues} syntax for the controller specification.

Manipulate[
 ListLogLogPlot[testdata[[All, {1, i}]], 
  PlotLabel -> testdata[[1, i]]], {i, Range[2, 1475]}, 
 ContinuousAction -> False]

This works pretty fast on my system. (Two year old MacBook Pro)

A fancier version:

spec = Thread[Range[2, 1476] -> Table[ToString[series[i]], {i, 1475}]];

Manipulate[
 ListLogLogPlot[testdata[[All, {1, i}]], 
  PlotLabel -> testdata[[1, i]]], {{i, 2, "Compound"}, spec}, 
 ContinuousAction -> False]

And if all you want to do is step through the images, click on the little plus next to a slider controller to get more detailed controls.




回答2:


For entering names in an InputField, you could do something like

compounds = Rest[data[[1]]];
Manipulate[
 If[MemberQ[compounds, compound], i = Position[compounds, compound][[1, 1]] + 1];
 ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]]],
 {{i, 2}, None},
 {{compound, data[[1, 2]], "Compound"}, InputField[#, String] &}]

Here, compounds is a list of all the names of the compounds. The If statement in Manipulate is to check whether the name entered in the InputField is a valid compound or not.

Others have already given you ways to create one big popup list. If you don't want to scroll through a popup list of 1475 compounds, you could consider splitting the popup list into sublists. For example, this would split the whole list of compounds into sublists of n=50 elements which might make it easier to navigate

compounds = Rest[data[[1]]];
With[{n = 50},
 Manipulate[
  i = 1 + Position[compounds, name][[1, 1]];
  ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]]],
  {{i, 2}, None},
  {{indexlist, 1, "Indices"},
   Table[i -> ToString[(i - 1) n + 1] <> " through " <> 
     ToString[Min[i n, Length[compounds]]], 
    {i, Ceiling[Length[compounds]/n]}], PopupMenu},
  {{name, compounds[[1]], "Compound"}, 
   compounds[[n (indexlist - 1) + 1 ;; 
      Min[Length[compounds], n indexlist]]], PopupMenu}
 ]
]

For example, for

data = Table[Join[{i}, RandomReal[{0, 1}, 1000]], {i, 1000}];
data = Join[{Prepend[Table["list " <> ToString[i], {i, 1000}], "year"]}, data];

this looks like




回答3:


For data sets of this size I'd recommend (as optimal) storing it all in a database and using DatabaseLink to call stuff as required. Then link your controllers, such as popup menus, to SQLExecute code or other SQL functions. Fragments like this would be the sort of thing that would do the job:

DynamicModule[{x,data, ...},

Column[{

PopupMenu[Dynamic[x], {1 -> "category 1", 2 -> "category 2", 3 -> "category 3", ...}],

Dynamic[

data = SQLExecute[conn, "SELECT * FROM myDatabase.table WHERE my_id = `1`;", {x}];
ListLogLogPlot[data]
]

}]
]

In reality you may want to be adding additional popups and doing joins and so on.

EDIT

Alternative that doesn't use databases but uses input fields as requested:

DynamicModule[{x = "He", rules, y},

 rules = Rule @@@ Transpose[{data[[1, All]], Range[Length[data[[1, All]]]]}];

 Column[{
   InputField[Dynamic[x], String],

   Dynamic[
    y = x /. rules;
    ListLogLogPlot[data[[All, {1, y}]], PlotLabel -> data[[1, y]]]
    ]

   }]
 ]

For rules lists of this size you'd probably want to use Dispatch I'd imagine. See how the timing goes for that. It looks like this is some sort of experiment you are running so my first choice remains dumping it into a DB.

FURTHER EDIT

If you're relying on input fields then you will need to account for clumsy typing by inserting a conditional so that Mma only attempts to plot if y is an integer.

If[IntegerQ[y],
ListLogLogPlot,
Spacer[0]
]


来源:https://stackoverflow.com/questions/8487586/mathematica-dynamic-to-plot-matrix-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!