10
$\begingroup$

I'm trying to reproduce a variant of this view, where hovering the mouse over a point highlights its "corresponding" point on all plots:

Google Finance page for AAPL, with a volume chart and the "Slow Stochastic Oscillator"

In my case, the additional complexion is that the x-axes are not the same (i.e. they're not all time), though they do all increase monotonically.

I'm in the process of reading, experimenting, and further exploring based on comments on these threads:

However, I've yet to understand (though perhaps the answer may be in one of those threads) how one would affect a plot based on an event triggered on another plot. Any pointers would be greatly appreciated. I'll post my solution when I figure it out, though I'm sure it won't be the best one could do, as I'm still new to Mathematica.


After @ssch's answer was posted, I realized I left out some critical details/clarifications.

First, I'm working with discreet data, i.e. two ListPlots. That doesn't seem to matter, though. @ssch's example worked for me, using ListPlot.

Second, and more importantly, the two x-axes are not linear images—_i.e._they do not increase uniformly. For example:

Non-uniform example

The above plots graph the same y-axes, but based on different x-axes. (The dotted gray lines correspond, so one can see how certain areas are "stretched" or "compressed" in the second graph.)

Is there a way to get a corresponding cursor in such a case?

$\endgroup$
2
  • $\begingroup$ But still n-th point in first plot is referring to the n-th point in the second? $\endgroup$
    – Kuba
    Oct 21, 2013 at 6:33
  • $\begingroup$ I found my answer in another thread: mathematica.stackexchange.com/questions/34611/…. But I will post back here when I get it working with a hovering cursor. $\endgroup$ Oct 24, 2013 at 8:05

3 Answers 3

3
$\begingroup$

Using Scaled coordinates can be quite helpful:

DynamicModule[{
  loc = Scaled[{0.5, 0.5}]},
 Column[{
   Plot[
    x, {x, 1, 2},
    Epilog -> Dynamic[ Point[Scaled[{loc[[1, 1]], loc[[1, 1]]}]] ]],
   Plot[
    x^2, {x, -1, 2},
    Epilog -> Dynamic@Locator[Dynamic[loc]]]
   }]
 ]

some plots

See how the point in the first coordinates follows quite nicely even though their ranges are completely different.

You can of course use EventHandler with MousePosition, which supports "GraphicsScaled" coordinates, instead of a Locator.

$\endgroup$
2
  • $\begingroup$ Thanks for the starter, @ssch! Indeed, your example worked up to the point of getting a locator to correspond to a depicted point on another graph. I wasn't aware of DynamicModule's use in this way. However, I've edited my question to reflect a more involved aspect of my problem: my x-axes are not linear multiples of one another! Would you have any suggestion(s) as to how to approach this problem? Thank you. $\endgroup$ Oct 21, 2013 at 2:24
  • $\begingroup$ @acheong87 I'd start by defining an invertible mapping between the two plotranges and use that to transform the location data. $\endgroup$
    – ssch
    Oct 21, 2013 at 2:49
3
$\begingroup$
data = Table[{i, 5 Sin[i/10] + RandomReal[]}, {i, 100}];
data2 = {Log[#], #2} & @@@ data;

In case when you don't know how both axes are related to each other but only have point sets you can do something like:

Deploy@With[{opts = {Axes -> False, Frame -> True, ImageSize -> {300, 300/GoldenRatio}, 
             AspectRatio -> 1/GoldenRatio}},
 DynamicModule[{sel = 1, mark},
  Column[{
          Graphics[{[email protected], Dynamic@mark[data], 
                    Red, [email protected], Dynamic@Point[data[[sel]]]}, opts],
          Graphics[{[email protected], Dynamic@mark[data2], 
                    Red, [email protected], Dynamic@Point[data2[[sel]]]}, opts]
        }]
  , Initialization :> (
 mark[data_] := MapIndexed[Dynamic@{If[CurrentValue["MouseOver"], sel = First@#2];, 
                                       Point[#]} &, data];
  )]
]

enter image description here

$\endgroup$
8
  • $\begingroup$ I apologize I haven't had a chance to return to my project since the workweek began! I'll get to it later today, but this already looks like it's gonna do what I want. You guessed correctly that I have only point sets that map one-to-one, not a continuous function of any sort (though, I recall seeing an Interpolate function in Mathematica that might help with that). Can't wait to try this. (And I'll delete this otherwise frivolous comment.) $\endgroup$ Oct 22, 2013 at 14:09
  • $\begingroup$ @acheong87 I'm looking forward hearing how it fits your needs :) If any improvements need to be done, just tell me. Good luck. $\endgroup$
    – Kuba
    Oct 22, 2013 at 14:33
  • $\begingroup$ Your code, using 100 sample points, works. Unfortunately however, when I up the number of points to 6,300 (the typical size of my lists), Mathematica hangs at the "Formatting Notebook Contents" dialog, bringing up the "Disable Dynamic Evaluation" dialog every 10 seconds. Do you think perhaps the mouseover aspect consumes a lot of processing power? (I'm trying to remove that now, as I don't necessarily need hovering (clicking is sufficient). Or is it something else? $\endgroup$ Oct 23, 2013 at 2:13
  • $\begingroup$ @acheong87 hi, sorry for delay, could you tell more about the data? Is the sampling constant etc? or you want a solution for just two list with arbitrary points related with pairs? $\endgroup$
    – Kuba
    Oct 24, 2013 at 6:56
  • $\begingroup$ No problem! I should thank you. I learned a ton over the past two days, starting from your code, and trying to modify it in various ways to do the minimum processing necessary. I know I probably could have been clearer about my data, too; I apologize. Two days ago, I didn't see my data that way, but yes, you're right, I have two arbitrarily lists, say {{1,2},{3,4},{5,6},...} and {{10,20},{30,40},{50,60},...} and need corresponding pairs to be "related," e.g. {1,2} and {10,20}. However, while asking a sub-question on another thread, @belisarius provided yet another answer, which I $\endgroup$ Oct 24, 2013 at 7:03
0
$\begingroup$

@belisarius answered my question in another thread. The following is his code with one modification: replacing MouseDown with MouseMoved.

opts = {Axes -> False, Frame -> True, ImageSize -> {300, 200},  AspectRatio -> 1/GoldenRatio};
td1 = Table[{x, 5 Sin[x] + RandomReal[]}, {x, 1, 10, (10 - 1)/500}];
td2 = {Log[#], #2} & @@@ td1;
f = Nearest[td1 -> Automatic];
g = Nearest[td2 -> Automatic];
DynamicModule[{pt1 = {0, 0}, pt2 = {0, 0}, x1 = First@td1, x2 = First@td2},
 Row@{
   Deploy@EventHandler[Dynamic@
     Graphics[{Point@td1 , Red, PointSize[Large], Point[x1]}, opts, GridLines -> {{x1[[1]]}, {}}], 
     "MouseMoved" :> ({x1, x2} = {td1[[#]], td2[[#]]} &@ f[MousePosition["Graphics"], 1])],
   Deploy@EventHandler[Dynamic@
   Graphics[{Point@td2, Green,  PointSize[Large], Point[x2]}, opts ,GridLines -> {{x2[[1]]}, {}}], 
     "MouseMoved" :> ({x1, x2} = {td1[[#]], td2[[#]]} &@ g[MousePosition["Graphics"], 1])]
}]

I'm only copying the answer here for posterity, as a comment may be overlooked (especially as I plan to accept @Kuba's answer for the time being, as his led me in the right direction). I will delete this answer if @belisarius chooses to move his answer here.

$\endgroup$

Your Answer

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

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