Re: Interactive Scatter Plots...

Hi Barry,

Really great questions.  VisAD provides a variety of
tools to help you do these tasks without getting into
screen coordinates.  The primary tools are VisAD's
direct manipulation DataRenderers.  When you connect
a Data object to a DisplayImpl by a call to the
addReferencesDataRenderer renderer, DataReference ref)
method of DisplayImpl, renderer may be one of the
DataRenderers that support direct manipulation.  This
means that users can change data values by redrawing
their depictions.  Thus mouse movements in screen
coordinates are translated back into data coordinates.

> The desired behaviors are:
> 1. For sample point picking, user clicks in plot area, and the sample point
> that is "closest" (in terms of euclidean distance in x-y screen coordinates)
> is highlighted, and a programmatic event is issued with the identity of that
> sample available.

The easiest way to do this is using
visad/bom/PickManipulationRendererJ3D.java.  This is a
direct manipulation DataRenderer that doesn't actually
change Data values, but just generates ThingChangedEvents
on their DataReferences so you can connect them to
CellImpl's whose doAction() methods get triggered when
the user clicks on the Data object's depiction.  This
will require you to create a seperate Data object,
DataReference and CellImpl for each sample point.  But
that shouldn't be a problem unless you have many thousands
of sample points.  In that case, you can still do what you
want by writing a new direct manipulation DataRenderer for
that purpose (if you decide to write your own, please feel
free to get help from me).  Note that picking is done by
clicking the right mouse button.

See the main() method of PickManipulationRendererJ3D.java
for an example of how to use it.

> 2. For sample group picking, user clicks in plot area, drags the cursor in a
> path that creates a closed loop and releases the mouse button.  Then sample
> points "inside" the loop (in terms of x-y screen coordinates) are
> highlighted, and a programmatic event is issued with the identities of those
> samples available.

The visad/bom/CurveManipulationRendererJ3D.java class
and the inside() method of visad/DelaunayCustom.java
give you a way to do this.  See
visad/bom/CollectiveBarbManipulation.java for an
example of how this is used.  Specifically in its
main() method see the code:

    Gridded2DSet set1
      new Gridded2DSet(earth, new float[][] {{0.0f}, {0.0f}}, 1);
    Gridded2DSet[] sets = {set1};
    UnionSet set = new UnionSet(earth, sets);

    final DataReferenceImpl set_ref = new DataReferenceImpl("set_ref");
    set_ref.setData(set);
    int mask = InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK;
    display1.addReferences(new CurveManipulationRendererJ3D(mask, mask, true),
                           set_ref);

You would probably use mask = 0, meaning that the user does not
need to hold down the SHIFT or CTRL keys to draw a curve.  The
"true" means that only one curve exists at a time.  Note that
curves are drawn by holding down the right mouse button.  You
can also construct a DisplayListener and pass it to
display.addDisplayListener().  Then in its displayChanged()
method look for DisplayEvents whose getId() =
DisplayEvent.MOUSE_RELEASED_RIGHT.  When you find one, apply
modified code from CollectiveBarbManipulation.cell2:

    UnionSet cset = (UnionSet) set_ref.getData();
    SampledSet[] csets = cset.getSets();
    if (csets.length > 0) {
      float[][] samples = csets[csets.length - 1].getSamples();
      if (samples != null && samples[0].length > 2) {
        for .. // loop over sample points (x, y)
        if (DelaunayCustom.inside(samples, x, y)) {
          // (x, y) is inside curve
        }
      }
    }

Note that x and y are values of the RealTypes mapped to
XAxis and YAxis, rather than screen coordinates.

> I know how to do the algorithmic parts of these behaviors... but how do I:
> A. Get the screen coordinates of a mouse click in this object
> B. Get the screen coordinates of all the data samples (to compare to the
> mouseclick)
> C. Highlight/unhighlight a sample point(s) (use a different color/circle it)
> D. Accumulate the list of screen coodinates generated during the drag

I think A, B & D are unnecessary if you use
PickManipulationRendererJ3D and
CurveManipulationRendererJ3D.  You can do C by
another addReference() call for the selected Data
point, and passing a ConstantMap[] array for a
special values of Red, Green, Blue, and maybe
PointSize (to make a large point).  Or you can
construct a special derived RealTuple data object
whose RealTypes include one mapped to Shape, if
you want to get fancy with circles etc.

>    I am guessing/hoping that tasks A&D may be done without interference with
> other callbacks, by doing the normal addMouseListener &
> addMouseMotionListener with my own MouseInputAdapter & MouseMotionAdapter.
> Is that so?  If "event crosstalk" might be a problem, is it possible to put
> the object into a "select sample mode" temporarily, removing the existing
> mouse listeners, add our listeners, use them, and then restore the "default
> mode" by swapping the listeners back again?  How would I access the default
> listeners?

Save yourself a lot of trouble and skip all this
stuff.  Note that there are a number of direct
manipulation DataRenderers in visad/bom,
visad/java3d and visad/java2d.  And over time
there will be lots more of them.

Cheers,
Bill
----------------------------------------------------------
Bill Hibbard, SSEC, 1225 W. Dayton St., Madison, WI  53706
hibbard@xxxxxxxxxxxxxxxxx  608-263-4427  fax: 608-263-6738
http://www.ssec.wisc.edu/~billh/vis.html