$darkmode
DENOPTIM
GUIInspectFSERun.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2020 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.gui;
20
21
22import java.awt.BorderLayout;
23import java.awt.CardLayout;
24import java.awt.Color;
25import java.awt.Cursor;
26import java.awt.Dimension;
27import java.awt.FlowLayout;
28import java.awt.GridLayout;
29import java.awt.Shape;
30import java.awt.event.ActionEvent;
31import java.awt.event.ActionListener;
32import java.awt.event.ComponentAdapter;
33import java.awt.event.ComponentEvent;
34import java.awt.geom.Ellipse2D;
35import java.io.File;
36import java.io.FileFilter;
37import java.util.ArrayList;
38import java.util.Comparator;
39import java.util.HashMap;
40import java.util.List;
41import java.util.Map;
42import java.util.concurrent.atomic.AtomicInteger;
43
44import javax.swing.DefaultListModel;
45import javax.swing.GroupLayout;
46import javax.swing.JButton;
47import javax.swing.JCheckBox;
48import javax.swing.JComboBox;
49import javax.swing.JComponent;
50import javax.swing.JLabel;
51import javax.swing.JList;
52import javax.swing.JOptionPane;
53import javax.swing.JPanel;
54import javax.swing.JScrollPane;
55import javax.swing.JSplitPane;
56import javax.swing.ListSelectionModel;
57import javax.swing.SwingConstants;
58import javax.swing.UIManager;
59
60import org.jfree.chart.ChartFactory;
61import org.jfree.chart.ChartMouseEvent;
62import org.jfree.chart.ChartMouseListener;
63import org.jfree.chart.ChartPanel;
64import org.jfree.chart.JFreeChart;
65import org.jfree.chart.editor.ChartEditor;
66import org.jfree.chart.editor.ChartEditorManager;
67import org.jfree.chart.entity.PlotEntity;
68import org.jfree.chart.entity.XYItemEntity;
69import org.jfree.chart.labels.XYToolTipGenerator;
70import org.jfree.chart.plot.DatasetRenderingOrder;
71import org.jfree.chart.plot.PlotOrientation;
72import org.jfree.chart.plot.SeriesRenderingOrder;
73import org.jfree.chart.plot.XYPlot;
74import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
75import org.jfree.data.xy.DefaultXYDataset;
76import org.jfree.data.xy.XYDataset;
77
78import denoptim.constants.DENOPTIMConstants;
79import denoptim.exception.DENOPTIMException;
80import denoptim.graph.CandidateLW;
81import denoptim.io.DenoptimIO;
82
83
91public class GUIInspectFSERun extends GUICardPanel
92{
96 private static final long serialVersionUID = 2245706077350445364L;
97
101 public static AtomicInteger fseInspectorTabUID = new AtomicInteger(1);
102
103 private JPanel ctrlPanel;
104 private JPanel ctrlPanelLeft;
105 private JPanel ctrlPanelRight;
106 private JSplitPane centralPanel;
107 private JPanel rightPanel;
109 private JPanel chartHolderPanel;
110
111 private JComboBox<String> cmbPlotType;
112
113 private ArrayList<CandidateLW> allItems;
114 private int itemsWithFitness = 0;
115 private int minLevel = 1;
116 private int maxLevel = -1;
117 private JLabel lblTotItems;
118
119 private Map<Integer,CandidateLW> mapItemsInByLevel;
120 private ArrayList<CandidateLW> sorted;
121
122 // WARNING: integer key in the map is is just a
123 // locally generated unique
124 // identifier that has NO RELATION to level/molId/fitness
125 // The Map 'mapCandsInByLevel' serve specifically to convert
126 // the unique key into a DENOPTIMMolecule
127
128 private DefaultXYDataset datasetAllFit;
129 private DefaultXYDataset datasetSorted;
130 private DefaultXYDataset datasetSelectedLev = new DefaultXYDataset();
131 private DefaultXYDataset datasetSelectedOrd = new DefaultXYDataset();
132
133 private JFreeChart chartByLevel;
134 private JFreeChart chartBySorted;
135 private ChartPanel chartPanelByLevel;
136 private ChartPanel chartPanelSorted;
137
142 private JButton openGraph;
143
149 private String pathToSelectedItem;
150
151//-----------------------------------------------------------------------------
152
157 {
158 super(mainPanel, "FSERun Inspector #"
159 + fseInspectorTabUID.getAndIncrement());
160 super.setLayout(new BorderLayout());
161 initialize();
162 }
163
164//-----------------------------------------------------------------------------
165
169 private void initialize()
170 {
171 // BorderLayout is needed to allow dynamic resizing!
172 this.setLayout(new BorderLayout());
173
174 // The Card has
175 // -> its own toolbar
176 // -> a central panel vertically divided in two
177 // |-> mol/graph viewers? (LEFT)
178 // |-> plot (RIGHT)
179
180 // Creating local tool bar
181 ctrlPanelLeft = new JPanel(new FlowLayout(FlowLayout.LEFT));
182 JButton rstView = new JButton("Reset Chart View");
183 rstView.addActionListener(new ActionListener() {
184 public void actionPerformed(ActionEvent e) {
185 resetView();
186 }
187 });
188 ctrlPanelLeft.add(rstView);
189
190 cmbPlotType = new JComboBox<String>(new String[] {
191 "Plot Sorted List of Candidates",
192 "Plot Candidates by Level"});
193 cmbPlotType.addActionListener(new ActionListener() {
194 public void actionPerformed(ActionEvent e) {
195 if (cmbPlotType.getSelectedIndex() == 0)
196 {
197 ((CardLayout) chartHolderPanel.getLayout()).show(chartHolderPanel,
198 "sorted");
199 }
200 else
201 {
202 ((CardLayout) chartHolderPanel.getLayout()).show(chartHolderPanel,
203 "byLevel");
204 }
205 }
206 });
208
209 openGraph = new JButton("Open Candidate's Graph");
210 openGraph.setEnabled(false); //Enables only upon selection of an item
211 openGraph.setToolTipText("Open a new tab for inspecting the "
212 + "DENOPTIMGraph of the selected candidate.");
213 openGraph.addActionListener(new ActionListener() {
214 public void actionPerformed(ActionEvent e) {
215 mainPanel.setCursor(Cursor.getPredefinedCursor(
216 Cursor.WAIT_CURSOR));
217 GUIGraphHandler graphPanel = new GUIGraphHandler(mainPanel);
218 mainPanel.add(graphPanel);
219 graphPanel.importGraphsFromFile(new File(pathToSelectedItem));
220 mainPanel.setCursor(Cursor.getPredefinedCursor(
221 Cursor.DEFAULT_CURSOR));
222 }
223 });
225
226 ctrlPanelRight = new JPanel(new FlowLayout(FlowLayout.RIGHT));
227 lblTotItems = new JLabel("No item loaded");
228 lblTotItems.setHorizontalAlignment(SwingConstants.RIGHT);
229 lblTotItems.setPreferredSize(new Dimension(300,28));
231 ctrlPanel = new JPanel();
232 GroupLayout lyoCtrlPanel = new GroupLayout(ctrlPanel);
233 ctrlPanel.setLayout(lyoCtrlPanel);
234 lyoCtrlPanel.setAutoCreateGaps(true);
235 lyoCtrlPanel.setAutoCreateContainerGaps(true);
236 lyoCtrlPanel.setHorizontalGroup(lyoCtrlPanel.createSequentialGroup()
237 .addComponent(ctrlPanelLeft)
238 .addComponent(ctrlPanelRight));
239 lyoCtrlPanel.setVerticalGroup(lyoCtrlPanel.createParallelGroup()
240 .addComponent(ctrlPanelLeft)
241 .addComponent(ctrlPanelRight));
242 this.add(ctrlPanel,BorderLayout.NORTH);
243
244 // Setting structure of central panel
245 centralPanel = new JSplitPane();
246 centralPanel.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
247 centralPanel.setOneTouchExpandable(true);
248 rightPanel = new JPanel();
249 rightPanel.setLayout(new BorderLayout());
250 centralPanel.setRightComponent(rightPanel);
252 centralPanel.setLeftComponent(molViewer);
253 centralPanel.setDividerLocation(300);
254 this.add(centralPanel,BorderLayout.CENTER);
255
256 // Button to the bottom of the card
257 ButtonsBar commandsPane = new ButtonsBar();
258 this.add(commandsPane, BorderLayout.SOUTH);
259 JButton btnCanc = new JButton("Close Tab");
260 btnCanc.setToolTipText("Closes this FSERun Inspector.");
261 btnCanc.addActionListener(new removeCardActionListener(this));
262 commandsPane.add(btnCanc);
263
264 JButton btnHelp = new JButton("?");
265 btnHelp.setToolTipText("<html>Hover over buttons and fields "
266 + "to get a tip.<br>"
267 + "Click the '?' button for further instructions.</html>");
268 btnHelp.addActionListener(new ActionListener() {
269 public void actionPerformed(ActionEvent e) {
270 String txt = "<html><body width='%1s'>"
271 + "<p>Selection of candidates:"
272 + "<ul>"
273 + "<li>Click on a dot in the chart to disply the "
274 + "corresponding molecular "
275 + "representation.</li>"
276 + "<li>Click away from any dot to reset the molecular "
277 + "viewer."
278 + "</li></ul></p>"
279 + "<p>Chart view:"
280 + "<ul>"
281 + "<li>zoom in: click-and-drag "
282 + "from the top-left to the bottom-right "
283 + "corners of the new region of the plot to focus on."
284 + "</li>"
285 + "<li>Use the <code>Reset Chart View</code> to reset "
286 + "the view.</li>"
287 + "<li>Right-click to get advanced controls and "
288 + "options</li>"
289 + "</ul></p>"
290 + "</body></html>";
291 JOptionPane.showMessageDialog(btnHelp, String.format(txt, 300),
292 "Tips",
293 JOptionPane.PLAIN_MESSAGE);
294 }
295 });
296 commandsPane.add(btnHelp);
297
298 }
299
300//-----------------------------------------------------------------------------
301
302 private void resetView()
303 {
304 if (cmbPlotType.getSelectedIndex() == 1)
305 {
307 }
308 else
309 {
311 }
312 }
313
314//-----------------------------------------------------------------------------
315
317 {
318 chartByLevel.getXYPlot().getRangeAxis().setAutoRange(true);
319 chartByLevel.getXYPlot().getDomainAxis().setLowerBound(
320 minLevel-0.5);
321 chartByLevel.getXYPlot().getDomainAxis().setUpperBound(
322 maxLevel+0.5);
323 }
324
325//-----------------------------------------------------------------------------
326
328 {
329 chartBySorted.getXYPlot().getDomainAxis().setLowerBound(
330 itemsWithFitness * -0.05);
331 chartBySorted.getXYPlot().getDomainAxis().setUpperBound(
332 itemsWithFitness * 1.05);
333 chartBySorted.getXYPlot().getRangeAxis().setAutoRange(true);
334 }
335
336//-----------------------------------------------------------------------------
337
338 public void importFSERunData(File folder) {
339
340 if (!folder.isDirectory() || !folder.exists())
341 {
342 JOptionPane.showMessageDialog(this,
343 "Could not read data from folder '" + folder+ "'!",
344 "Error",
345 JOptionPane.PLAIN_MESSAGE,
346 UIManager.getIcon("OptionPane.errorIcon"));
347 return;
348 }
349 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
350
351 System.out.println("Importing data from '" + folder + "'... ");
352
353 allItems = new ArrayList<CandidateLW>();
354 boolean skippFurtherErrors = false;
355 for (File itemFile : folder.listFiles(new FileFilter() {
356
357 @Override
358 public boolean accept(File pathname) {
359 if (pathname.getName().startsWith(
361 && pathname.getName().endsWith(
363 && !pathname.isDirectory())
364 {
365 return true;
366 }
367 return false;
368 }
369 }))
370 {
371 CandidateLW item = null;
372 try {
373 //WARNING: here we assume one candidate per file
374 item = DenoptimIO.readLightWeightCandidate(itemFile).get(0);
375 } catch (DENOPTIMException e1) {
376 if (!skippFurtherErrors)
377 {
378 e1.printStackTrace();
379 mainPanel.setCursor(Cursor.getPredefinedCursor(
380 Cursor.DEFAULT_CURSOR));
381
382 JPanel msgPanel = new JPanel(new GridLayout(2, 1));
383 String msg = "<html><body width='%1s'>Could not read data "
384 + "from '" + itemFile + "'. Hint on cause: "
385 + e1.getMessage() + " Should we try to "
386 + "visualize the results anyway?</html>";
387 JLabel text = new JLabel(String.format(msg, 450));
388 JCheckBox cb = new JCheckBox("Remember decision");
389 cb.setSelected(false);
390 msgPanel.add(text);
391 msgPanel.add(cb);
392 String[] options = new String[]{"Yes", "Abandon"};
393 int res = JOptionPane.showOptionDialog(this,
394 msgPanel,
395 "ERROR",
396 JOptionPane.DEFAULT_OPTION,
397 JOptionPane.QUESTION_MESSAGE,
398 UIManager.getIcon("OptionPane.errorIcon"),
399 options,
400 options[1]);
401 if (cb.isSelected())
402 {
403 skippFurtherErrors = true;
404 }
405 switch (res)
406 {
407 case 0:
408 break;
409
410 case 1:
411 return;
412 }
413 }
414 }
415
416 if (item.hasFitness())
417 {
419 }
420
421 int lev = item.getLevel();
422 if (lev > maxLevel)
423 {
424 maxLevel = lev;
425 } else if (lev < minLevel)
426 {
427 minLevel = lev;
428 }
429
430 allItems.add(item);
431 }
432
433 System.out.println("Imported "+allItems.size()+" individuals.");
434
435 lblTotItems.setText("Found "+allItems.size()+" candidates ("
436 +itemsWithFitness+" with fitness)");
437
438 // Process data and organize them into series for the plot
439 double[][] itemsWithFitnessDataPerLevel = new double[2][itemsWithFitness];
440 mapItemsInByLevel = new HashMap<Integer,CandidateLW>();
441 int j= -1;
442 for (int i=0; i<allItems.size(); i++)
443 {
444 CandidateLW item = allItems.get(i);
445 if (!item.hasFitness())
446 {
447 continue;
448 }
449
450 // WARNING: itemId in the data is "j" and is just a unique
451 // identifier that has NO RELATION to generation/molId/fitness
452 // The Map 'mapCandsInByLevel' serve specifically to convert
453 // the itemId 'j' into a DENOPTIMMolecule
454
455 j++;
456 mapItemsInByLevel.put(j, item);
457 itemsWithFitnessDataPerLevel[0][j] = item.getLevel();
458 itemsWithFitnessDataPerLevel[1][j] = item.getFitness();
459 }
460
461 sorted = new ArrayList<CandidateLW>();
462 sorted.addAll(mapItemsInByLevel.values());
463 sorted.sort(new Comparator<CandidateLW>() {
464 public int compare(CandidateLW a, CandidateLW b) {
465 return Double.compare(a.getFitness(),
466 b.getFitness());
467 }
468 });
469 allItems.sort(new Comparator<CandidateLW>() {
470 public int compare(CandidateLW c1, CandidateLW c2) {
471 int byGen = Integer.compare(c1.getLevel(),
472 c2.getLevel());
473 if (byGen!=0)
474 return byGen;
475 if (c1.hasFitness() && c2.hasFitness())
476 return Double.compare(c1.getFitness(), c2.getFitness());
477 else if (c1.hasFitness())
478 return 1;
479 else if (c2.hasFitness())
480 return -1;
481 return 0;
482 }
483 });
484
485 double[][] itemsWithFitnessDataSorted = new double[2][itemsWithFitness];
486 for (int i=0; i<itemsWithFitness; i++)
487 {
488 CandidateLW item = sorted.get(i);
489 itemsWithFitnessDataSorted[0][i] = i;
490 itemsWithFitnessDataSorted[1][i] = item.getFitness();
491 }
492
493 datasetAllFit = new DefaultXYDataset();
494 datasetAllFit.addSeries("Candidates_with_fitness",
495 itemsWithFitnessDataPerLevel);
496
497 datasetSorted = new DefaultXYDataset();
498 datasetSorted.addSeries("Sorted_candidates",
499 itemsWithFitnessDataSorted);
500
501 //TODO: somehow collect and display the candidates that hit a mol error
502 // Could it be a histogram (#failed x level) below the levels plot
503 // Failed items should be selectable by click, to allow
504 // visualization.
505
506 chartByLevel = ChartFactory.createScatterPlot(
507 null, // plot title
508 "Level", // x axis label
509 "Fitness", // y axis label
510 datasetAllFit, // all items with fitness
511 PlotOrientation.VERTICAL,
512 false, // include legend
513 false, // tool tips
514 false // urls
515 );
516
517 chartBySorted = ChartFactory.createScatterPlot(
518 null, // plot title
519 "", // x axis label
520 "Fitness", // y axis label
521 datasetSorted, // all items with fitness
522 PlotOrientation.VERTICAL,
523 false, // include legend
524 false, // tool tips
525 false // urls
526 );
527
528 // Chart appearance
529 XYPlot plotBL = (XYPlot) chartByLevel.getPlot();
530 plotBL.getDomainAxis().setLowerBound(-0.5); //min X-axis
531 plotBL.setBackgroundPaint(Color.WHITE);
532 plotBL.setDomainGridlinePaint(Color.LIGHT_GRAY);
533 plotBL.setRangeGridlinePaint(Color.LIGHT_GRAY);
534 plotBL.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD);
535 plotBL.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
536 // main dataset (all items with fitness)
537 Shape shape0 = new Ellipse2D.Double(
542 XYLineAndShapeRenderer renderer0 =
543 (XYLineAndShapeRenderer) plotBL.getRenderer();
544 renderer0.setSeriesShape(0, shape0);
545 renderer0.setSeriesPaint(0, new Color(192, 192, 192, 60));
546 renderer0.setSeriesFillPaint(0, new Color(192, 192, 192, 60));
547 renderer0.setSeriesOutlinePaint(0, Color.GRAY);
548 renderer0.setUseOutlinePaint(true);
549 renderer0.setUseFillPaint(true);
550
551 // dataset of selected items
552 Shape shape1 = new Ellipse2D.Double(
557 XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer();
558 //now the dataset of selected is null. Created upon selection
559 plotBL.setRenderer(1, renderer1);
560 renderer1.setSeriesShape(0, shape1);
561 renderer1.setSeriesPaint(0, Color.red);
562 renderer1.setSeriesFillPaint(0, Color.red);
563 renderer1.setSeriesOutlinePaint(0, Color.BLACK);
564 renderer1.setUseOutlinePaint(true);
565 renderer1.setUseFillPaint(true);
566
567 // Chart appearance for chart of sorted
568 XYPlot plotS = (XYPlot) chartBySorted.getPlot();
569 plotS.getDomainAxis().setLowerBound(-0.5); //min X-axis
570 plotS.setBackgroundPaint(Color.WHITE);
571 plotS.setDomainGridlinePaint(Color.LIGHT_GRAY);
572 plotS.setRangeGridlinePaint(Color.LIGHT_GRAY);
573 plotS.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD);
574 plotS.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
575 // main dataset (all items with fitness)
576 XYLineAndShapeRenderer rendererS0 =
577 (XYLineAndShapeRenderer) plotS.getRenderer();
578 rendererS0.setSeriesShape(0, shape0);
579 rendererS0.setSeriesPaint(0, Color.decode("#848482"));
580 rendererS0.setSeriesOutlinePaint(0, Color.gray);
581
582 // dataset of selected items
583 XYLineAndShapeRenderer rendererS1 = new XYLineAndShapeRenderer();
584 plotS.setRenderer(1, rendererS1);
585 rendererS1.setSeriesShape(0, shape1);
586 rendererS1.setSeriesPaint(0, Color.red);
587 rendererS1.setSeriesFillPaint(0, Color.red);
588 rendererS1.setSeriesOutlinePaint(0, Color.BLACK);
589 rendererS1.setUseOutlinePaint(true);
590 rendererS1.setUseFillPaint(true);
591
592 // Create the actual panels that contains the charts
593 chartPanelSorted = new ChartPanel(chartBySorted);
595 chartPanelByLevel = new ChartPanel(chartByLevel);
597
598 // Adapt chart size to the size of the panel
599 rightPanel.addComponentListener(new ComponentAdapter() {
600 @Override
601 public void componentResized(ComponentEvent e) {
602 chartPanelByLevel.setMaximumDrawHeight(
603 e.getComponent().getHeight());
604 chartPanelByLevel.setMaximumDrawWidth(
605 e.getComponent().getWidth());
606 chartPanelByLevel.setMinimumDrawWidth(
607 e.getComponent().getWidth());
608 chartPanelByLevel.setMinimumDrawHeight(
609 e.getComponent().getHeight());
610 chartPanelSorted.setMaximumDrawHeight(
611 e.getComponent().getHeight());
612 chartPanelSorted.setMaximumDrawWidth(
613 e.getComponent().getWidth());
614 chartPanelSorted.setMinimumDrawWidth(
615 e.getComponent().getWidth());
616 chartPanelSorted.setMinimumDrawHeight(
617 e.getComponent().getHeight());
618 // WARNING: this update is needed to make the new size affective
619 // also after movement of the JSplitPane divider, which is
620 // otherwise felt by this listener but the new sizes do not
621 // take effect.
622 ChartEditor ceL = ChartEditorManager.getChartEditor(
624 ceL.updateChart(chartByLevel);
625 ChartEditor ceS = ChartEditorManager.getChartEditor(
627 ceS.updateChart(chartBySorted);
628 }
629 });
630
631 // Setting toolTip when on top of an series item in the chart
632 //TODO deal with superposed points by adding all their names to tip text
633 XYToolTipGenerator ttg = new XYToolTipGenerator() {
634 public String generateToolTip(XYDataset data, int sId, int itemId)
635 {
636 return mapItemsInByLevel.get(itemId).getName();
637 }
638 };
639 chartByLevel.getXYPlot().getRenderer().setSeriesToolTipGenerator(0,
640 ttg);
641 chartBySorted.getXYPlot().getRenderer().setSeriesToolTipGenerator(0,
642 ttg);
643
644 // Click-based selection of item, possibly displaying mol structure
645 chartPanelByLevel.addChartMouseListener(new ChartMouseListener() {
646
647 public void chartMouseMoved(ChartMouseEvent e) {
648 //nothing to do
649 }
650
651 public void chartMouseClicked(ChartMouseEvent e)
652 {
653 if (e.getEntity() instanceof XYItemEntity)
654 {
655 int serId = ((XYItemEntity)e.getEntity()).getSeriesIndex();
656 if (serId == 0)
657 {
658 int itemId = ((XYItemEntity) e.getEntity()).getItem();
659 CandidateLW item = mapItemsInByLevel.get(itemId);
660
661 // The even can carry only one item, but there could be
662 // many items overlapping each other.
663 // Search for overlapping items and ask which one to the
664 // user wants to see.
665 int initPos = allItems.indexOf(item);
666 double tolerance = Math.abs(chartByLevel.getXYPlot()
667 .getRangeAxis().getRange().getLength() * 0.02);
668 int maxItems = 25;
669 int nItems = 0;
670 List<CandidateLW> overlappingItems =
671 new ArrayList<CandidateLW>();
672 while (nItems<maxItems &&
673 (initPos+nItems)<allItems.size())
674 {
675 CandidateLW c = allItems.get(initPos + nItems);
676 if (!c.hasFitness())
677 {
678 nItems++;
679 continue;
680 }
681 double delta = Math.abs(item.getFitness()
682 - c.getFitness());
683 if (delta > tolerance)
684 break;
685 overlappingItems.add(c);
686 nItems++;
687 }
688 nItems = 1;
689 while (nItems<maxItems && (initPos-nItems)>-1)
690 {
691 CandidateLW c = allItems.get(initPos - nItems);
692 if (!c.hasFitness())
693 {
694 nItems++;
695 continue;
696 }
697 double delta = Math.abs(item.getFitness()
698 - c.getFitness());
699 if (delta > tolerance)
700 break;
701 overlappingItems.add(0,c);
702 nItems++;
703 }
705 chartPanelByLevel, overlappingItems);
706 if (choosenItem!=null)
707 renderViewWithSelectedItem(choosenItem);
708 }
709 //do we do anything if we select other series? not now...
710 }
711 else if (e.getEntity() instanceof PlotEntity)
712 {
714 }
715 }
716 });
717
718 chartPanelSorted.addChartMouseListener(new ChartMouseListener() {
719
720 public void chartMouseMoved(ChartMouseEvent e) {
721 //nothing to do
722 }
723
724 public void chartMouseClicked(ChartMouseEvent e)
725 {
726 if (e.getEntity() instanceof XYItemEntity)
727 {
728 int serId = ((XYItemEntity)e.getEntity()).getSeriesIndex();
729 if (serId == 0)
730 {
731 int itemId = ((XYItemEntity) e.getEntity()).getItem();
732 CandidateLW item = sorted.get(itemId);
734 }
735 }
736 else if (e.getEntity() instanceof PlotEntity)
737 {
739 }
740 }
741 });
742
743 chartHolderPanel = new JPanel(new CardLayout());
744 chartPanelByLevel.setName("byLevel");
745 chartPanelSorted.setName("sorted");
746 chartHolderPanel.add(chartPanelByLevel,"byLevel");
748 ((CardLayout) chartHolderPanel.getLayout()).show(chartHolderPanel,
749 "sorted");
750 rightPanel.add(chartHolderPanel,BorderLayout.CENTER);
751
752 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
753 }
754
755
756//------------------------------------------------------------------------------
757
759 List<CandidateLW> overlappingItems)
760 {
761 switch (overlappingItems.size())
762 {
763 case 0:
764 return null;
765 case 1:
766 return overlappingItems.get(0);
767 }
768
769 DefaultListModel<String> listModel = new DefaultListModel<String>();
770 JList<String> optionsList = new JList<String>(listModel);
771 overlappingItems.stream().forEach(c -> listModel.addElement(c.getName()));
772 optionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
773
774 JPanel chooseItem = new JPanel();
775 JLabel header = new JLabel("Select item to visualize:");
776 JScrollPane scrollPane = new JScrollPane(optionsList);
777 chooseItem.add(header);
778 chooseItem.add(scrollPane);
779
780 int res = JOptionPane.showConfirmDialog(parent,
781 chooseItem,
782 "Choose Among Overlapping Items",
783 JOptionPane.OK_CANCEL_OPTION,
784 JOptionPane.PLAIN_MESSAGE,
785 null);
786 if (res != JOptionPane.OK_OPTION)
787 {
788 return null;
789 }
790 return overlappingItems.get(optionsList.getSelectedIndex());
791 }
792
793//-----------------------------------------------------------------------------
794
796 {
797 // NB: we just change the series of selected items
798 // The charts are updated automatically
799
800 double[][] selectedCandsDataLev = new double[2][1];
801 selectedCandsDataLev[0][0] = item.getLevel();
802 selectedCandsDataLev[1][0] = item.getFitness();
803 datasetSelectedLev.removeSeries("Selected_candidates");
804 datasetSelectedLev.addSeries("Selected_candidates", selectedCandsDataLev);
805 chartByLevel.getXYPlot().setDataset(1, datasetSelectedLev);
806
807 double[][] selectedCandsDataOrd = new double[2][1];
808 selectedCandsDataOrd[0][0] = sorted.indexOf(item);
809 selectedCandsDataOrd[1][0] = item.getFitness();
810 datasetSelectedOrd.removeSeries("Selected_candidates");
811 datasetSelectedOrd.addSeries("Selected_candidates", selectedCandsDataOrd);
812 chartBySorted.getXYPlot().setDataset(1, datasetSelectedOrd);
813
815 openGraph.setEnabled(true);
816
817 // Update the molecular viewer
819 }
820
821//-----------------------------------------------------------------------------
822
824 {
825 datasetSelectedLev.removeSeries("Selected_candidates");
826 datasetSelectedOrd.removeSeries("Selected_candidates");
827 //TODO: we could avoid 'zap-ping' jmol by covering it with an opaque card
828 molViewer.clearAll(false);
829 openGraph.setEnabled(false);
830 }
831
832//-----------------------------------------------------------------------------
833
834}
General set of constants used in DENOPTIM.
static final String FITFILENAMEPREFIX
Prefix of filenames for input/output files related to fitness.
static final String FITFILENAMEEXTOUT
Ending and extension of output file of external fitness provider.
A light-weight candidate is a very low-demanding collection of data upon a specific candidate item.
int getLevel()
Returns the level that generated this graph in a fragment space exploration experiment.
Standardised horizontal bar with padded components, which are meant to be JButtons.
Definition: ButtonsBar.java:36
Component add(Component comp)
Definition: ButtonsBar.java:53
Remove the card from the deck of cards and takes care of removing also the entry in the list of activ...
Class of GUI panels meant to occupy one card in the deck-of-cards layout of the main panel.
GUIMainPanel mainPanel
The main panel (cards deck)
A panel that understands DENOPTIM graphs and allows to create and edit them.
void importGraphsFromFile(File file)
Imports graphs from file.
A panel that allows to inspect the output of an combinatorial experiment exploring a fragment space.
static AtomicInteger fseInspectorTabUID
Unique identified for instances of this handler.
static final long serialVersionUID
Version UID.
JButton openGraph
Button offering the possibility to load the graph inspector for a selected item.
void renderViewWithSelectedItem(CandidateLW item)
String pathToSelectedItem
Storage of pathname to the item selected in the chart.
ArrayList< CandidateLW > allItems
void initialize()
Initialize the panel and add buttons.
GUIInspectFSERun(GUIMainPanel mainPanel)
Constructor.
Map< Integer, CandidateLW > mapItemsInByLevel
CandidateLW choseAmongPossiblyOverlapping(JComponent parent, List< CandidateLW > overlappingItems)
ArrayList< CandidateLW > sorted
The main panel is a deck of cards that occupies all the GUI frame.
Component add(Component comp)
Add a component and a reference to such component in the main tool bar.
The collection of tunable preferences.
static int chartPointSize
Evolutionary Inspector: size of points.
A panel with a molecular viewer and data table.
void clearAll(boolean dataIsComing)
Removes the currently visualized molecule and AP table.
void loadChemicalStructureFromFile(String pathName)
Loads a structure in the Jmol viewer.
Utility methods for input/output.
static List< CandidateLW > readLightWeightCandidate(File file)
Read only selected data from a GA produced items.