package org.baderlab.csplugins.enrichmentmap.style;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_CUTOFF_TYPE;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_HYPERGEOM_CUTOFF;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_HYPERGEOM_PVALUE;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_MANN_WHIT_CUTOFF;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_MANN_WHIT_GREATER_PVALUE;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_MANN_WHIT_LESS_PVALUE;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_MANN_WHIT_TWOSIDED_PVALUE;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_SIMILARITY_COEFF;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.EDGE_WIDTH_FORMULA_COLUMN;
import static org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns.NETWORK_EDGE_WIDTH_PARAMETERS_COLUMN;
import org.baderlab.csplugins.enrichmentmap.CytoscapeServiceModule.Continuous;
import org.baderlab.csplugins.enrichmentmap.model.EnrichmentMap;
import org.baderlab.csplugins.enrichmentmap.model.EnrichmentMapManager;
import org.baderlab.csplugins.enrichmentmap.model.PostAnalysisFilterType;
import org.baderlab.csplugins.enrichmentmap.model.PostAnalysisParameters;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyRow;
import org.cytoscape.model.CyTable;
import org.cytoscape.view.presentation.property.BasicVisualLexicon;
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
import org.cytoscape.view.vizmap.mappings.BoundaryRangeValues;
import org.cytoscape.view.vizmap.mappings.ContinuousMapping;
import org.cytoscape.work.TaskMonitor;
import com.google.inject.Inject;
public class WidthFunction {
public static final double DEFAULT_WIDTH_EM_LOWER = 1.0;
public static final double DEFAULT_WIDTH_EM_UPPER = 5.0;
public static final double DEFAULT_WIDTH_PA_LESS_THAN_100 = 8.0;
public static final double DEFAULT_WIDTH_PA_LESS_THAN_10 = 4.5;
public static final double DEFAULT_WIDTH_PA_GREATER = 1.0;
private final VisualMappingFunctionFactory vmfFactoryContinuous;
private final EnrichmentMapManager emManager;
@Inject
public WidthFunction(@Continuous VisualMappingFunctionFactory vmfFactoryContinuous, EnrichmentMapManager emManager) {
this.vmfFactoryContinuous = vmfFactoryContinuous;
this.emManager = emManager;
}
private static boolean isSignature(String interaction) {
return PostAnalysisParameters.SIGNATURE_INTERACTION_TYPE.equals(interaction)
|| PostAnalysisParameters.SIGNATURE_INTERACTION_TYPE_SET1.equals(interaction)
|| PostAnalysisParameters.SIGNATURE_INTERACTION_TYPE_SET2.equals(interaction);
}
public static boolean appliesTo(CyNetwork network) {
CyTable networkTable = network.getDefaultNetworkTable();
return networkTable.getColumn(NETWORK_EDGE_WIDTH_PARAMETERS_COLUMN.with(null,null)) != null;
}
public void setEdgeWidths(CyNetwork network, String prefix, TaskMonitor taskMonitor) {
createColumns(network, prefix);
calculateAndSetEdgeWidths(network, prefix, taskMonitor);
}
private void createColumns(CyNetwork network, String prefix) {
CyTable networkTable = network.getDefaultNetworkTable();
NETWORK_EDGE_WIDTH_PARAMETERS_COLUMN.createColumnIfAbsent(networkTable, null, null);
CyTable edgeTable = network.getDefaultEdgeTable();
EDGE_WIDTH_FORMULA_COLUMN.createColumnIfAbsent(edgeTable, prefix, null);
}
private void calculateAndSetEdgeWidths(CyNetwork network, String prefix, TaskMonitor taskMonitor) {
EdgeWidthParams edgeWidthParams = EdgeWidthParams.restore(network);
EnrichmentMap map = emManager.getEnrichmentMap(network.getSUID());
// String widthAttribute = prefix + EDGE_WIDTH_FORMULA_COLUMN;
int n = network.getDefaultEdgeTable().getRowCount();
int i = 0;
for (CyRow row : network.getDefaultEdgeTable().getAllRows()) {
if (taskMonitor != null)
taskMonitor.setProgress((double) i / (double) n);
i++;
String interaction = row.get(CyEdge.INTERACTION, String.class);
if (isSignature(interaction)) {
String cutoffType = EDGE_CUTOFF_TYPE.get(row, prefix, null);
PostAnalysisFilterType filterType = PostAnalysisFilterType.fromDisplayString(cutoffType);
if (filterType == null) {
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, null, null);
continue;
}
Double pvalue, cutoff;
switch(filterType) {
case MANN_WHIT_TWO_SIDED:
pvalue = EDGE_MANN_WHIT_TWOSIDED_PVALUE.get(row, prefix);
cutoff = EDGE_MANN_WHIT_CUTOFF.get(row, prefix);
break;
case MANN_WHIT_GREATER:
pvalue = EDGE_MANN_WHIT_GREATER_PVALUE.get(row, prefix);
cutoff = EDGE_MANN_WHIT_CUTOFF.get(row, prefix);
break;
case MANN_WHIT_LESS:
pvalue = EDGE_MANN_WHIT_LESS_PVALUE.get(row, prefix);
cutoff = EDGE_MANN_WHIT_CUTOFF.get(row, prefix);
break;
default:
pvalue = EDGE_HYPERGEOM_PVALUE.get(row, prefix);
cutoff = EDGE_HYPERGEOM_CUTOFF.get(row, prefix);
break;
}
if (pvalue == null || cutoff == null) {
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, null);
} else if (pvalue <= cutoff / 100) {
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, edgeWidthParams.pa_lessThan100);
} else if (pvalue <= cutoff / 10) {
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, edgeWidthParams.pa_lessThan10);
} else {
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, edgeWidthParams.pa_greater);
}
} else {
// Can use a continuous mapping object to perform calculation
// even though it won't be added to the visual style.
ContinuousMapping<Double, Double> conmapping_edgewidth = (ContinuousMapping<Double, Double>) vmfFactoryContinuous
.createVisualMappingFunction(prefix + EDGE_SIMILARITY_COEFF, Double.class,
BasicVisualLexicon.EDGE_WIDTH);
Double under_width = 0.5;
Double min_width = edgeWidthParams.em_lower;
Double max_width = edgeWidthParams.em_upper;
Double over_width = 6.0;
// Create boundary conditions less than, equals, greater than
BoundaryRangeValues<Double> bv4 = new BoundaryRangeValues<>(under_width, min_width, min_width);
BoundaryRangeValues<Double> bv5 = new BoundaryRangeValues<>(max_width, max_width, over_width);
conmapping_edgewidth.addPoint(map.getParams().getSimilarityCutoff(), bv4);
conmapping_edgewidth.addPoint(1.0, bv5);
Double value = conmapping_edgewidth.getMappedValue(row);
EDGE_WIDTH_FORMULA_COLUMN.set(row, prefix, value);
}
}
}
/**
* Parameters typically used by the EdgeWidthDialog and stored in the network table.
*/
public static class EdgeWidthParams {
public final double em_lower;
public final double em_upper;
public final double pa_lessThan100;
public final double pa_lessThan10;
public final double pa_greater;
public EdgeWidthParams(double em_lower, double em_upper, double pa_lessThan100, double pa_lessThan10, double pa_greater) {
this.em_lower = em_lower;
this.em_upper = em_upper;
this.pa_lessThan100 = pa_lessThan100;
this.pa_lessThan10 = pa_lessThan10;
this.pa_greater = pa_greater;
}
public static EdgeWidthParams defaultValues() {
return new EdgeWidthParams(DEFAULT_WIDTH_EM_LOWER, DEFAULT_WIDTH_EM_UPPER,
DEFAULT_WIDTH_PA_LESS_THAN_100, DEFAULT_WIDTH_PA_LESS_THAN_10, DEFAULT_WIDTH_PA_GREATER);
}
public static EdgeWidthParams restore(CyNetwork network) {
try {
String val = NETWORK_EDGE_WIDTH_PARAMETERS_COLUMN.get(network.getRow(network), null);
String[] params = val.split(",");
double em_lower = Double.parseDouble(params[0]);
double em_upper = Double.parseDouble(params[1]);
double pa_lessThan100 = Double.parseDouble(params[2]);
double pa_lessThan10 = Double.parseDouble(params[3]);
double pa_greater = Double.parseDouble(params[4]);
return new EdgeWidthParams(em_lower, em_upper, pa_lessThan100, pa_lessThan10, pa_greater);
} catch(NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
return defaultValues();
}
}
public void save(CyNetwork network) {
CyRow row = network.getRow(network);
String val = String.format("%f,%f,%f,%f,%f", em_lower, em_upper, pa_lessThan100, pa_lessThan10, pa_greater);
NETWORK_EDGE_WIDTH_PARAMETERS_COLUMN.set(row, null, val);
}
}
}