/*
* This file is part of ADDIS (Aggregate Data Drug Information System).
* ADDIS is distributed from http://drugis.org/.
* Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen.
* Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels,
* Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel
* Reid.
* Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin
* Schimbinschi.
* Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter
* Reckman.
* Copyright © 2013 Gert van Valkenhoef, Joël Kuiper.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.drugis.addis.presentation;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.drugis.addis.entities.AdverseEvent;
import org.drugis.addis.entities.Arm;
import org.drugis.addis.entities.ContinuousVariableType;
import org.drugis.addis.entities.Endpoint;
import org.drugis.addis.entities.Entity;
import org.drugis.addis.entities.OutcomeMeasure;
import org.drugis.addis.entities.RateVariableType;
import org.drugis.addis.entities.Variable;
import org.drugis.addis.entities.VariableType;
import org.drugis.addis.entities.analysis.BenefitRiskAnalysis;
import org.drugis.addis.entities.analysis.MetaBenefitRiskAnalysis;
import org.drugis.addis.entities.analysis.StudyBenefitRiskAnalysis;
import org.drugis.addis.entities.analysis.MeasurementSource.Listener;
import org.drugis.addis.entities.relativeeffect.AxisType;
import org.drugis.addis.entities.relativeeffect.ConfidenceInterval;
import org.drugis.addis.entities.relativeeffect.Distribution;
import org.drugis.addis.entities.treatment.TreatmentDefinition;
import org.drugis.addis.forestplot.BinnedScale;
import org.drugis.addis.forestplot.ForestPlot;
import org.drugis.addis.forestplot.LinearScale;
import org.drugis.addis.forestplot.LogScale;
import org.drugis.addis.forestplot.Scale;
import org.drugis.common.Interval;
public class BRATTableModel<Alternative extends Entity, AnalysisType extends BenefitRiskAnalysis<Alternative>> extends AbstractTableModel {
public static class BRATForest {
public final ConfidenceInterval ci;
public final BinnedScale scale;
public final Scale axis;
public final VariableType vt;
public BRATForest(BinnedScale scale, ConfidenceInterval ci, VariableType vt) {
this.ci = ci;
this.scale = scale;
this.vt = vt;
this.axis = null;
}
public BRATForest(BinnedScale scale, Scale axis, VariableType vt) {
this.vt = vt;
this.ci = null;
this.scale = scale;
this.axis = axis;
}
}
public static class BRATDifference {
private final OutcomeMeasure d_om;
private final Distribution d_difference;
public BRATDifference(OutcomeMeasure om, Distribution difference) {
d_om = om;
d_difference = difference;
}
public OutcomeMeasure getOutcomeMeasure() {
return d_om;
}
public Distribution getDifference() {
return d_difference;
}
}
public static final int COLUMN_BR = 0;
public static final int COLUMN_CRITERIA = 1;
public static final int COLUMN_OUTCOME_TYPE = 2;
public static final int COLUMN_BASELINE = 3;
public static final int COLUMN_SUBJECT = 4;
public static final int COLUMN_DIFFERENCE = 5;
public static final int COLUMN_FOREST = 6;
public static final int OFFSET_LOGAXIS = 0;
public static final int OFFSET_LINAXIS = 1;
private static final long serialVersionUID = 4201230853343429062L;
private final AnalysisType d_analysis;
private final Alternative d_subject;
private LinearScale d_linScale;
private LogScale d_logScale;
private LinearScale d_linScaleFull;
private LogScale d_logScaleFull;
public BRATTableModel(AnalysisType bean, Alternative subject) {
d_analysis = bean;
d_subject = subject;
d_analysis.getMeasurementSource().addMeasurementsChangedListener(new Listener() {
public void notifyMeasurementsChanged() {
calculateScales();
fireTableDataChanged();
}
});
calculateScales();
}
private void calculateScales() {
List<ConfidenceInterval> logCIs = new ArrayList<ConfidenceInterval>();
List<ConfidenceInterval> linCIs = new ArrayList<ConfidenceInterval>();
for (OutcomeMeasure om : d_analysis.getCriteria()) {
Distribution diff = getDifference(om);
if (om.getVariableType() instanceof RateVariableType && diff != null) {
logCIs.add(getCI(diff));
} else if (om.getVariableType() instanceof ContinuousVariableType && diff != null) {
linCIs.add(getCI(diff));
}
}
if (!logCIs.isEmpty()) {
d_logScale = new LogScale(REMAForestPlotPresentation.getRange(logCIs, AxisType.LOGARITHMIC));
}
if (!linCIs.isEmpty()) {
d_linScale = new LinearScale(REMAForestPlotPresentation.getRange(linCIs, AxisType.LINEAR));
}
double hullLower = -1;
double hullUpper = 1;
if (d_logScale != null && d_linScale != null) {
hullLower = Math.min(Math.log(d_logScale.getMin()), d_linScale.getMin());
hullUpper = Math.max(Math.log(d_logScale.getMax()), d_linScale.getMax());
} else if (d_logScale != null) {
hullLower = Math.log(d_logScale.getMin());
hullUpper = Math.log(d_logScale.getMax());
} else if (d_linScale != null) {
hullLower = d_linScale.getMin();
hullUpper = d_linScale.getMax();
}
d_logScaleFull = new LogScale(new Interval<Double>(Math.exp(hullLower), Math.exp(hullUpper)));
d_linScaleFull = new LinearScale(new Interval<Double>(hullLower, hullUpper));
}
@Override
public int getColumnCount() {
return COLUMN_FOREST + 1;
}
@Override
public int getRowCount() {
return d_analysis.getCriteria().size() + 2;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// Special case for axes
if (rowIndex >= d_analysis.getCriteria().size()) {
if (columnIndex == COLUMN_FOREST) {
final int offset = rowIndex - d_analysis.getCriteria().size();
if (offset == OFFSET_LOGAXIS) {
return new BRATForest(getBinnedScale(getFullLogScale()), getNiceLogScale(), new ContinuousVariableType());
} else if (offset == OFFSET_LINAXIS) {
return new BRATForest(getBinnedScale(getFullLinearScale()), getNiceLinearScale(), new RateVariableType());
}
} else if (columnIndex == COLUMN_DIFFERENCE) {
final int offset = rowIndex - d_analysis.getCriteria().size();
if (offset == OFFSET_LOGAXIS && d_logScale != null) {
return "<html>Log scale</html>";
} else if (offset == OFFSET_LINAXIS && d_linScale != null) {
return "<html>Linear scale</html>";
}
}
return null;
}
// regular table cells
if (columnIndex == COLUMN_BR) {
if (d_analysis.getCriteria().get(rowIndex) instanceof Endpoint) {
return "Benefit";
} else if (d_analysis.getCriteria().get(rowIndex) instanceof AdverseEvent) {
return "Risk";
}
} else if (columnIndex == COLUMN_CRITERIA) {
return d_analysis.getCriteria().get(rowIndex);
} else if (columnIndex == COLUMN_OUTCOME_TYPE) {
return getVariableType(rowIndex);
} else if (columnIndex == COLUMN_BASELINE) {
return getMeasurement(rowIndex, getBaseline());
} else if (columnIndex == COLUMN_SUBJECT) {
return getMeasurement(rowIndex, getSubject());
} else if (columnIndex == COLUMN_DIFFERENCE) {
return getDifference(rowIndex);
} else if (columnIndex == COLUMN_FOREST) {
return getDifference(rowIndex) == null ? null :
new BRATForest(getBinnedScale(getScale(rowIndex)), getCI(getDifference(rowIndex).getDifference()), getVariableType(rowIndex));
}
return "";
}
private BinnedScale getBinnedScale(Scale scale) {
return new BinnedScale(scale, 1, ForestPlot.BARWIDTH);
}
private VariableType getVariableType(int rowIndex) {
return d_analysis.getCriteria().get(rowIndex).getVariableType();
}
private ConfidenceInterval getCI(Distribution difference) {
return new ConfidenceInterval(difference.getQuantile(0.5), difference.getQuantile(0.025), difference.getQuantile(0.975));
}
private BRATDifference getDifference(int rowIndex) {
OutcomeMeasure om = d_analysis.getCriteria().get(rowIndex);
Distribution difference = getDifference(om);
return difference == null ? null : new BRATDifference(om, difference);
}
private Distribution getDifference(OutcomeMeasure om) {
if (d_analysis instanceof StudyBenefitRiskAnalysis) {
StudyBenefitRiskAnalysis sba = (StudyBenefitRiskAnalysis) d_analysis;
return sba.getRelativeEffectDistribution(om, (Arm) getSubject());
} else if (d_analysis instanceof MetaBenefitRiskAnalysis) {
MetaBenefitRiskAnalysis mba = (MetaBenefitRiskAnalysis) d_analysis;
return mba.getRelativeEffectDistribution(om, (TreatmentDefinition) getSubject());
}
return null;
}
private Object getMeasurement(int rowIndex, Alternative a) {
if (d_analysis instanceof StudyBenefitRiskAnalysis && rowIndex < d_analysis.getCriteria().size()) {
StudyBenefitRiskAnalysis sba = (StudyBenefitRiskAnalysis) d_analysis;
return sba.getMeasurement(sba.getCriteria().get(rowIndex), (Arm) a);
} else if (d_analysis instanceof MetaBenefitRiskAnalysis && rowIndex < d_analysis.getCriteria().size()) {
MetaBenefitRiskAnalysis mba = (MetaBenefitRiskAnalysis) d_analysis;
return mba.getMeasurement(mba.getCriteria().get(rowIndex), (TreatmentDefinition) a);
}
throw new IllegalStateException("Unknown analysis type " + d_analysis.getClass().getSimpleName());
}
@Override
public String getColumnName(int column) {
switch(column) {
case COLUMN_BR:
return "";
case COLUMN_CRITERIA:
return "Outcome";
case COLUMN_OUTCOME_TYPE:
return "Type";
case COLUMN_BASELINE:
return getAlternativeDescription(getBaseline());
case COLUMN_SUBJECT:
return getAlternativeDescription(getSubject());
case COLUMN_DIFFERENCE:
return "Difference (95% CI)";
case COLUMN_FOREST:
return "";
default:
return"";
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case COLUMN_BR:
return String.class;
case COLUMN_CRITERIA:
return Variable.class;
case COLUMN_OUTCOME_TYPE:
return VariableType.class;
case COLUMN_BASELINE:
case COLUMN_SUBJECT:
return Distribution.class;
case COLUMN_DIFFERENCE:
return BRATDifference.class;
case COLUMN_FOREST:
return BRATForest.class;
default:
return null;
}
}
private String getAlternativeDescription(Alternative alternative) {
if(alternative instanceof Arm) {
StudyBenefitRiskAnalysis sba = (StudyBenefitRiskAnalysis) d_analysis;
return sba.getStudy().getTreatment((Arm) alternative).getLabel();
}
return alternative.getLabel();
}
private Scale getScale(int rowIndex) {
VariableType vt = getVariableType(rowIndex);
if (vt instanceof ContinuousVariableType) {
return d_linScaleFull;
} else if (vt instanceof RateVariableType) {
return d_logScaleFull;
}
throw new IllegalStateException("Unknown variable type " + vt.getClass().getSimpleName());
}
LinearScale getNiceLinearScale() {
return d_linScale;
}
LogScale getNiceLogScale() {
return d_logScale;
}
LinearScale getFullLinearScale() {
return d_linScaleFull;
}
LogScale getFullLogScale() {
return d_logScaleFull;
}
public Alternative getBaseline() {
return d_analysis.getBaseline();
}
public Alternative getSubject() {
return d_subject;
}
}