Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm able to plot two lists with a tooltip on the curves to display the name of the curve:

list1 = {{{0, 1}, {1, 2}, {2, 4}}, {{0, 3}, {1, 1}, {2, 5}}};
names = {"curve1", "curve2"};
ListLinePlot[Table[Tooltip[list1[[i]], names[[i]]], {i, Length[list1]}]]

enter image description here

Now I would like to evaluate this action when I click on a curve:

Manipulate[dummyFunction[nameOfTheCurve, variable], {variable , {0, 1}}]

with dummyFunction being

dummyFunction[t_, u_] := If[u == 1,
  Graphics[{Green, Disk[], Black, Text[t]}],
  Graphics[{Red, Disk[], Black, Text[t]}]
]

and nameOfTheCurve being the name of the clicked curve.

I've tried

ListLinePlot[Table[Button[list1[[i]], Manipulate[dummyFunction[names[[i]], variable], {variable , {0, 1}}]], {i,Length[list1]}]]

but this doesn't work (I can't click on the curve). What's the correct syntax? And more precisely, I would like to plot the output of dummyFunction (the Disk) under the first graph, not replacing it.

share|improve this question
    
Are you perhaps trying to do something similar to my answer here? –  Jens Mar 27 '13 at 15:47
add comment

2 Answers

up vote 3 down vote accepted

This is the simplest version of what you want. The Manipulate objects are printed right under the plot.

list1 = {{{0, 1}, {1, 2}, {2, 4}}, {{0, 3}, {1, 1}, {2, 5}}};
names = {"curve1", "curve2"};
dummyFunction[t_, u_] := Graphics[{If[u == 1, Green, Red], Disk[], Black, Text[t]}];

