Skip to content

Commit 7911c32

Browse files
authored
Merge pull request #2648 from lorenzgerber/pca
PCA, Mouse Selections in Scorebarplot
2 parents 8ed2b9a + 5507ce4 commit 7911c32

File tree

1 file changed

+278
-7
lines changed
  • chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt

1 file changed

+278
-7
lines changed

chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/ExtendedScorePlotBarChart.java

Lines changed: 278 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
import java.util.Comparator;
1717
import java.util.List;
1818
import java.util.concurrent.atomic.AtomicReference;
19+
import java.util.stream.IntStream;
1920

2021
import org.eclipse.chemclipse.model.statistics.ISample;
2122
import org.eclipse.chemclipse.model.statistics.IVariable;
2223
import org.eclipse.chemclipse.support.events.IChemClipseEvents;
24+
import org.eclipse.chemclipse.swt.ui.notifier.UpdateNotifierUI;
25+
import org.eclipse.chemclipse.swt.ui.support.Colors;
2326
import org.eclipse.chemclipse.ux.extension.ui.model.IDataUpdateListener;
2427
import org.eclipse.chemclipse.ux.extension.ui.support.DataUpdateSupport;
2528
import org.eclipse.chemclipse.ux.extension.ui.swt.IExtendedPartUI;
@@ -31,17 +34,24 @@
3134
import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.Activator;
3235
import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.chart2d.ScorePlotBarChart;
3336
import org.eclipse.swt.SWT;
37+
import org.eclipse.swt.events.PaintEvent;
3438
import org.eclipse.swt.events.SelectionAdapter;
3539
import org.eclipse.swt.events.SelectionEvent;
40+
import org.eclipse.swt.graphics.GC;
41+
import org.eclipse.swt.graphics.Point;
3642
import org.eclipse.swt.layout.GridData;
3743
import org.eclipse.swt.layout.GridLayout;
3844
import org.eclipse.swt.widgets.Combo;
3945
import org.eclipse.swt.widgets.Composite;
4046
import org.eclipse.swt.widgets.Event;
4147
import org.eclipse.swt.widgets.Label;
48+
import org.eclipse.swt.widgets.Scrollable;
49+
import org.eclipse.swtchart.ICustomPaintListener;
50+
import org.eclipse.swtchart.IPlotArea;
4251
import org.eclipse.swtchart.extensions.core.BaseChart;
4352
import org.eclipse.swtchart.extensions.core.IChartSettings;
4453
import org.eclipse.swtchart.extensions.core.IMouseSupport;
54+
import org.eclipse.swtchart.extensions.core.UserSelection;
4555
import org.eclipse.swtchart.extensions.events.IHandledEventProcessor;
4656

