Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/src/org/labkey/api/data/JsonWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ public static Map<String, Object> getMetaData(DisplayColumn dc, FieldKey fieldKe

props.put("wrappedColumnName", cinfo == null ? null : cinfo.getWrappedColumnName());
props.put("valueExpression", cinfo == null ? null : cinfo.getValueExpression());
props.put("displayWidth", cinfo == null ? null : cinfo.getDisplayWidth());

ColumnInfo displayField = dc.getDisplayColumnInfo();
if (displayField != null && displayField != cinfo)
Expand Down
30 changes: 21 additions & 9 deletions api/src/org/labkey/api/data/statistics/StatsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import org.jetbrains.annotations.Nullable;
import org.labkey.api.services.ServiceRegistry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
* Created by klum on 1/14/14.
Expand All @@ -38,22 +40,27 @@ static void setInstance(StatsService impl)

enum CurveFitType
{
THREE_PARAMETER("Three Parameter", "3pl"),
FOUR_PARAMETER("Four Parameter", "4pl"),
FIVE_PARAMETER("Five Parameter", "5pl"),
THREE_PARAMETER_ALT("3 Parameter", "3param"),
FOUR_PARAMETER_SIMPLEX("4 Parameter", "4param"),
POLYNOMIAL("Polynomial", "poly"),
LINEAR("Linear", "linear"),
NONE("None", "none");
// TODO see updated labels for these equations in genericChartHelper.js TRENDLINE_OPTIONS
// we should update the labels here as well at some point (but this would like need to include an upgrade script for saved chart configs)
THREE_PARAMETER("Three Parameter", "3pl", Arrays.asList("min", "max", "inflection")),
FOUR_PARAMETER("Four Parameter", "4pl", Arrays.asList("min", "max", "slope", "inflection")),
FIVE_PARAMETER("Five Parameter", "5pl", Arrays.asList("min", "max", "slope", "inflection", "asymmetry")),
THREE_PARAMETER_ALT("3 Parameter", "3param", Arrays.asList("min", "max", "inflection")),
FOUR_PARAMETER_SIMPLEX("4 Parameter", "4param", Arrays.asList("min", "max", "slope", "inflection")),
FIVE_PARAMETER_ALT("5 Parameter", "5param", Arrays.asList("min", "max", "slope", "inflection", "asymmetry")),
POLYNOMIAL("Polynomial", "poly", Arrays.asList("coefficients")),
LINEAR("Linear", "linear", Arrays.asList("slope", "intercept")),
NONE("None", "none", Arrays.asList());

private final String _label;
private final String _colSuffix;
private final List<String> _parameterNames = new ArrayList<>();

CurveFitType(String label, String colSuffix)
CurveFitType(String label, String colSuffix, List<String> parameterNames)
{
_label = label;
_colSuffix = colSuffix;
_parameterNames.addAll(parameterNames);
}

// Consider : moving the col suffix portion of this back into assays...
Expand All @@ -68,6 +75,11 @@ public String getLabel()
return _label;
}

public List<String> getParameterNames()
{
return _parameterNames;
}

@Override
public String toString()
{
Expand Down
41 changes: 41 additions & 0 deletions core/src/org/labkey/core/statistics/FiveParameterCurveFit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.labkey.core.statistics;

import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.statistics.DoublePoint;

import static org.labkey.api.data.statistics.StatsService.CurveFitType.FIVE_PARAMETER_ALT;

/*
* Equation: Asymmetrical Sigmoidal, 5PL (aka Richards five-parameter dose-response curve)
* Y = Bottom + (Numerator/Denominator)
* Numerator = Top - Bottom
* Denominator = (1+(2^(1/S)-1)*((EC50/X)^HillSlope))^S
*/
public class FiveParameterCurveFit extends ParameterCurveFit
{
public FiveParameterCurveFit(DoublePoint[] data, @Nullable Double asymptoteMin, @Nullable Double asymptoteMax)
{
super(data, FIVE_PARAMETER_ALT, asymptoteMin, asymptoteMax);
}

@Override
public double solveForX(double y)
{
throw new UnsupportedOperationException("Not implemented");
}

@Override
public double fitCurve(double x, SigmoidalParameters params)
{
if (params != null)
{
double topMinusBottom = params.getMax() - params.getMin();
double exponent = 1.0 / params.getAsymmetry();
double base = Math.pow(2.0, exponent) - 1.0;
double ec50OverXPowerHillSlope = Math.pow(params.getInflection() / x, params.getSlope());
double denominator = Math.pow(1.0 + (base * ec50OverXPowerHillSlope), params.getAsymmetry());
return params.getMin() + (topMinusBottom / denominator);
}
throw new IllegalArgumentException("No curve fit parameters for " + _fitType.name());
}
}
3 changes: 2 additions & 1 deletion core/src/org/labkey/core/statistics/ParameterCurveFit.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public double adjustedRSquared(SigmoidalParameters parameters)
{
case THREE_PARAMETER, THREE_PARAMETER_ALT -> adjustedRSquared(parameters, 3);
case FOUR_PARAMETER -> adjustedRSquared(parameters, 4);
case FIVE_PARAMETER -> adjustedRSquared(parameters, 5);
case FIVE_PARAMETER, FIVE_PARAMETER_ALT -> adjustedRSquared(parameters, 5);
default -> throw new IllegalStateException("Unsupported curve fit type: " + _fitType.name());
};
}
Expand Down Expand Up @@ -276,6 +276,7 @@ protected SigmoidalParameters calculateFitParameters(double minValue, double max
switch (_fitType)
{
case FIVE_PARAMETER:
case FIVE_PARAMETER_ALT:
for (double asymmetryFactor = 0; asymmetryFactor < Math.PI; asymmetryFactor += Math.PI / 30)
{
parameters.asymmetry = asymmetryFactor;
Expand Down
28 changes: 25 additions & 3 deletions core/src/org/labkey/core/statistics/StatsServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public CurveFit getCurveFit(CurveFitType type, DoublePoint[] data, @Nullable Dou
return new ThreeParameterCurveFit(data, asymptoteMax);
case FOUR_PARAMETER_SIMPLEX:
return new FourParameterSimplex(data);
case FIVE_PARAMETER_ALT:
return new FiveParameterCurveFit(data, asymptoteMin, asymptoteMax);
case THREE_PARAMETER:
return new ParameterCurveFit(data, type, 0.0, asymptoteMax);
case FOUR_PARAMETER:
Expand Down Expand Up @@ -133,6 +135,7 @@ public void TestCurveFits() throws Exception
v1.setResults(CurveFitType.THREE_PARAMETER, new CurveResults(3.09, .065, .065));
v1.setResults(CurveFitType.THREE_PARAMETER_ALT, new CurveResults(3.09, .065, .065));
v1.setResults(CurveFitType.FOUR_PARAMETER, new CurveResults(2.5, .031, .045));
v1.setResults(CurveFitType.FIVE_PARAMETER_ALT, new CurveResults(2.08, .046, .054));
v1.setResults(CurveFitType.FIVE_PARAMETER, new CurveResults(2.2, .046, .054));
v1.setResults(CurveFitType.LINEAR, new CurveResults(6.8, .070, .070));
validations.add(v1);
Expand All @@ -143,6 +146,7 @@ public void TestCurveFits() throws Exception
v2.setResults(CurveFitType.THREE_PARAMETER, new CurveResults(2.93, .414, .414));
v2.setResults(CurveFitType.THREE_PARAMETER_ALT, new CurveResults(2.93, .414, .414));
v2.setResults(CurveFitType.FOUR_PARAMETER, new CurveResults(3.4, .403, .403));
v2.setResults(CurveFitType.FIVE_PARAMETER_ALT, new CurveResults(2.44, .420, .420));
v2.setResults(CurveFitType.FIVE_PARAMETER, new CurveResults(3.1, .420, .420));
v2.setResults(CurveFitType.LINEAR, new CurveResults(36.8, .553, .553));
validations.add(v2);
Expand All @@ -153,6 +157,7 @@ public void TestCurveFits() throws Exception
v3.setResults(CurveFitType.THREE_PARAMETER, new CurveResults(5.0, .078, .078));
v3.setResults(CurveFitType.THREE_PARAMETER_ALT, new CurveResults(5.0, .078, .078));
v3.setResults(CurveFitType.FOUR_PARAMETER, new CurveResults(4.7, .048, .049));
v3.setResults(CurveFitType.FIVE_PARAMETER_ALT, new CurveResults(4.6, .049, .051));
v3.setResults(CurveFitType.FIVE_PARAMETER, new CurveResults(4.6, .080, .082));
v3.setResults(CurveFitType.LINEAR, new CurveResults(5.9, .070, .070));
validations.add(v3);
Expand All @@ -163,6 +168,7 @@ public void TestCurveFits() throws Exception
v4.setResults(CurveFitType.THREE_PARAMETER, new CurveResults(4.05, .265, .265));
v4.setResults(CurveFitType.THREE_PARAMETER_ALT, new CurveResults(4.05, .265, .265));
v4.setResults(CurveFitType.FOUR_PARAMETER, new CurveResults(4.5, .226, .247));
v4.setResults(CurveFitType.FIVE_PARAMETER_ALT, new CurveResults(3.29, .245, .251));
v4.setResults(CurveFitType.FIVE_PARAMETER, new CurveResults(3.7, .245, .262));
v4.setResults(CurveFitType.LINEAR, new CurveResults(27.5, .374, .374));
validations.add(v4);
Expand All @@ -173,6 +179,7 @@ public void TestCurveFits() throws Exception
v5.setResults(CurveFitType.THREE_PARAMETER, new CurveResults(7.86, .281, .281));
v5.setResults(CurveFitType.THREE_PARAMETER_ALT, new CurveResults(7.86, .281, .281));
v5.setResults(CurveFitType.FOUR_PARAMETER, new CurveResults(5, .201, .263));
v5.setResults(CurveFitType.FIVE_PARAMETER_ALT, new CurveResults(4.105, .221, .277));
v5.setResults(CurveFitType.FIVE_PARAMETER, new CurveResults(5.1, .221, .277));
v5.setResults(CurveFitType.LINEAR, new CurveResults(38.0, .363, .363));
validations.add(v5);
Expand All @@ -187,9 +194,9 @@ public void TestCurveFits() throws Exception
CurveResults results = validation.getResults(fitType);

// validate calculated and expected fit error and auc
assertEquals(results.getFitError(), fit.getFitError(), 0.05);
assertEquals(results.getAuc(), fit.calculateAUC(AUCType.NORMAL), 0.005);
assertEquals(results.getPositiveAuc(), fit.calculateAUC(AUCType.POSITIVE), 0.005);
assertEquals(fitType.getLabel(), results.getFitError(), fit.getFitError(), 0.05);
assertEquals(fitType.getLabel(), results.getAuc(), fit.calculateAUC(AUCType.NORMAL), 0.005);
assertEquals(fitType.getLabel(), results.getPositiveAuc(), fit.calculateAUC(AUCType.POSITIVE), 0.005);
}
}
}
Expand Down Expand Up @@ -328,6 +335,15 @@ public void TestCurveFitParameters() throws Exception
fit.setLogXScale(true);
verifySigmoidalParameters(fit, 0.67, 4.0, 2.246, 0.095, 1.466);
assertEquals(0.997, fit.rSquared(fit.getParameters()), delta);

fit = service.getCurveFit(CurveFitType.FIVE_PARAMETER_ALT, data1);
fit.setLogXScale(false);
verifySigmoidalParameters(fit, 0.67, 3.17, 9.5144, 0.096, 0.2094);
assertEquals(0.9978, fit.rSquared(fit.getParameters()), delta);
fit = service.getCurveFit(CurveFitType.FIVE_PARAMETER_ALT, data1, null, 4.0);
fit.setLogXScale(true);
verifySigmoidalParameters(fit, 0.67, 4.0, 1.7321, 0.0946, 3.0369);
assertEquals(0.9207, fit.rSquared(fit.getParameters()), delta);
}

@Test
Expand All @@ -353,6 +369,12 @@ public void TestCurveFitParametersNAbCase() throws Exception
assertEquals(3.493, fit.getFitError(), delta);
assertEquals(0.990, fit.rSquared(fit.getParameters()), delta);

fit = service.getCurveFit(CurveFitType.FIVE_PARAMETER_ALT, data1);
fit.setLogXScale(true);
verifySigmoidalParameters(fit, -2.0, 93.0, -1.1106, 10.6605, 0.2094);
assertEquals(2.3816, fit.getFitError(), delta);
assertEquals(0.9954, fit.rSquared(fit.getParameters()), delta);

fit = service.getCurveFit(CurveFitType.FOUR_PARAMETER, data1);
fit.setLogXScale(true);
verifySigmoidalParameters(fit, -2.0, 103.0, -0.325, 6.907, 1.0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,4 @@ public double fitCurve(double x, SigmoidalParameters params)
}
throw new IllegalArgumentException("No curve fit parameters for " + _fitType.name());
}