ListLinePlot[MapThread[
  Tooltip[EventHandler[#, {"MouseClicked" :> 
       CellPrint[Manipulate[dummyFunction[#2, 
          variable], {variable, {0, 1}}]]}], #2] &, {list1, names}]]

It has the issue that every time a curve is clicked, a new Manipulate is printed. To overcome this problem and only show one of the Manipulates at a time, introduce an extra switch (show) that records whichever curve was clicked, and a variable that stores the actual Manipulate (menu).

list1 = {{{0, 1}, {1, 2}, {2, 4}}, {{0, 3}, {1, 1}, {2, 5}}};
names = {"curve1", "curve2"};
show = 0;
menu = Spacer@0;
dummyFunction[t_, u_] := Graphics[{If[u == 1, Green, Red], Disk[], Black, Text[t]}];

Column@{
  ListLinePlot[
   MapThread[
    Tooltip[EventHandler[#1, {"MouseClicked" :> 
         If[show =!= #3, show = #3; 
          menu = Manipulate[dummyFunction[#2, variable], {variable, {0, 1}}], 
          show = 0; menu = Spacer@0]}], #2] &, {list1, names, 
     Range@Length@names}]],
  Dynamic@menu}

Even more convenient is the following setup where the appearing menu is directly inserted in ListLinePlot result:

list1 = {{{0, 1}, {1, 2}, {2, 4}}, {{0, 3}, {1, 1}, {2, 5}}};
names = {"curve1", "curve2"};
selected = None;
dummyFunction[t_, u_] := Graphics[{If[u == 1, Green, Red], Disk[],
        Black, Style[Text[t], 14]}, ImageSize -> 40]

Dynamic[ListLinePlot[MapThread[EventHandler[#2,
     "MouseDown" :> (
       menuPos = MousePosition["Graphics"]; 
       selected = #1;
       menu = Grid[{{
           Manipulate[dummyFunction[names[[#1]], x], {x, {0, 1}}],
           Button["X", selected = None; menu = Spacer@0, ImageSize -> {20, 20}]
           }}, Spacings -> 0, Alignment -> Top]),
     PassEventsDown -> False, PassEventsUp -> False] &,
   {Range@Length@list1, list1}],
  PlotStyle -> {{Thick, If[selected === 1, Dashed, {}], Red}, {Thick, 
     If[selected === 2, Dashed, {}], Blue}}, ImageSize -> 400, 
  Epilog -> If[selected =!= None, Inset[menu, menuPos], {}]], 
 TrackedSymbols :> {menuPos, selected, menu}]

enter image description here

Edit

The second approach, in its package-ready function form:

f[list_, names_] := DynamicModule[{show = 0, menu = Spacer@0, dummy},
   dummy[t_, u_] := 
    Graphics[{If[u == 1, Green, Red], Disk[], Black, Text@t}, 
     ImageSize -> 60];
   Column@{ListLinePlot[
      MapThread[
       Tooltip[EventHandler[#1, {"MouseClicked" :> If[show =!= #3,
             show = #3; 
             menu = Manipulate[
               dummy[#2, variable], {variable, {0, 1}}],
             show = 0; menu = Spacer@0
             ]}], #2] &, {list, names, Range@Length@names}]], 
     Dynamic@menu}
   ];

list = {{{0, 1}, {1, 2}, {2, 4}}, {{0, 3}, {1, 1}, {2, 5}}};
names = {"curve1", "curve2"};
Manipulate[f[list, names], {t, {"a", "b"}}]
share|improve this answer
    
Fantastic exactly what I wanted! There are a few functions I don't know so I have to take the time to read about that, and also I would need to generalize it to the case where I not only have two curves but a changing number n. Other than this it works great! –  su1 Mar 27 '13 at 17:32
    
My examples are fairly general, I only left the final Epilog part to be converted to a Table or Map, as an exercise. Thanks for the accept, though mind that it is generally more rewarding to wait a few days before accepting an answer so that other, even better solutions could appear! –  István Zachar Mar 27 '13 at 17:43
    
I tried to implement your second piece of code inside another custom function of mine, but for some reason nothing happens when I click on a curve. Even a simple x = Graphics[Circle[]] will not get plotted, but I can see with a Print[] that I reach this line. I know it's a vague question and I'm still trying to figure out what prevents the second plot to be plotted, but are there general reasons why this could happen (embedded Manipulate functions, graphs with fixed size...)? –  su1 Mar 28 '13 at 11:18
    
@su1 I made an error (corrected now) by initially setting x instead of menu, which is the correct dynamic variable. Could you please check whether it still does not work? –  István Zachar Mar 28 '13 at 12:21
    
Yes I was using another variable name so this is not the problem. I think the problem comes from a bad interaction of this piece of code with other functions I'm using around, but there are many so I can't paste everything. It's probably something very simple but I've been working on this for hours now. –  su1 Mar 28 '13 at 12:43
show 4 more comments

I doubt that this is really all you want, but not knowing any details I'll just answer the specific question how to get a Manipulate to run based on a click, and then have the output appear in the plot. If you want the outputs from several clicks to accumulate, you could adapt this in combination with the AppendTo method in this answer. You say the disk is supposed to appear below line 1, so I'm assuming it's not dynamically movable (again, look at my linked answer if you do want that).

With[
 {placedPosition = {1.6, 2}, objectSize = .5},
 DynamicModule[
  {
   object = Graphics[{}]
   },
  ListLinePlot[
   Table[
    PopupWindow[list1[[i]],
     With[{nameTemplate = names[[i]]},
      Manipulate[
       object = 
        dummyFunction[nameTemplate, variable], {variable, {0, 1}}]
      ]
     ],
    {i, Length[list1]}],
   Epilog -> 
    Dynamic[Inset[object, placedPosition, Automatic, objectSize]]
   ]
  ]
 ]

manipulate

I decided to implement your Manipulate inside a PopupWindow so it's independent of the plot in which you clicked.

I may have misunderstood what you mean by "under the first graph": my interpretation was that it is placed in the same plot. If you want it to be spaced further down then just create extra space with ImageMargins, and change the coordinate in placedPosition accordingly. The variable objectSize is the relative size of the disk in the parent plot.

share|improve this answer
    
By "under the first graph" I meant in a separate graph under this one, like in Istvan Zachar's answer. I'd rather not use a Popup, but thanks, you answer was helpful too! –  su1 Mar 27 '13 at 17:34
    
@su1 You should vote for all answers that you find helpful. Note that you can also vote for the answer you Accept (check mark). –  Mr.Wizard Mar 27 '13 at 17:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.