Group Abstract Group Abstract

Message Boards Message Boards

Drag the cursor to create a rectangle which is zoomed using EventHandler?

Posted 9 years ago

I would like to drag the cursor to create a rectangle which will then be zoomed to window size. As a start, I will be happy to drag a small disk from point to point. I have tried various ways involving DynamicModule[], EventHandler[], "MouseClicked", "MouseDragged", MousePosition[], Dynamic[], and PassEventsDown --> True, but my results are poor. I have even seen the code for this, but I lost it and can't reproduce it or find it. I have concluded that my understanding of EventHandler[] is wanting. Would someone be so kind as to discuss its parts, options, and requirements as they pertain to this problem. All the versions below make the dot disappear rather than move.

disk[pos_] := 
  Graphics[{Disk[pos, .1]}, PlotRange -> .5 {{-1, 1}, {-1, 1}}, 
   ImageSize -> 100, Background -> White];

(* 1 *)
DynamicModule[{pos = {0, 0}}, 
 EventHandler[
  disk[Dynamic @ pos], {"MouseClicked" :> ( pos = MousePosition[])}]]

(* 2 *)
DynamicModule[{pos = {0, 0}},
 EventHandler[
  disk[Dynamic @ 
    pos], {"MouseClicked" :> (pos = 
      pos /. {pos -> MousePosition[]})}]]

(* 3 *)
DynamicModule[{pos = {0, 0}}, 
 Dynamic @ 
  EventHandler[
   disk[ pos], {"MouseClicked" :> ( pos = MousePosition[])}]]

(* 4 *)
DynamicModule[{pos = {0, 0}},
 Dynamic @ EventHandler[
   disk[pos], {"MouseDragged" :> (pos = 
       pos /. {pos -> MousePosition[]})}, PassEventsDown -> True]]
POSTED BY: Gary Palmer
11 Replies
Posted 9 years ago

@Patrik, I don't know how I missed the icons right in front of my cursor. Preoccupied with code I guess. Thank you.

Your examples were helpful in navigating the quirky world of Dynamic[]. Here is an additional example. The first two are yours, rewritten to use different symbols because Dynamic preserves the symbol values even after clearing so one gets interactions. And my ["Global`*"] was overkill, so I just cleared the symbols. The third example has Dynamic[] applied to the z in ImageSize. It behaves much like your first example.

Clear[w, x, y, z];
x = 1;
{Dynamic[Slider[Dynamic[x], {0, 1}, ContinuousAction -> False, 
   ImageSize -> x*1000]], Dynamic[x]}

y = 1;
{Slider[Dynamic[y], {0, 1}, ContinuousAction -> False, 
  ImageSize -> y*1000], Dynamic[y]}

z = 1;
{Slider[Dynamic[z], {0, 1}, ContinuousAction -> False, 
  ImageSize -> Dynamic[z]*1000], Dynamic[z]]}

w = 1;
{Dynamic[Slider[w, {0, 1}, ContinuousAction -> False, 
   ImageSize -> w*1000]], Dynamic[w]}

If we use Dynamic[] only outside Slider[] as in the fourth example, the slider appears to work, but the Dynamic[w] after the Slider[] shows that w argument to Slider[] is not being updated. So it appears that no argument or option value inside Slider[] will update unless it is wrapped immediately in Dynamic[] or Slider itself is wrapped in Dynamic[]. Slider[] will just change it's appearance without updating values. This is different from controls in Manipulate, which updates control values without the explicit need for Dynamic[]. I believe one would still have to use Dynamic to update other varables within Manipulate.

Manipulate[
 Graphics[{Text[Style[x, 72], {0, 0}]}, Background -> White],
 {{x, 0}, 0, 1}]
POSTED BY: Gary Palmer
Posted 9 years ago

This page on the Mathematica StackExchange contains some 2016 code for the PlotExplorer which István Zachar began writing for Mathematica 9. The old code had problems, but this code seems to actually work.

http://mathematica.stackexchange.com/questions/94716/how-to-use-a-ready-function-in-your-code-for-panning-and-zooming-on-2d-plots/94759#94759

It really provides a variety of functions. To try it, cut and paste it and add this:

PlotExplorer@ ListLinePlot[Table[Accumulate[RandomReal[{-1, 1}, 250]], {3}], Filling -> Axis]

Some interesting demonstrations is here along with a 2015 version of the PlotExplorer. I was unable to make this version work in MMA 10.0.0, late 2009 iMac.

http://mathematica.stackexchange.com/questions/7142/how-to-manipulate-2d-plots

POSTED BY: Gary Palmer
Posted 9 years ago

Gary,

To the extent that I have tested it with the examples used by the developers of the code, It seems to work in my trial V11 (windows 10),

POSTED BY: E Martin
Posted 9 years ago

In the link you provide in your post above, István Zachar says

When it comes to visual analysis, large datasets or data with intricate internal details often makes plotting in 2 D useless, as the outcome is either just a fraction of the full dataset, or no details can be observed in the mess of datapoints.How can one make the process of changing the plot range and/or zooming, panning, etc.less tedious than doing it programmatically and iteratively, from time to time?I often meet with this issue, and developed various methods to deal with it (like this).Though I have now a working solution that I would like to share (see below), I also am highly interested in what kind of methods and tricks others invented to visualize and manipulate complex 2 D data with ease.

