Skip to content

Commit 819f9bf

Browse files
committed
Fix color interpolation for expression data chart. Fixes #356
1 parent 30b80e7 commit 819f9bf

File tree

7 files changed

+102
-137
lines changed

7 files changed

+102
-137
lines changed

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/style/charts/radialheatmap/RadialHeatMapLayer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ protected JFreeChart createChart(final PieDataset dataset) {
151151
Color upperColor = Color.BLUE;
152152
Color zeroColor = Color.WHITE;
153153
Color lowerColor = Color.RED;
154-
Color nanColor = TRANSPARENT_COLOR;
154+
Color nanColor = Color.LIGHT_GRAY;
155155

156156
if (colorPoints.isEmpty() || colorPoints.size() != colors.size()) {
157157
if (range != null && range.size() >= 2 && range.get(0) != null && range.get(1) != null) {

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/task/UpdateAssociatedStyleTask.java

Lines changed: 33 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package org.baderlab.csplugins.enrichmentmap.task;
22

33
import java.awt.Color;
4-
import java.util.ArrayList;
54
import java.util.Arrays;
65
import java.util.Collection;
7-
import java.util.Collections;
86
import java.util.HashMap;
97
import java.util.List;
108
import java.util.Map;
@@ -24,12 +22,10 @@
2422
import org.baderlab.csplugins.enrichmentmap.style.ChartFactoryManager;
2523
import org.baderlab.csplugins.enrichmentmap.style.ChartOptions;
2624
import org.baderlab.csplugins.enrichmentmap.style.ChartType;
27-
import org.baderlab.csplugins.enrichmentmap.style.ColorScheme;
2825
import org.baderlab.csplugins.enrichmentmap.style.EMStyleBuilder.Columns;
2926
import org.baderlab.csplugins.enrichmentmap.style.charts.AbstractChart;
3027
import org.baderlab.csplugins.enrichmentmap.util.NetworkUtil;
3128
import org.baderlab.csplugins.enrichmentmap.view.heatmap.table.DataSetColorRange;
32-
import org.baderlab.csplugins.enrichmentmap.view.util.ChartUtil;
3329
import org.cytoscape.model.CyNetwork;
3430
import org.cytoscape.model.CyNode;
3531
import org.cytoscape.model.CyTable;
@@ -110,39 +106,38 @@ private void updateExpressionDataColumn() {
110106
} catch (Exception e) {
111107
logger.error("Cannot create column " + Columns.EXPRESSION_DATA_CHART.with(prefix), e);
112108
}
109+
}
113110

111+
Map<Long, double[]> columnData = new HashMap<>();
112+
EnrichmentMap map = options.getEnrichmentMap();
113+
ExpressionData exp = options.getExpressionData();
114114

115-
Map<Long, double[]> columnData = new HashMap<>();
116-
EnrichmentMap map = options.getEnrichmentMap();
117-
ExpressionData exp = options.getExpressionData();
115+
int n = exp.getSize();
116+
117+
for (CyNode node : network.getNodeList()) {
118+
double[] data = new double[n];
119+
columnData.put(node.getSUID(), data);
118120

119-
int n = exp.getSize();
120-
121-
for (CyNode node : network.getNodeList()) {
122-
double[] data = new double[n];
123-
columnData.put(node.getSUID(), data);
124-
125-
String name = NetworkUtil.getGeneName(network, node);
126-
127-
if (name == null)
128-
continue;
129-
130-
String queryTerm = NetworkUtil.getQueryTerm(network, name);
131-
Integer id = map.getHashFromGene(queryTerm != null ? queryTerm : name);
132-
133-
if (id == null)
134-
continue;
135-
136-
for (int i = 0; i < n; i++) {
137-
double value = exp.getValue(id, i, options.getCompress());
138-
data[i] = value;
139-
}
121+
String name = NetworkUtil.getGeneName(network, node);
122+
123+
if (name == null)
124+
continue;
125+
126+
String queryTerm = NetworkUtil.getQueryTerm(network, name);
127+
Integer id = map.getHashFromGene(queryTerm != null ? queryTerm : name);
128+
129+
if (id == null)
130+
continue;
131+
132+
for (int i = 0; i < n; i++) {
133+
double value = exp.getValue(id, i, options.getCompress());
134+
data[i] = value;
140135
}
141-
142-
columnData.forEach((suid, data) ->
143-
Columns.EXPRESSION_DATA_CHART.set(nodeTable.getRow(suid), prefix, Doubles.asList(data))
144-
);
145136
}
137+
138+
columnData.forEach((suid, data) ->
139+
Columns.EXPRESSION_DATA_CHART.set(nodeTable.getRow(suid), prefix, Doubles.asList(data))
140+
);
146141
}
147142

148143
private void createDataSetColumn() {
@@ -215,7 +210,7 @@ private CyCustomGraphics2<?> createChart() {
215210
List<AbstractDataSet> dataSets = options.getDataSets(); // Ignore Signature Data Sets in charts
216211

217212
if (type != null && !dataSets.isEmpty()) {
218-
Map<String, Object> props = new HashMap<>(type.getProperties());
213+
Map<String,Object> props = new HashMap<>(type.getProperties());
219214

220215
String prefix = options.getEnrichmentMap().getParams().getAttributePrefix();
221216
AbstractColumnDescriptor columnDescriptor = data.getColumnDescriptor();
@@ -231,6 +226,7 @@ private CyCustomGraphics2<?> createChart() {
231226
List<CyColumnIdentifier> columns = Arrays.asList(columnIdFactory.createColumnIdentifier(columnDescriptor.with(prefix)));
232227
List<Double> range = null;
233228
List<Color> colors = null;
229+
List<Double> colorPoints = null;
234230

235231
AbstractDataSet ds = dataSets.get(0);
236232

@@ -239,43 +235,24 @@ private CyCustomGraphics2<?> createChart() {
239235
Optional<DataSetColorRange> dsColorRange = DataSetColorRange.create(matrix, options.getTransform());
240236

241237
if (dsColorRange.isPresent()) {
242-
Color c1 = dsColorRange.get().getTheme().getMinColor();
243-
Color c2 = dsColorRange.get().getTheme().getCenterColor();
244-
Color c3 = dsColorRange.get().getTheme().getMaxColor();
245-
colors = Arrays.asList(new Color[] { c1, c2, c3 });
238+
range = dsColorRange.get().getRangeMinMax();
239+
colors = dsColorRange.get().getColors();
240+
colorPoints = dsColorRange.get().getPoints();
246241
}
247242
}
248243

249-
range = ChartUtil.calculateGlobalRange(options.getNetworkView().getModel(), columns);
250-
System.out.println(range.get(0)+","+range.get(1));
251-
252-
if (colors == null || colors.isEmpty())
253-
colors = new ArrayList<>(ColorScheme.RD_YL_BU_3.getColors());
254-
255-
if (range.size() > 0 && range.get(0) < 0) // Does it have negative numbers?
256-
Collections.reverse(colors);
257-
258244
props.put("cy_dataColumns", columns);
259245
props.put("cy_range", range);
260246
props.put("cy_autoRange", false);
261247
props.put("cy_globalRange", true);
262248
props.put("cy_showRangeZeroBaseline", true);
263249
props.put("cy_showItemLabels", chartOptions.isShowLabels());
264250
props.put("cy_colors", colors);
265-
266-
ColorScheme colorScheme = chartOptions != null ? chartOptions.getColorScheme() : null;
267-
268-
if (colorScheme != null && colorScheme.getPoints() != null) {
269-
List<Double> points = colorScheme.getPoints();
270-
271-
if (!points.isEmpty())
272-
props.put(AbstractChart.COLOR_POINTS, points);
273-
}
251+
props.put(AbstractChart.COLOR_POINTS, colorPoints);
274252
}
275253

276254
try {
277255
CyCustomGraphics2Factory<?> factory = chartFactoryManager.getChartFactory(type.getId());
278-
279256
if (factory != null)
280257
chart = factory.getInstance(props);
281258
} catch (Exception e) {

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/view/control/ControlPanelMediator.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -796,15 +796,13 @@ private AssociatedStyleOptions createAssociatedStyleOptions(EnrichmentMap map, A
796796
final AssociatedApp app = NetworkUtil.getAssociatedApp(netView.getModel());
797797
List<EMDataSet> datasets = ds != null ? Collections.singletonList(ds) : map.getDataSetList();
798798

799-
ExpressionData exp = data == ChartData.EXPRESSION_DATA ?
800-
createExpressionData(map, datasets, transform, compress) : null;
799+
ExpressionData exp = data == ChartData.EXPRESSION_DATA ? createExpressionData(map, datasets, transform, compress) : null;
801800
ChartOptions chartOptions = data != null ? new ChartOptions(data, type, null, false) : null;
802801

803802
return new AssociatedStyleOptions(netView, map, transform, compress, exp, chartOptions, app);
804803
}
805804

806-
private ExpressionData createExpressionData(EnrichmentMap map, List<EMDataSet> datasets, Transform transform,
807-
Compress compress) {
805+
private ExpressionData createExpressionData(EnrichmentMap map, List<EMDataSet> datasets, Transform transform, Compress compress) {
808806
ExpressionData exp = null;
809807
ExpressionCache cache = new ExpressionCache(transform);
810808

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/view/heatmap/table/DataSetColorRange.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package org.baderlab.csplugins.enrichmentmap.view.heatmap.table;
22

3+
import java.awt.Color;
4+
import java.util.Arrays;
5+
import java.util.List;
36
import java.util.Optional;
47

58
import org.baderlab.csplugins.enrichmentmap.model.GeneExpressionMatrix;
69
import org.baderlab.csplugins.enrichmentmap.model.Transform;
10+
import org.baderlab.csplugins.enrichmentmap.view.util.ColorUtil;
711
import org.baderlab.csplugins.org.mskcc.colorgradient.ColorGradientRange;
812
import org.baderlab.csplugins.org.mskcc.colorgradient.ColorGradientTheme;
913

@@ -12,6 +16,10 @@ public class DataSetColorRange {
1216
private final ColorGradientTheme theme;
1317
private final ColorGradientRange range;
1418

19+
private List<Double> points;
20+
private List<Color> colors;
21+
22+
1523
private DataSetColorRange(ColorGradientTheme theme, ColorGradientRange range) {
1624
this.theme = theme;
1725
this.range = range;
@@ -49,7 +57,6 @@ public static Optional<DataSetColorRange> create(GeneExpressionMatrix expression
4957
}
5058
}
5159

52-
5360
public ColorGradientTheme getTheme() {
5461
return theme;
5562
}
@@ -58,6 +65,49 @@ public ColorGradientRange getRange() {
5865
return range;
5966
}
6067

68+
69+
public Color getColor(Double value) {
70+
if(value == null || !Double.isFinite(value))
71+
return theme.getNoDataColor();
72+
73+
if(points == null)
74+
points = Arrays.asList(range.getMaxValue(), range.getCenterHighValue(), range.getMinValue());
75+
if(colors == null)
76+
colors = Arrays.asList(theme.getMaxColor(), theme.getCenterColor(), theme.getMinColor());
77+
78+
return ColorUtil.getColor(value, colors, points);
79+
}
80+
81+
82+
/**
83+
* Returns the (max, center, min) colors.
84+
* Compatible with the "cy_colors" property of the RadialHeatMap.
85+
*/
86+
public List<Color> getColors() {
87+
if(colors == null)
88+
colors = Arrays.asList(theme.getMaxColor(), theme.getCenterColor(), theme.getMinColor());
89+
return colors;
90+
}
91+
92+
/**
93+
* Returns the (max, center, min) points of the range.
94+
* Compatible with the "cy_colorPoints" property of the RadialHeatMap.
95+
*/
96+
public List<Double> getPoints() {
97+
if(points == null)
98+
points = Arrays.asList(range.getMaxValue(), range.getCenterHighValue(), range.getMinValue());
99+
return points;
100+
}
101+
102+
/**
103+
* Returns the range bounds as a two-element List.
104+
* Compatible with the "cy_range" property of the RadialHeatMap.
105+
*/
106+
public List<Double> getRangeMinMax() {
107+
return Arrays.asList(range.getMinValue(), range.getMaxValue());
108+
}
109+
110+
61111
@Override
62112
public String toString() {
63113
return String.format("Range[min:%f,max:%f]", range.getMinValue(), range.getMaxValue());

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/view/heatmap/table/HeatMapCellRenderer.java

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
import org.apache.commons.lang3.tuple.Pair;
2020
import org.baderlab.csplugins.enrichmentmap.model.EMDataSet;
2121
import org.baderlab.csplugins.enrichmentmap.model.Transform;
22-
import org.baderlab.csplugins.org.mskcc.colorgradient.ColorGradientRange;
23-
import org.baderlab.csplugins.org.mskcc.colorgradient.ColorGradientTheme;
2422

2523
public class HeatMapCellRenderer implements TableCellRenderer {
2624

@@ -79,7 +77,7 @@ private static Color getColor(HeatMapTableModel model, int col, double d, BiFunc
7977
Transform transform = model.getTransform();
8078
DataSetColorRange range = getColorRange.apply(dataset, transform);
8179
if(range != null) {
82-
Color color = getColor(d, range);
80+
Color color = range.getColor(d);
8381
return color;
8482
} else {
8583
return Color.GRAY;
@@ -101,63 +99,5 @@ public DataSetColorRange getRange(EMDataSet dataset, Transform transform) {
10199
).orElse(null);
102100
}
103101

104-
public static Color getColor(Double measurement, DataSetColorRange range) {
105-
return getColor(measurement, range.getTheme(), range.getRange());
106-
}
107-
108-
public static Color getColor(Double measurement, ColorGradientTheme theme, ColorGradientRange range) {
109-
if (theme == null)
110-
return Color.GRAY;
111-
if(range == null || measurement == null || !Double.isFinite(measurement)) // missing data can result in NaN, log transformed value of -1 can result in -Infinity
112-
return theme.getNoDataColor();
113-
114-
float rLow = (float)theme.getMinColor().getRed() / 255f;
115-
float gLow = (float)theme.getMinColor().getGreen() / 255f;
116-
float bLow = (float)theme.getMinColor().getBlue() / 255f;
117-
118-
float rMid = (float)theme.getCenterColor().getRed() / 255f;
119-
float gMid = (float)theme.getCenterColor().getGreen() / 255f;
120-
float bMid = (float)theme.getCenterColor().getBlue() / 255f;
121-
122-
float rHigh = (float)theme.getMaxColor().getRed() / 255f;
123-
float gHigh = (float)theme.getMaxColor().getGreen() / 255f;
124-
float bHigh = (float)theme.getMaxColor().getBlue() / 255f;
125-
126-
double median;
127-
if (range.getMinValue() >= 0)
128-
median = (range.getMaxValue() / 2);
129-
else
130-
median = 0.0;
131-
132-
// This happens when you row-normalize but there is only one column. This is probably
133-
// not the best way to fix it...
134-
if(median == 0.0 && measurement == 0.0) {
135-
return theme.getCenterColor();
136-
}
137-
138-
if (measurement <= median) {
139-
float prop = (float) ((float) (measurement - range.getMinValue()) / (median - range.getMinValue()));
140-
float rVal = rLow + prop * (rMid - rLow);
141-
float gVal = gLow + prop * (gMid - gLow);
142-
float bVal = bLow + prop * (bMid - bLow);
143-
144-
return new Color(rVal, gVal, bVal);
145-
} else {
146-
//Related to bug https://github.com/BaderLab/EnrichmentMapApp/issues/116
147-
//When there is differing max and mins for datasets then it will throw exception
148-
//for the dataset2 if the value is bigger than the max
149-
//This need to be fixed on the dataset but in the meantime if the value is bigger
150-
//than the max set it to the max
151-
if (measurement > range.getMaxValue())
152-
measurement = range.getMaxValue();
153-
154-
float prop = (float) ((float) (measurement - median) / (range.getMaxValue() - median));
155-
float rVal = rMid + prop * (rHigh - rMid);
156-
float gVal = gMid + prop * (gHigh - gMid);
157-
float bVal = bMid + prop * (bHigh - bMid);
158-
159-
return new Color(rVal, gVal, bVal);
160-
}
161-
}
162102

163103
}

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/view/heatmap/table/HeatMapTableModel.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ public void update(
9292
expressionCache = new ExpressionCache(transform);
9393

9494
ExpressionData uncompressed = new Uncompressed(datasets, expressionCache);
95-
ExpressionData compressedDataSet = new CompressedDataSet(datasets, expressionCache,
96-
map != null && map.isDistinctExpressionSets());
95+
ExpressionData compressedDataSet = new CompressedDataSet(datasets, expressionCache, map != null && map.isDistinctExpressionSets());
9796
ExpressionData compressedClass = new CompressedClass(datasets, expressionCache);
9897

9998
data.put(Compress.NONE, uncompressed);

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/view/util/ColorUtil.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ public static Color getColor(double value, List<Color> colors, List<Double> poin
105105
double p2 = points.get(i - 1);
106106
Color c1 = colors.get(i);
107107
Color c2 = colors.get(i - 1);
108-
float t = interpolate(value, p1, p2);
109-
108+
float t = interpolate(value, p2, p1);
110109
return interpolate(c1, c2, t);
111110
}
112111
}
@@ -125,16 +124,18 @@ public static Color interpolate(Color c1, Color c2, float t) {
125124
return new Color(comp3[0], comp3[1], comp3[2], comp3[3]);
126125
}
127126

127+
128128
private static float interpolate(final double value, final double lowerBound, final double upperBound) {
129-
// Linearly interpolate the value
130-
final double f = value < 0.0 ? MathUtil.invLinearInterp(value, lowerBound, 0)
131-
: MathUtil.invLinearInterp(value, 0, upperBound);
132-
float t = (float) (value < 0.0 ? MathUtil.linearInterp(f, 0.0, 1.0) : MathUtil.linearInterp(f, 1.0, 0.0));
133-
134-
// Make sure it's between 0.0-1.0
135-
t = Math.max(0.0f, t);
136-
t = Math.min(1.0f, t);
137-
138-
return t;
129+
return (float) MathUtil.invLinearInterp(value, lowerBound, upperBound);
130+
// // Linearly interpolate the value
131+
// final double f = value < 0.0 ? MathUtil.invLinearInterp(value, lowerBound, 0)
132+
// : MathUtil.invLinearInterp(value, 0, upperBound);
133+
// float t = (float) (value < 0.0 ? MathUtil.linearInterp(f, 0.0, 1.0) : MathUtil.linearInterp(f, 1.0, 0.0));
134+
//
135+
// // Make sure it's between 0.0-1.0
136+
// t = Math.max(0.0f, t);
137+
// t = Math.min(1.0f, t);
138+
//
139+
// return t;
139140
}
140141
}

0 commit comments

Comments
 (0)