imagej / imagej/imagej-common

Support general text specified axis class

Open
#39 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
12
Forks
15
PR merge metrics
No merged PRs in 30d

Description

There are good reasons to support one kind of axis that has its equation defined by a string. I have mocked up a class below. This is not a simple endeavor but would eliminate a lot of (sometimes redundant) concrete `CalibratedAxis` implementations. See notes in code below for pointers.

``` java
package net.imglib2.meta.axis;

import net.imglib2.meta.AxisType;

/**
* A very general text driven axis class.
*
* @author Barry DeZonia
*/
public class UberAsciiAxis extends VariableAxis {

// I might be getting carried away but think it would be nice to define axes
// by equation alone. IJ1 has lots of one off definitions in CurveFitter that
// have offsets or not or powers or not. I've generalized some of this by
// always having an offset that can be 0. But really we'd like the flexibility
// of not needing a new concrete axis class every time someone comes up with a
// new formula. This class would parse the equation and build an appropriate
// function that can scale coords as needed. The nice thing here is that the
// parsed axis can be queried for variables and then a curve fitting algo can
// determine appropriate variable values. Curtis' idea of the EditAxes plugin
// directly tweaking the variables of a displayed equation is correct. There
// remains the trick of determining when an axis is linear. This can be done
// by testing that an axis.equals(some general linear axis string) as noted
// below.

// TODO - bad name: Equation is more general than our 1d case

private interface Equation {

// This might be involved to determine but it would be fun to write!
Equation inverse(); // if doesn't exist we will return a NullEquation

double eval(double input);

// TODO - maybe one String method rather than two.

String generalEquation();

String particularEquation(); // likely in an abstract class
}

// equation string can be things like:
// y = m*x + b
// y = 74*x + b
// y = q*sin(slope*x+19.4)^(33*power)+fred (here only x & y are predefined)
// constants and vars automatically detected

private final String equationString;
private final Equation eqn;
private final Equation eqnInverse;

public UberAsciiAxis(AxisType type, String unit, String equationString) {
super(type, unit);
this.eqn = parse(equationString);
this.eqnInverse = eqn.inverse();
this.equationString = equationString;
}

public UberAsciiAxis(AxisType type, String unit, Equation equation) {
super(type, unit);
this.eqn = equation;
this.eqnInverse = eqn.inverse();
this.equationString = equation.generalEquation(); // or particular?
}

@Override
public double calibratedValue(double rawValue) {
return eqn.eval(rawValue);
}

@Override
public double rawValue(double calibratedValue) {
return eqnInverse.eval(calibratedValue);
}

@Override
public String generalEquation() {
return equationString;
}

@Override
public UberAsciiAxis copy() {
return new UberAsciiAxis(type(), unit(), equationString);
}

@Override
public boolean equals(Object o) {
if (!(o instanceof UberAsciiAxis)) return false;
UberAsciiAxis other = (UberAsciiAxis) o;

// TODO: do something really cool. compare syntax trees and variables of the
// two UberAxes. Even trickier: detect when vars of two eqns are the same
// due to coeffs being 1 or 0. For example y = 1*x + 0 is same as y = x
// though they would have different syntax trees.

// TEMP: only equal to self
return other == this;
}

// For generality and reuse elsewhere maybe make parser return multidim
// equation. We'd need to test that it has a single dim of input to qualify as
// a valid axis equation

private Equation parse(String equationString) {
// TODO
return new NullEquation();
}

// return one of these as an Equation::inverse() when it is not invertible

private class NullEquation implements Equation {

@Override
public double eval(double input) {
return Double.NaN;
}

@Override
public Equation inverse() {
return this;
}

@Override
public String generalEquation() {
return "y = NaN";
}

@Override
public String particularEquation() {
return "y = NaN";
}

}
}
```

Migrated-From: http://trac.imagej.net/ticket/2012

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing VariableAxis and existing CalibratedAxis implementations, then examine the proposed UberAsciiAxis API and its Equation, parsing, and inverse-evaluation responsibilities. Done means a general text-defined axis can be constructed, calibrated and inverted where supported, copied, and represented by its equation, with behavior validated by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
data
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.