I fully agree with the remark, and have spent a lot of time struggling with the issue for years..

It seems that in Mathematica V9 WRI included an experimental function (PlotExplorer[]) that disappeared in versions 10 and 11.

Any comment will be welcome if anyone has made any successful use of the István Zachar' sPlotExplorercode published in the Mathematica StackExchange post linked by Gary,

POSTED BY: E Martin
Posted 9 years ago

@Patrik, Thank you for the nice explanation and added code.

But I find no difference in behavior in the following two items:

x = 1;
{Dynamic[Slider[Dynamic[x], {0, x}, ContinuousAction -> False]], 
 Dynamic[x]}

Clear["Global`*"];
x = 1;
{Slider[Dynamic[x], {0, x}, ContinuousAction -> False], Dynamic[x]} (* Initial Dynamic[] removed *)

By the way, how does one create a panel for code and quote in this forum? I see no help links on this page.

POSTED BY: Gary Palmer

@Gary

The first one resets it's max value each time you drop the slider.

Maybe this one is more obvious, where the slider width changes with values of x:

Clear["Global`*"]; 
x = 1; 
{Dynamic[Slider[Dynamic[x], {0, 1}, ContinuousAction -> False, ImageSize -> x*1000]], Dynamic[x]}

Versus this one where only the initial value is used and the slider isn't changed after evaluation (although the value of x is)

Clear["Global`*"]; 
x = 1; 
{Slider[Dynamic[x], {0, 1}, ContinuousAction -> False, ImageSize -> x*1000], Dynamic[x]}

Quotes have are preceded by an ">" sign.

Code snippets are preceded by a tab indentation.

Click on the icons at the top of the box where you write the messages. The left most one is for code, the right most one in the second column is for quotes.

POSTED BY: Patrik Ekenberg
POSTED BY: Patrik Ekenberg
Posted 9 years ago

@Patrik, That is what I was looking for. Thanks.

But what about the explanation? Let me pose a few questions:

  1. AutoAction is suppose to enable the controls to take action whenever the pointer is over them, even if they are not clicked. I suppose in this script, that must mean whenever the pointer is over the locator pane, which has the dimensions of PlotRange. Is that right? What is the role of AutoAction in this script? What action are the controls taking when the pointer is over the locator pane (as opposed to actually being clicked)?

  2. The documentation for AutoAction says that it is an option for controls such as Slider, Locator, and Button, yet you have written it as an option for LocatorPane[]. Is that because LocatorPane[] is also a control like Locator?

  3. Since you have Dynamic[pt2] inside LocatorPane[], what is the need for Dynamic[LocatorPane[]]? Or perhaps I should ask it the other way around.

  4. And how is it that one can reset with right click?

POSTED BY: Gary Palmer

Hi! What about something like this?

autoAction = False;
pt1 = {0, 0};
pt2 = {0, 0};
zoom = {{0, 4}, {-2, 2}};
graphics = {Thick, Green, Rectangle[{0, -1}, {2, 1}], Red, Disk[], 
   Blue, Circle[{2, 0}], Yellow, Polygon[{{2, 0}, {4, 1}, {4, -1}}], 
   Purple, Arrowheads[Large], Arrow[{{4, 3/2}, {0, 3/2}, {0, 0}}], 
   Black, Dashed, Line[{{-1, 0}, {4, 0}}]};
EventHandler[
 Dynamic[
  LocatorPane[Dynamic[pt2], 
   Graphics[{graphics, Directive[{LightOrange, Opacity[0.5]}], 
     Rectangle[pt1, pt2]}, PlotRange -> zoom], 
   AutoAction -> autoAction, Appearance -> None]], {
  {"MouseDown", 1} :> (autoAction = True; 
    pt1 = MousePosition["Graphics"];),
  {"MouseUp", 1} :> (autoAction = False;
    zoom = Transpose[{pt1, pt2}]; pt1 = {0, 0}; pt2 = {0, 0};),
  {"MouseClicked", 2} :> (zoom = {{0, 4}, {-2, 2}})}]

Click and drag to zoom in, right click to reset. Could be a start at least!

Regards, Patrik

POSTED BY: Patrik Ekenberg
Posted 9 years ago

@Gianlucca, We now have two such attempts. Thank you for making a try. Perhaps the traffic will inspire more experienced event handlers to jump in.

I noticed that you included "Graphics" as the argument to MousePosition[]. As I read the documentation on ?Graphics, this should yield the position of the cursor when it lies within the boundaries of the Graphics[], which perhaps means any position within the PlotRange rather than within the graphics objects (i.e. the rectangle or disk) that are the arguments of Graphics[]. I have not seen this explained. At least, when I include "Graphics", the behavior changes to provide what I was attempting. That is, the disk moves from point to point instead of disappearing. So that is a big improvement.

POSTED BY: Gary Palmer

A crude attempt, by a novice of EventHandler:

DynamicModule[{pos1 = {0, 0}, pos2 = {.1, .1}, pr = .5}, 
 EventHandler[
  Dynamic@Graphics[{Rectangle[pos1, pos2]}, PlotRange -> pr, 
    Frame -> True],
  {"MouseDown" :> (pos1 = MousePosition["Graphics"]), 
   "MouseUp" :> (pos2 = MousePosition["Graphics"]; 
     pr = Transpose[Map[Sort, {pos1, pos2}]])}]]
POSTED BY: Gianluca Gorni
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard