dhale / jtk

The Mines Java Toolkit
http://inside.mines.edu/~dhale/jtk/
Apache License 2.0
83 stars 56 forks source link

Log Scale Option in TileAxis #17

Closed ericaddison closed 8 years ago

ericaddison commented 8 years ago

I have added an option to display a TileAxis with a logarithmic scale. This is done by calling the new setLogScale() method in TileAxis, which can be accessed for any axis through the Mosaic class. See the LogAxisPlotDemo class for an example.

The meat of this update is in the paintToRect() method in TileAxis, which now draws logarithmically spaced tic marks if a TileAxis is set with setLogScale(true). This overrides the behavior provided by AxisTics, which carefully determines how many linear tics to display, and simply displays nine tics for each decade (one major and eight minor tics).

It is assumed that the x1[] float array or sampling passed in a call to a plot method (e.g. addPoints) represents a range of exponents, not raw values, e.g. for a function defined on (10^a,10^b), the x1[] values passed to a plotting method should range from (a,b), not from (10^a,10^b). This is similar to the syntax for logspace(a,b,n) in MATLAB. This choice avoids the need for a lot of error checking for negative numbers in the range or issues with zero, placing that responsibility with the user.

This update only changes the axis tic painting ... no change to the data is made, so it's not like semilogx() or loglog() in MATLAB. This also places responsibility with the user to pass in appropriate data.

The following figure shows the result of setting two of the four TileAxis objects to display with a log scale.

image

dhale commented 8 years ago

We should choose between linear or log scales by specifying a property of the PointsView that displays our data.

Users of the proposed implementation of log scales must first make new transformed arrays of data, as in your demo program, before constructing a PointsView. Given the many ways we can view data in the Mines JTK, it would be confusing and error-prone that for log scales we must first transform our data before viewing.

The projection of data to either a linear or log scale should be handled by the graphical view, in this case PointsView. If you want to implement this feature in this way, I again recommend that you first study the code for the class edu.mines.jtk.mosaic.Projector and learn how other classes such as PointsView and TileAxis use it.

ericaddison commented 8 years ago

Ok, Dave. It sounds like you are suggesting that the log transformations should be handled internally, is that right? Would this kind of interface be what you have in mind?

float[] x = makeX();
float[] y = makeY();
PlotPanel plot = new PlotPanel();
plot.addPoints(x,y).setLogScaleX(true);   // set the x axis to log scale
dhale commented 8 years ago

Right, sort of like what happens with setOrientation, which causes a PointsView to update its best Projectors. We can change the view's orientation without altering the (x1, x2) data provided to the PointsView.

In this case, with methods like setHLogScale or setVLogScale, PointsView would construct a best Projector with a log scale (not yet supported), and such scales would be handled by TileAxis, PointsView, GridView, ....

Must also think about the impact on methods such as setHLimits, setHInterval, and others in PlotPanel, but this part seems easier.

dhale commented 8 years ago

Eric, do you know Chris Engelsma? He knows his way around the Mines JTK. Not sure if he watches these pull requests.

chrisengelsma commented 8 years ago

I think to be consistent with the other plotting parameters it might make more sense to have the methods as set[H/V]Scale(), each taking an enum: Scale.LINEAR, Scale.LOG, Scale.AUTO, etc, and this could be done on each View.

So,

    PointsView pv = new PointsView(f);
    pv.setHScale(PointsView.Scale.LOG);

I'm not sure if this would affect set[H/V]Limits or Set[H/V]Interval, but that's what some good ol' unit tests could find out

dhale commented 8 years ago

That's it.

ericaddison commented 8 years ago

Thanks for the ideas, guys. I'll keep playing with it.

ericaddison commented 8 years ago

Hi guys,

This is pretty much working, just need to iron out one or two more issues. One thing I'd like to do in the spirit of extensibility is to create an interface called AxisScalable and program against that. Initially I would just have PointsView implement this interface, but having it there would allow for simpler extension to other views in the future.

This seems to be a little inconsistent with the style of the Mosaic package (I don't see any other interfaces), so I wanted to run it by you before I threw it in.

Thanks!

@dhale @chrisengelsma

dhale commented 8 years ago

I can imagine the need for something like AxisScalable, sort of like ColorMapped, but the changes you have made so far seem to be headed in a direction different from what Chris and I discussed above. For example, you have made no changes (yet) to classes PointsView or Projector.

TileAxis must of course know the type of projection, but it should get this information from a Projector. To support log scales, Projector should support more than one type (linear, log, ...) of projection. A Projector today reconciles (merges) the best Projectors provided by each TiledView, such as PointsView. Each TileAxis uses a Projector provided by an adjacent Tile to draw appropriate tics and labels. The word "uses" here is important. A TileAxis need/should not maintain any properties that would alter the projection. One reason for this is that a Mosaic may contain Tiles without TileAxes.

ericaddison commented 8 years ago

I've been working in PointsView and Projector like you suggested, I just haven't incorporated those changes with the pull request yet. I guess I'll get those up here!

ericaddison commented 8 years ago

Closing to create pull request for new branch.