@Override
public double adjustedRSquared(SigmoidalParameters parameters)
{
return adjustedRSquared(parameters, 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Ext4.define('LABKEY.vis.TrendlineField', {
baseQueryKey: null,
initData: null,

options: ['', 'Linear', 'Polynomial', '3 Parameter', 'Three Parameter', '4 Parameter', 'Four Parameter', 'Five Parameter'],
options: ['', 'Linear', 'Polynomial', '3 Parameter', 'Three Parameter', '4 Parameter', 'Four Parameter', 'Five Parameter', '5 Parameter'],

initComponent: function() {
if (this.initData == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,7 @@ Ext4.define('LABKEY.ext4.GenericChartPanel', {
config.geomOptions.trendlineType = this.trendline.trendlineType;
config.geomOptions.trendlineAsymptoteMin = this.trendline.trendlineAsymptoteMin;
config.geomOptions.trendlineAsymptoteMax = this.trendline.trendlineAsymptoteMax;
config.geomOptions.trendlineParameters = this.trendline.trendlineParameters;
}

if (this.getCustomChartOptions)
Expand Down Expand Up @@ -1325,6 +1326,7 @@ Ext4.define('LABKEY.ext4.GenericChartPanel', {
trendlineType: chartConfig.geomOptions.trendlineType,
trendlineAsymptoteMin: chartConfig.geomOptions.trendlineAsymptoteMin,
trendlineAsymptoteMax: chartConfig.geomOptions.trendlineAsymptoteMax,
trendlineParameters: chartConfig.geomOptions.trendlineParameters,
}
}
}
Expand Down
Loading
Loading