4
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ Are you perhaps trying to do something similar to my answer here? $\endgroup$
    – Jens
    Mar 27, 2013 at 15:47

2 Answers 2

4
$\begingroup$

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"}}]
$\endgroup$
9
  • $\begingroup$ 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! $\endgroup$
    – Sulli
    Mar 27, 2013 at 17:32
  • $\begingroup$ 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! $\endgroup$ Mar 27, 2013 at 17:43
  • $\begingroup$ 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...)? $\endgroup$
    – Sulli
    Mar 28, 2013 at 11:18
  • $\begingroup$ @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? $\endgroup$ Mar 28, 2013 at 12:21
  • $\begingroup$ 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. $\endgroup$
    – Sulli
    Mar 28, 2013 at 12:43
3
$\begingroup$

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.

$\endgroup$
2
  • $\begingroup$ 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! $\endgroup$
    – Sulli
    Mar 27, 2013 at 17:34
  • $\begingroup$ @su1 You should vote for all answers that you find helpful. Note that you can also vote for the answer you Accept (check mark). $\endgroup$
    – Mr.Wizard
    Mar 27, 2013 at 17:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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