4757
public class ExtendedScorePlotBarChart extends Composite implements IExtendedPartUI {
@@ -51,7 +61,7 @@ public class ExtendedScorePlotBarChart extends Composite implements IExtendedPar
5161
private EvaluationPCA evaluationPCA = null;
5262
private int currentPC = 0;
5363
private Composite control;
54-
@SuppressWarnings("unused")
64+
private UserSelection userSelection = new UserSelection();
5565
private ISamplesPCA<IVariable, ISample> samples = null;
5666

5767
public ExtendedScorePlotBarChart(Composite parent, int style) {
@@ -171,10 +181,7 @@ public void handleEvent(BaseChart baseChart, Event event) {
171181

172182
if(evaluationPCA != null) {
173183

174-
// Convert pixel coordinates to data coordinates
175184
double xValue = baseChart.getAxisSet().getXAxis(BaseChart.ID_PRIMARY_X_AXIS).getDataCoordinate(event.x);
176-
177-
// Create list of sample-score pairs
178185
IResultsMVA results = evaluationPCA.getResults();
179186
List<IResultMVA> resultList = results.getPcaResultList();
180187
List<SampleScore> sampleScores = new ArrayList<>();
@@ -189,11 +196,8 @@ public void handleEvent(BaseChart baseChart, Event event) {
189196
}
190197
}
191198

192-
// Sort by score value (descending: positive to negative)
193199
sampleScores.sort(Comparator.comparingDouble(SampleScore::getScore).reversed());
194-
195200
int barIndex = (int)Math.round(xValue);
196-
197201
if(barIndex >= 0 && barIndex < sampleScores.size()) {
198202
String sampleName = sampleScores.get(barIndex).getSampleName();
199203
String tooltip = "Sample: " + sampleName + "\nValue: " + String.format("%.2f", sampleScores.get(barIndex).getScore());
@@ -205,9 +209,248 @@ public void handleEvent(BaseChart baseChart, Event event) {
205209
}
206210

207211
});
212+
chartSettings.addHandledEventProcessor(new IHandledEventProcessor() {
213+
214+
@Override
215+
public int getEvent() {
216+
217+
return IMouseSupport.EVENT_MOUSE_DOWN;
218+
}
219+
220+
@Override
221+
public int getButton() {
222+
223+
return IMouseSupport.MOUSE_BUTTON_LEFT;
224+
}
225+
226+
@Override
227+
public int getStateMask() {
228+
229+
return SWT.MOD1;
230+
}
231+
232+
@Override
233+
public void handleEvent(BaseChart baseChart, Event event) {
234+
235+
if(evaluationPCA != null) {
236+
if(event.count == 1) {
237+
userSelection.setSingleClick(true);
238+
userSelection.setStartCoordinate(event.x, event.y);
239+
}
240+
}
241+
}
242+
});
243+
chartSettings.addHandledEventProcessor(new IHandledEventProcessor() {
244+
245+
@Override
246+
public int getEvent() {
247+
248+
return IMouseSupport.EVENT_MOUSE_MOVE;
249+
}
250+
251+
@Override
252+
public int getButton() {
253+
254+
return IMouseSupport.MOUSE_BUTTON_NONE;
255+
}
256+
257+
@Override
258+
public int getStateMask() {
259+
260+
return SWT.MOD1;
261+
}
262+
263+
@Override
264+
public void handleEvent(BaseChart baseChart, Event event) {
265+
266+
if(userSelection.getStartX() > 0 && userSelection.getStartY() > 0) {
267+
userSelection.setStopCoordinate(event.x, event.y);
268+
}
269+
}
270+
});
271+
chartSettings.addHandledEventProcessor(new IHandledEventProcessor() {
272+
273+
@Override
274+
public int getEvent() {
275+
276+
return IMouseSupport.EVENT_MOUSE_UP;
277+
}
278+
279+
@Override
280+
public int getButton() {
281+
282+
return IMouseSupport.MOUSE_BUTTON_LEFT;
283+
}
284+
285+
@Override
286+
public int getStateMask() {
287+
288+
return SWT.MOD1;
289+
}
290+
291+
@Override
292+
public void handleEvent(BaseChart baseChart, Event event) {
293+
294+
if(evaluationPCA != null && isBoxSelection()) {
295+
int pXStart = (int)baseChart.getAxisSet().getXAxis(BaseChart.ID_PRIMARY_X_AXIS).getDataCoordinate(userSelection.getStartX());
296+
int pXStop = (int)baseChart.getAxisSet().getXAxis(BaseChart.ID_PRIMARY_X_AXIS).getDataCoordinate(userSelection.getStopX());
297+
298+
if(pXStart > pXStop) {
299+
int flip = pXStart;
300+
pXStart = pXStop;
301+
pXStop = flip;
302+
}
303+
IResultsMVA results = evaluationPCA.getResults();
304+
List<IResultMVA> resultList = results.getPcaResultList();
305+
List<SampleScore> sampleScores = new ArrayList<>();
306+
for(IResultMVA result : resultList) {
307+
ISample sample = result.getSample();
308+
double[] scoreMatrix = result.getScoreVector();
309+
310+
if(currentPC < scoreMatrix.length) {
311+
double score = scoreMatrix[currentPC];
312+
String sampleName = sample.getSampleName();
313+
sampleScores.add(new SampleScore(sampleName, score));
314+
}
315+
}
316+
sampleScores.sort(Comparator.comparingDouble(SampleScore::getScore).reversed());
317+
List<ISample> samplesHighlighted = evaluationPCA.getHighlightedSamples();
318+
for(int i = pXStart; i <= pXStop; i++) {
319+
String currentSampleName = sampleScores.get(i).getSampleName();
320+
int index = IntStream.range(0, samplesHighlighted.size()).filter(x -> samplesHighlighted.get(x).getSampleName().equals(currentSampleName)).findFirst().orElse(-1);
321+
if(index == -1) {
322+
samplesHighlighted.add(samples.getSamples().stream().filter(x -> x.getSampleName().equals(currentSampleName)).findFirst().get());
323+
} else {
324+
samplesHighlighted.remove(index);
325+
}
326+
327+
}
328+
329+
if(!samplesHighlighted.isEmpty()) {
330+
UpdateNotifierUI.update(event.display, IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_SAMPLE, samplesHighlighted.toArray());
331+
}
332+
333+
userSelection.reset();
334+
userSelection.setSingleClick(false);
335+
}
336+
337+
}
338+
339+
});
340+
341+
chartSettings.addHandledEventProcessor(new IHandledEventProcessor() {
342+
343+
@Override
344+
public int getEvent() {
345+
346+
return IMouseSupport.EVENT_MOUSE_DOUBLE_CLICK;
347+
}
348+
349+
@Override
350+
public int getButton() {
351+
352+
return IMouseSupport.MOUSE_BUTTON_LEFT;
353+
}
354+
355+
@Override
356+
public int getStateMask() {
357+
358+
return SWT.NONE;
359+
}
360+
361+
@Override
362+
public void handleEvent(BaseChart baseChart, Event event) {
363+
364+
if(evaluationPCA != null) {
365+
int clickIndex = (int)baseChart.getAxisSet().getXAxis(BaseChart.ID_PRIMARY_X_AXIS).getDataCoordinate(event.x);
366+
367+
List<SampleScore> sampleScores = getSampleScoreList();
368+
List<ISample> highlightedSamples = new ArrayList<>();
369+
List<ISample> samplesHighlighted = evaluationPCA.getHighlightedSamples();
370+
371+
String currentSampleName = sampleScores.get(clickIndex).getSampleName();
372+
int sampleIndex = IntStream.range(0, samplesHighlighted.size()).filter(x -> samplesHighlighted.get(x).getSampleName().equals(currentSampleName)).findFirst().orElse(-1);
373+
if(sampleIndex == -1) {
374+
highlightedSamples.add(samples.getSamples().stream().filter(x -> x.getSampleName().equals(currentSampleName)).findFirst().get());
375+
UpdateNotifierUI.update(event.display, IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_SAMPLE, highlightedSamples.toArray());
376+
} else {
377+
UpdateNotifierUI.update(event.display, IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_SAMPLE, highlightedSamples.toArray());
378+
}
379+
}
380+
}
381+
});
382+
chartSettings.addHandledEventProcessor(new IHandledEventProcessor() {
383+
384+
@Override
385+
public int getEvent() {
386+
387+
return IMouseSupport.EVENT_MOUSE_DOUBLE_CLICK;
388+
}
389+
390+
@Override
391+
public int getButton() {
392+
393+
return IMouseSupport.MOUSE_BUTTON_LEFT;
394+
}
395+
396+
@Override
397+
public int getStateMask() {
398+
399+
return SWT.MOD1;
400+
}
401+
402+
@Override
403+
public void handleEvent(BaseChart baseChart, Event event) {
404+
405+
if(evaluationPCA != null) {
406+
int clickIndex = (int)baseChart.getAxisSet().getXAxis(BaseChart.ID_PRIMARY_X_AXIS).getDataCoordinate(event.x);
407+
408+
List<SampleScore> sampleScores = getSampleScoreList();
409+
List<ISample> samplesHighlighted = evaluationPCA.getHighlightedSamples();
410+
411+
String currentSampleName = sampleScores.get(clickIndex).getSampleName();
412+
int sampleIndex = IntStream.range(0, samplesHighlighted.size()).filter(x -> samplesHighlighted.get(x).getSampleName().equals(currentSampleName)).findFirst().orElse(-1);
413+
if(sampleIndex == -1) {
414+
samplesHighlighted.add(samples.getSamples().stream().filter(x -> x.getSampleName().equals(currentSampleName)).findFirst().get());
415+
UpdateNotifierUI.update(event.display, IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_SAMPLE, samplesHighlighted.toArray());
416+
} else {
417+
samplesHighlighted.remove(sampleIndex);
418+
UpdateNotifierUI.update(event.display, IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_SAMPLE, samplesHighlighted.toArray());
419+
}
420+
}
421+
userSelection.reset();
422+
}
423+
});
208424

209425
chart.applySettings(chartSettings);
210426

427+
chart.getBaseChart().getPlotArea().addCustomPaintListener(new ICustomPaintListener() {
428+
429+
@Override
430+
public void paintControl(PaintEvent e) {
431+
432+
if(userSelection.isActive()) {
433+
int xMin = Math.min(userSelection.getStartX(), userSelection.getStopX());
434+
int xMax = Math.max(userSelection.getStartX(), userSelection.getStopX());
435+
int y = Math.min(userSelection.getStartY(), userSelection.getStopY());
436+
BaseChart baseChart = chartControl.get().getBaseChart();
437+
IPlotArea plotArea = baseChart.getPlotArea();
438+
Point rectangle = plotArea instanceof Scrollable scrollable ? scrollable.getSize() : plotArea.getSize();
439+
440+
GC gc = e.gc;
441+
gc.setBackground(Colors.RED);
442+
gc.setForeground(Colors.DARK_RED);
443+
gc.setAlpha(45);
444+
gc.setLineStyle(SWT.LINE_DASH);
445+
gc.setLineWidth(2);
446+
gc.drawLine(xMin, 0, xMin, rectangle.y);
447+
gc.drawLine(xMax, 0, xMax, rectangle.y);
448+
gc.drawLine(xMin, y, xMax, y);
449+
}
450+
}
451+
452+
});
453+
211454
chartControl.set(chart);
212455
}
213456

@@ -288,4 +531,32 @@ public double getScore() {
288531
return score;
289532
}
290533
}
534+
535+
private boolean isBoxSelection() {
536+
537+
if(userSelection.getStartX() != 0 && userSelection.getStartY() != 0 && userSelection.getStopX() != 0 && userSelection.getStopY() != 0) {
538+
return true;
539+
}
540+
return false;
541+
}
542+
543+
private List<SampleScore> getSampleScoreList() {
544+
545+
IResultsMVA results = evaluationPCA.getResults();
546+
List<IResultMVA> resultList = results.getPcaResultList();
547+
List<SampleScore> sampleScores = new ArrayList<>();
548+
for(IResultMVA result : resultList) {
549+
ISample sample = result.getSample();
550+
double[] scoreMatrix = result.getScoreVector();
551+
552+
if(currentPC < scoreMatrix.length) {
553+
double score = scoreMatrix[currentPC];
554+
String sampleName = sample.getSampleName();
555+
sampleScores.add(new SampleScore(sampleName, score));
556+
}
557+
}
558+
559+
sampleScores.sort(Comparator.comparingDouble(SampleScore::getScore).reversed());
560+
return sampleScores;
561+
}
291562
}

0 commit comments

Comments
 (0)