$darkmode
DENOPTIM
GUIInspectGARun.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.BasicStroke;
23import java.awt.BorderLayout;
24import java.awt.Color;
25import java.awt.Component;
26import java.awt.Cursor;
27import java.awt.Dimension;
28import java.awt.FlowLayout;
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.event.ItemEvent;
35import java.awt.event.ItemListener;
36import java.awt.geom.Ellipse2D;
37import java.io.File;
38import java.io.FileFilter;
39import java.io.IOException;
40import java.util.ArrayList;
41import java.util.Collections;
42import java.util.Comparator;
43import java.util.HashMap;
44import java.util.List;
45import java.util.Map;
46import java.util.concurrent.atomic.AtomicInteger;
47import java.util.stream.IntStream;
48
49import javax.swing.DefaultListModel;
50import javax.swing.GroupLayout;
51import javax.swing.JButton;
52import javax.swing.JCheckBox;
53import javax.swing.JCheckBoxMenuItem;
54import javax.swing.JComponent;
55import javax.swing.JLabel;
56import javax.swing.JList;
57import javax.swing.JOptionPane;
58import javax.swing.JPanel;
59import javax.swing.JPopupMenu;
60import javax.swing.JScrollPane;
61import javax.swing.JSplitPane;
62import javax.swing.JTextField;
63import javax.swing.ListSelectionModel;
64import javax.swing.SwingConstants;
65import javax.swing.UIManager;
66
67import org.jfree.chart.ChartMouseEvent;
68import org.jfree.chart.ChartMouseListener;
69import org.jfree.chart.ChartPanel;
70import org.jfree.chart.JFreeChart;
71import org.jfree.chart.axis.NumberAxis;
72import org.jfree.chart.editor.ChartEditor;
73import org.jfree.chart.editor.ChartEditorManager;
74import org.jfree.chart.entity.PlotEntity;
75import org.jfree.chart.entity.XYItemEntity;
76import org.jfree.chart.labels.XYToolTipGenerator;
77import org.jfree.chart.plot.DatasetRenderingOrder;
78import org.jfree.chart.plot.SeriesRenderingOrder;
79import org.jfree.chart.plot.XYPlot;
80import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
81import org.jfree.chart.ui.RectangleEdge;
82import org.jfree.data.xy.DefaultXYDataset;
83import org.jfree.data.xy.XYDataset;
84
85import denoptim.constants.DENOPTIMConstants;
86import denoptim.exception.DENOPTIMException;
87import denoptim.files.FileUtils;
88import denoptim.graph.CandidateLW;
89import denoptim.io.DenoptimIO;
90import denoptim.logging.CounterID;
91import denoptim.utils.GeneralUtils;
92
93
101public class GUIInspectGARun extends GUICardPanel
102{
106 private static final long serialVersionUID = -8303012362366503382L;
107
111 public static AtomicInteger evolInspectorTabUID = new AtomicInteger(1);
112
113 private JPanel ctrlPanel;
114 private JPanel ctrlPanelRow1;
115 private JPanel ctrlPanelRow1Left;
116 private JPanel ctrlPanelRow1Right;
117 private JPanel ctrlPanelRow2Left;
118 private JSplitPane centralPanel;
119 private JSplitPane rightPanel;
120 private JPanel rightUpPanel;
121 private JPanel rightDownPanel;
123
124 private File srcFolder;
125
126 private ArrayList<CandidateLW> allIndividuals;
127 private int molsWithFitness = 0;
128 private boolean warnedAboutMissingCandFiles = false;
129 private JLabel lblTotItems;
130 private Map<Integer,CandidateLW> candsWithFitnessMap;
131
132 // WARNING: itemId in the map is "j" and is just a
133 // locally generated unique
134 // identifier that has NO RELATION to generation/molId/fitness
135 // The Map 'candsWithFitnessMap' serve specifically to convert
136 // the itemId 'j' into a reference to the appropriate object.
137
138 private DefaultXYDataset datasetAllFit = new DefaultXYDataset();;
139 private DefaultXYDataset datasetSelected = new DefaultXYDataset();
140 private DefaultXYDataset datasetPopMin = new DefaultXYDataset();
141 private DefaultXYDataset datasetPopMax = new DefaultXYDataset();
142 private DefaultXYDataset datasetPopMean = new DefaultXYDataset();
143 private DefaultXYDataset datasetPopMedian = new DefaultXYDataset();
144 private XYPlot evoPlot;
145 private JFreeChart evoChart;
146 private ChartPanel evoChartPanel;
147
148 private JPopupMenu evoSeriesCheckList;
149 private JButton evoSeriesBtn;
150
151 private Map<CounterID,DefaultXYDataset> monitorDatasets =
152 new HashMap<CounterID,DefaultXYDataset>();
153
154 private XYPlot monitorPlot;
155 private JFreeChart monitorChart;
156 private ChartPanel monitorChartPanel;
157
159 private JButton monitorSeriesBtn;
160
161
162 private final String NL = System.getProperty("line.separator");
163
168 private JButton openSingleGraph;
169
175 private String pathToSelectedItem;
176
181 private JButton openGeneratinGraphs;
182
187 private JButton openFinalPopGraphs;
188
194 private Map<Integer,List<String>> candsPerGeneration;
195
199 private final Color[] colors = new Color[] {Color.black,
200 Color.decode("#354ccd"), //blue-ish
201 Color.decode("#1e9222"), //dark green
202 Color.decode("#9eca2f"), //light green
203 Color.decode("#28cbad"), //cyan-ish
204 Color.decode("#dea0c8"), //pink-ish
205 Color.decode("#dd6835"), //oragne
206 Color.decode("#b70505"), //red-ish
207 Color.decode("#a42ac4")}; //violet
208
212 private final BasicStroke[] strokes = {
213 new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
214 0.0f),
215 new BasicStroke(
216 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
217 1.0f, new float[] {2f, 2f}, 0.0f),
218 new BasicStroke(
219 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
220 1.0f, new float[] {5f, 2f}, 0.0f),
221 new BasicStroke(
222 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
223 1.0f, new float[] {2f, 2f, 5f, 2f}, 0.0f),
224 new BasicStroke(
225 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
226 1.0f, new float[] {2f, 2f, 2f, 2f, 5f, 2f}, 0.0f),
227 new BasicStroke(
228 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
229 1.0f, new float[] {2f, 2f, 2f, 2f, 2f, 2f, 5f, 2f}, 0.0f),
230 new BasicStroke(
231 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
232 1.0f, new float[] {2f, 2f, 5f, 2f, 5f, 2f}, 0.0f),
233 new BasicStroke(
234 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
235 1.0f, new float[] {2f, 2f, 2f, 2f, 5f, 2f, 5f, 2f}, 0.0f),
236 new BasicStroke(
237 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
238 1.0f, new float[] {2f, 2f, 2f, 2f, 2f, 2f,
239 5f, 2f, 5f, 2f, 5f, 2f}, 0.0f),
240 };
241
246 private String nameFirstMonitorSeries = "unset";
247
248//-----------------------------------------------------------------------------
249
254 {
255 super(mainPanel, "GARun Inspector #"
256 + evolInspectorTabUID.getAndIncrement());
257 super.setLayout(new BorderLayout());
258 initialize();
259 }
260
261//-----------------------------------------------------------------------------
262
266 private void initialize()
267 {
268 // BorderLayout is needed to allow dynamic resizing!
269 this.setLayout(new BorderLayout());
270
271 // The Card has
272 // -> its own toolbar
273 // -> a central panel vertically divided in two
274 // |-> mol/graph viewers? (LEFT)
275 // |-> plots (RIGHT)
276
277 // Creating local tool bar
278 ctrlPanelRow1Left = new JPanel(new FlowLayout(FlowLayout.LEFT));
279
280 evoSeriesCheckList = new JPopupMenu();
281 evoSeriesBtn = new JButton("Show/Hide Population Stats");
282 evoSeriesBtn.setComponentPopupMenu(evoSeriesCheckList);
283 evoSeriesBtn.setToolTipText(String.format(
284 "<html><body width='%1s'>Click to select which population "
285 + "statistics to plot in the top plot.",300));
286 evoSeriesBtn.addActionListener(new ActionListener() {
287 public void actionPerformed(ActionEvent e) {
289 }
290 });
292
294 monitorSeriesBtn = new JButton("Show/Hide Monitor Series");
295 monitorSeriesBtn.setToolTipText(String.format(
296 "<html><body width='%1s'>Click to select which monitored event "
297 + "counts to plot in the bottom plot.",300));
298 monitorSeriesBtn.addActionListener(new ActionListener() {
299 public void actionPerformed(ActionEvent e) {
301 /*
302 LineExamplePanel p = new LineExamplePanel();
303 p.showDialog();
304 */
305 }
306 });
308
309 JButton rstView = new JButton("Reset Charts");
310 rstView.addActionListener(new ActionListener() {
311 public void actionPerformed(ActionEvent e) {
312 evoPlot.getDomainAxis().setAutoRange(true);
313 evoPlot.getRangeAxis().setAutoRange(true);
314 evoPlot.getDomainAxis().setLowerBound(-0.5);
315 for (int iItem=0; iItem<evoSeriesCheckList.getComponentCount();
316 iItem++)
317 {
318 Component c = evoSeriesCheckList.getComponent(iItem);
319 if (c instanceof JCheckBoxMenuItem)
320 {
321 // NB: this sets the default series displayed upon reset
322 if (((JCheckBoxMenuItem) c).getText().startsWith("Max")
323 || ((JCheckBoxMenuItem) c).getText().startsWith("Min"))
324 ((JCheckBoxMenuItem) c).setSelected(true);
325 else
326 ((JCheckBoxMenuItem) c).setSelected(false);
327 }
328 }
329
330 monitorPlot.getDomainAxis().setAutoRange(true);
331 monitorPlot.getRangeAxis().setAutoRange(true);
332 monitorPlot.getDomainAxis().setLowerBound(-0.5);
333 for (JCheckBox cb : monitorSeriesCheckList.getAllBChekBoxes())
334 {
335 // NB: this sets the default series displayed upon reset
336 if (cb.getText().startsWith(nameFirstMonitorSeries))
337 cb.setSelected(true);
338 else
339 cb.setSelected(false);
340 }
341 }
342 });
343 ctrlPanelRow1Left.add(rstView);
344
345 // Done with left part of bar, not the right-hand part...
346
347 ctrlPanelRow1Right = new JPanel(new FlowLayout(FlowLayout.RIGHT));
348 lblTotItems = new JLabel("No item loaded");
349 lblTotItems.setHorizontalAlignment(SwingConstants.RIGHT);
350 lblTotItems.setPreferredSize(new Dimension(300,28));
352
353 ctrlPanelRow2Left = new JPanel(new FlowLayout(FlowLayout.LEFT));
354
355 openSingleGraph = new JButton("Open Candidate's Graph");
356 openSingleGraph.setEnabled(false); //Enables only upon selection of an item
357 openSingleGraph.setToolTipText("Open a new tab for inspecting the "
358 + "graph representation of the selected candidate.");
359 openSingleGraph.addActionListener(new ActionListener() {
360 public void actionPerformed(ActionEvent e) {
361 mainPanel.setCursor(Cursor.getPredefinedCursor(
362 Cursor.WAIT_CURSOR));
363 GUIGraphHandler graphPanel = new GUIGraphHandler(mainPanel);
364 mainPanel.add(graphPanel);
365 graphPanel.importGraphsFromFile(new File(pathToSelectedItem));
366 mainPanel.setCursor(Cursor.getPredefinedCursor(
367 Cursor.DEFAULT_CURSOR));
368 }
369 });
371
372
373 openGeneratinGraphs = new JButton("Open Population Graphs");
374 openGeneratinGraphs.setToolTipText(String.format(
375 "<html><body width='%1s'>Open a "
376 + "new tab for inspecting the graph representation of all "
377 + "members of the population. "
378 + "Opens a dialog to specify which generation to consider of "
379 + "the selected candidate.",300));
380 openGeneratinGraphs.addActionListener(new ActionListener() {
381 public void actionPerformed(ActionEvent e) {
382 // Ask which generation
385 Object res = dialog.showDialog();
386 if (res==null)
387 {
388 return;
389 }
390 int genId = -1;
391 try {
392 genId = Integer.parseInt((String) res);
393 } catch (Throwable t) {
394 JOptionPane.showMessageDialog(openGeneratinGraphs,
395 String.format("<html><body width='%1s'>String '"
396 + res+ "' could not be used to identify "
397 + "a generation. "
398 + "Please, type an integer 0, 1, 2,...", 300),
399 "Error",
400 JOptionPane.PLAIN_MESSAGE,
401 UIManager.getIcon("OptionPane.errorIcon"));
402 return;
403 }
404 if (!candsPerGeneration.containsKey(genId))
405 {
406 JOptionPane.showMessageDialog(openGeneratinGraphs,
407 String.format("<html><body width='%1s'>"
408 + "List of members of generation " + genId
409 + " could not be found. Generation summary "
410 + "missing or not properly formatted.",300),
411 "Error",
412 JOptionPane.PLAIN_MESSAGE,
413 UIManager.getIcon("OptionPane.errorIcon"));
414 return;
415 }
416
417 // Collect population
418 String pathtoTmpFile = Utils.getTempFile("population_at_gen"
419 + genId + ".sdf");
420 mainPanel.setCursor(Cursor.getPredefinedCursor(
421 Cursor.WAIT_CURSOR));
422 try
423 {
424 FileUtils.mergeIntoOneFile(pathtoTmpFile,
425 candsPerGeneration.get(genId));
426 mainPanel.setCursor(Cursor.getPredefinedCursor(
427 Cursor.DEFAULT_CURSOR));
428 } catch (IOException e1)
429 {
430 e1.printStackTrace();
431 JOptionPane.showMessageDialog(openGeneratinGraphs,
432 String.format("<html><body width='%1s'>"
433 + "List of members of generation " + genId
434 + " could not be collected. Hint: "
435 + e1.getMessage(), 300),
436 "Error",
437 JOptionPane.PLAIN_MESSAGE,
438 UIManager.getIcon("OptionPane.errorIcon"));
439 mainPanel.setCursor(Cursor.getPredefinedCursor(
440 Cursor.DEFAULT_CURSOR));
441 return;
442 }
443
444 // Launch the GUI component to visualize population
445 GUIGraphHandler graphPanel = new GUIGraphHandler(mainPanel);
446 mainPanel.add(graphPanel);
447 graphPanel.importGraphsFromFile(new File(pathtoTmpFile));
448
449 //Log
450 System.out.println("File collecting members of the population "
451 + "at generation " + genId + ": "+ pathtoTmpFile);
452 }
453 });
455
456
457 openFinalPopGraphs = new JButton("Open Final Pop Graphs");
458 openFinalPopGraphs.setToolTipText(String.format(
459 "<html><body width='%1s'>Open a "
460 + "new tab for inspecting the graph representation of all "
461 + "members of the final population. ",300));
462 openFinalPopGraphs.addActionListener(new ActionListener() {
463 public void actionPerformed(ActionEvent e) {
464 // Collect population
465 String pathtoTmpFile = Utils.getTempFile("final_population.sdf");
466 File finalPopFolder = new File(srcFolder,"Final");
467 if (!finalPopFolder.exists())
468 {
469 JOptionPane.showMessageDialog(openGeneratinGraphs,
470 String.format("<html><body width='%1s'>"
471 + "Cannot find folder '" + finalPopFolder
472 + "'. Final population not found.", 300),
473 "Error",
474 JOptionPane.ERROR_MESSAGE,
475 UIManager.getIcon("OptionPane.errorIcon"));
476 mainPanel.setCursor(Cursor.getPredefinedCursor(
477 Cursor.DEFAULT_CURSOR));
478 return;
479 }
480 mainPanel.setCursor(Cursor.getPredefinedCursor(
481 Cursor.WAIT_CURSOR));
482 List<String> filesToMerge = new ArrayList<String>();
483 for (File fitFile : finalPopFolder.listFiles(new FileFilter() {
484
485 @Override
486 public boolean accept(File pathname) {
487 if (pathname.getName().endsWith(
489 {
490 return true;
491 }
492 return false;
493 }
494 }))
495 {
496 filesToMerge.add(fitFile.getAbsolutePath());
497 }
498
499 try
500 {
501 FileUtils.mergeIntoOneFile(pathtoTmpFile, filesToMerge);
502 mainPanel.setCursor(Cursor.getPredefinedCursor(
503 Cursor.DEFAULT_CURSOR));
504 } catch (IOException e1)
505 {
506 e1.printStackTrace();
507 JOptionPane.showMessageDialog(openGeneratinGraphs,
508 String.format("<html><body width='%1s'>"
509 + "List of members of final population "
510 + " could not be collected. Hint: "
511 + e1.getMessage(), 400),
512 "Error",
513 JOptionPane.PLAIN_MESSAGE,
514 UIManager.getIcon("OptionPane.errorIcon"));
515 mainPanel.setCursor(Cursor.getPredefinedCursor(
516 Cursor.DEFAULT_CURSOR));
517 return;
518 }
519
520 // Launch the GUI component to visualize population
521 GUIGraphHandler graphPanel = new GUIGraphHandler(mainPanel);
522 mainPanel.add(graphPanel);
523 graphPanel.importGraphsFromFile(new File(pathtoTmpFile));
524
525 //Log
526 System.out.println("File collecting members of the final "
527 + "population: "+ pathtoTmpFile);
528 }
529 });
531
532
533 ctrlPanelRow1 = new JPanel();
534 GroupLayout lyoCtrlPanelRow1 = new GroupLayout(ctrlPanelRow1);
535 ctrlPanelRow1.setLayout(lyoCtrlPanelRow1);
536 lyoCtrlPanelRow1.setAutoCreateGaps(true);
537 lyoCtrlPanelRow1.setAutoCreateContainerGaps(true);
538 lyoCtrlPanelRow1.setHorizontalGroup(
539 lyoCtrlPanelRow1.createSequentialGroup()
540 .addComponent(ctrlPanelRow1Left)
541 .addComponent(ctrlPanelRow1Right));
542 lyoCtrlPanelRow1.setVerticalGroup(lyoCtrlPanelRow1.createParallelGroup()
543 .addComponent(ctrlPanelRow1Left)
544 .addComponent(ctrlPanelRow1Right));
545
546 ctrlPanel = new JPanel();
547 GroupLayout lyoCtrlPanel = new GroupLayout(ctrlPanel);
548 ctrlPanel.setLayout(lyoCtrlPanel);
549 lyoCtrlPanel.setAutoCreateGaps(true);
550 lyoCtrlPanel.setAutoCreateContainerGaps(true);
551 lyoCtrlPanel.setHorizontalGroup(lyoCtrlPanel.createParallelGroup()
552 .addComponent(ctrlPanelRow1)
553 .addComponent(ctrlPanelRow2Left));
554 lyoCtrlPanel.setVerticalGroup(lyoCtrlPanel.createSequentialGroup()
555 .addComponent(ctrlPanelRow1)
556 .addComponent(ctrlPanelRow2Left));
557
558 this.add(ctrlPanel,BorderLayout.NORTH);
559
560 // Setting structure of panels structure that goes in the center
561 centralPanel = new JSplitPane();
562 centralPanel.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
563 centralPanel.setOneTouchExpandable(true);
564 rightPanel = new JSplitPane();
565 rightPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
566 rightPanel.setDividerLocation(300);
567 rightUpPanel = new JPanel();
568 rightUpPanel.setLayout(new BorderLayout());
569 rightDownPanel = new JPanel();
570 rightDownPanel.setLayout(new BorderLayout());
571 rightPanel.setTopComponent(rightUpPanel);
572 rightPanel.setBottomComponent(rightDownPanel);
573
574 centralPanel.setRightComponent(rightPanel);
576 centralPanel.setLeftComponent(molViewer);
577 centralPanel.setDividerLocation(300);
578 this.add(centralPanel,BorderLayout.CENTER);
579
580 // Button to the bottom of the card
581 ButtonsBar commandsPane = new ButtonsBar();
582 this.add(commandsPane, BorderLayout.SOUTH);
583 JButton btnCanc = new JButton("Close Tab");
584 btnCanc.setToolTipText("Closes this GARun Inspector.");
585 btnCanc.addActionListener(new removeCardActionListener(this));
586 commandsPane.add(btnCanc);
587
588 JButton btnHelp = new JButton("?");
589 btnHelp.setToolTipText("<html>Hover over buttons and fields "
590 + "to get a tip.<br>"
591 + "Click the '?' button for further instructions.</html>");
592 btnHelp.addActionListener(new ActionListener() {
593 public void actionPerformed(ActionEvent e) {
594 String txt = "<html><body width='%1s'>"
595 + "<p>Selection of candidates:"
596 + "<ul>"
597 + "<li>Click on a dot in the chart to load the "
598 + "molecular "
599 + "representation of that candidates.</li>"
600 + "<li>Click away from any dot to reset the molecular "
601 + "viewer."
602 + "</li></ul></p>"
603 + "<p>Chart view:"
604 + "<ul>"
605 + "<li>zoom in: click-and-drag "
606 + "from the top-left to the bottom-right "
607 + "corners of the new region of the plot to focus on."
608 + "</li>"
609 + "<li>Use the <code>Reset Chart View</code> to reset "
610 + "the view.</li>"
611 + "<li>Right-click to get advanced controls and "
612 + "options, inclusing exporting the charts as PNG or "
613 + "SVG.</li>"
614 + "</ul></p>"
615 + "</body></html>";
616 JOptionPane.showMessageDialog(btnHelp, String.format(txt, 300),
617 "Tips",
618 JOptionPane.PLAIN_MESSAGE);
619 }
620 });
621 commandsPane.add(btnHelp);
622
623 }
624
625//------------------------------------------------------------------------------
626
630 @SuppressWarnings("serial")
632 {
633 public GenerationChoiceDialog(Component refForPlacement)
634 {
635 super(refForPlacement,false);
636 this.setTitle("Choose Generation");
637
638 Dimension sizeNameFields = new Dimension(200,
639 (int) (new JTextField()).getPreferredSize().getHeight());
640
641 JPanel rowOne = new JPanel(new FlowLayout(FlowLayout.LEFT));
642 JLabel lblVarName = new JLabel("Generation Number:");
643 JTextField txtVarName = new JTextField();
644 txtVarName.setPreferredSize(sizeNameFields);
645 rowOne.add(lblVarName);
646 rowOne.add(txtVarName);
647
648 addToCentralPane(rowOne);
649
650 this.btnDone.addActionListener(new ActionListener() {
651
652 @Override
653 public void actionPerformed(ActionEvent e) {
654 if (txtVarName.getText().equals(""))
655 {
656 result = null;
657 } else {
658 result = txtVarName.getText();
659 }
660 close();
661 }
662 });
663 this.getRootPane().setDefaultButton(this.btnDone);
664 this.btnCanc.addActionListener(new ActionListener() {
665
666 @Override
667 public void actionPerformed(ActionEvent e) {
668 result = null;
669 close();
670 }
671 });
672 }
673 }
674
675//-----------------------------------------------------------------------------
676
677 public void importGARunData(File file, JComponent parent)
678 {
679 if (!file.isDirectory() || !file.exists())
680 {
681 JOptionPane.showMessageDialog(parent,
682 "Could not read data from folder '" + file + "'!",
683 "Error",
684 JOptionPane.PLAIN_MESSAGE,
685 UIManager.getIcon("OptionPane.errorIcon"));
686 return;
687 }
688
689 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
690
691 srcFolder = file;
692
693 System.out.println("Importing data from '" + srcFolder + "'...");
694
695 candsPerGeneration = new HashMap<Integer,List<String>>();
696 Map<Integer,double[]> popProperties = new HashMap<Integer,double[]>();
697 allIndividuals = new ArrayList<CandidateLW>();
698 int largestGenId = -1;
699 for (File genFolder : file.listFiles(new FileFilter() {
700
701 @Override
702 public boolean accept(File pathname) {
703 if (pathname.getName().startsWith("Gen")
704 && pathname.isDirectory())
705 {
706 return true;
707 }
708 return false;
709 }
710 }))
711 {
712 //WARNING: assuming folders are named "Gen.*"
713 int genId = Integer.parseInt(genFolder.getName().substring(3));
714 int padSize = genFolder.getName().substring(3).length();
715 String zeroedGenId = GeneralUtils.getPaddedString(padSize, genId);
716 readOneGeneration(genFolder, "Gen" + zeroedGenId + ".txt",
717 genId, parent, popProperties);
718 if (genId>largestGenId)
719 largestGenId = genId;
720 }
721
722 System.out.println("Imported "+allIndividuals.size()+" individuals.");
723
724 lblTotItems.setText("Found "+allIndividuals.size()+" candidates ("
725 +molsWithFitness+" with fitness)");
726
727 // Process data and organize then into series for the plot
728 double[][] candsWithFitnessData = new double[2][molsWithFitness];
729 candsWithFitnessMap = new HashMap<Integer,CandidateLW>();
730 int j = -1;
731 for (int i=0; i<allIndividuals.size(); i++)
732 {
733 CandidateLW item = allIndividuals.get(i);
734 if (!item.hasFitness())
735 {
736 continue;
737 }
738
739 // WARNING: itemId in the data is "j" and is just a unique
740 // identifier that has NO RELATION to generation/molId/fitness
741 // The Map 'candsWithFitnessMap' serve specifically to convert
742 // the itemId 'j' into a DENOPTIMMolecule
743
744 j++;
745 candsWithFitnessMap.put(j, item);
746 candsWithFitnessData[0][j] = item.getGeneration();
747 candsWithFitnessData[1][j] = item.getFitness();
748 }
749 datasetAllFit.addSeries("Candidates_with_fitness", candsWithFitnessData);
750
751 // We sort the list of individuals by fitness and generation so that we
752 // can quickly identify overlapping items
753 Collections.sort(allIndividuals, new PlottedCandidatesComparator());
754
755 int numGen = popProperties.keySet().size();
756 double[][] popMin = new double[2][numGen];
757 double[][] popMax = new double[2][numGen];
758 double[][] popMean = new double[2][numGen];
759 double[][] popMedian = new double[2][numGen];
760 for (int i=0; i<numGen; i++)
761 {
762 double[] values = popProperties.get(i);
763 popMin[0][i] = i;
764 popMin[1][i] = values[0];
765 popMax[0][i] = i;
766 popMax[1][i] = values[1];
767 popMean[0][i] = i;
768 popMean[1][i] = values[2];
769 popMedian[0][i] = i;
770 popMedian[1][i] = values[3];
771
772 }
773 datasetPopMin.addSeries("Population_min", popMin);
774 datasetPopMax.addSeries("Population_max", popMax);
775 datasetPopMean.addSeries("Population_mean", popMean);
776 datasetPopMedian.addSeries("Population_median", popMedian);
777
778
779 //TODO: somehow collect and display the candidates that hit a mol error
780 // Could it be a histogram (#failed x gen) below the evolution plot
781
782 NumberAxis xAxis = new NumberAxis("Generation");
783 xAxis.setRange(-0.5, numGen-0.5); //"-" because numGen includes 0
784 xAxis.setAutoRangeIncludesZero(false);
785 NumberAxis yAxis = new NumberAxis("Fitness");
786 yAxis.setAutoRangeIncludesZero(false);
787 evoPlot = new XYPlot(null,xAxis,yAxis,null);
788
789 evoChart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT,evoPlot,
791 if (evoChart.getLegend()!=null)
792 evoChart.getLegend().setPosition(RectangleEdge.BOTTOM);
793
794 evoPlot.getDomainAxis().setLowerBound(-0.5); //min X-axis
795 evoPlot.setBackgroundPaint(Color.WHITE);
796 evoPlot.setDomainGridlinePaint(Color.LIGHT_GRAY);
797 evoPlot.setRangeGridlinePaint(Color.LIGHT_GRAY);
798 evoPlot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD);
799 // The following brings the points for datasets of selected
800 // items and the main dataset in front of the
801 // mean/min/max/median lines, thus allowing selection of points
802 // even in presence of these line series, which would otherwise (if in
803 // front-most layer) prevent the mouse clicked event to identify the
804 // item from datasetAllFit, thus preventing to display the molecular
805 // representation of that item.
806 evoPlot.setDatasetRenderingOrder(DatasetRenderingOrder.REVERSE);
807
808 // dataset of selected items
809 Shape shape0 = new Ellipse2D.Double(
814 XYLineAndShapeRenderer renderer0 =
815 new XYLineAndShapeRenderer(false, true);
816 //NB: here is where we define that the selected ones are at '0'
817 // Search for the 'HERE@HERE' string to find where I use this assumption
818 evoPlot.setDataset(0, datasetSelected);
819 evoPlot.setRenderer(0, renderer0);
820 renderer0.setSeriesShape(0, shape0);
821 renderer0.setSeriesPaint(0, Color.red);
822 renderer0.setSeriesFillPaint(0, Color.red);
823 renderer0.setSeriesOutlinePaint(0, Color.BLACK);
824 renderer0.setUseOutlinePaint(true);
825 renderer0.setUseFillPaint(true);
826
827 // main dataset (all items with fitness)
828 Shape shape1 = new Ellipse2D.Double(
833 XYLineAndShapeRenderer renderer1 =
834 new XYLineAndShapeRenderer(false, true);
835 evoPlot.setDataset(1, datasetAllFit);
836 evoPlot.setRenderer(1, renderer1);
837 renderer1.setSeriesShape(0, shape1);
838 renderer1.setSeriesPaint(0, new Color(192, 192, 192, 60));
839 renderer1.setSeriesFillPaint(0, new Color(192, 192, 192, 60));
840 renderer1.setSeriesOutlinePaint(0, Color.GRAY);
841 renderer1.setUseOutlinePaint(true);
842 renderer1.setUseFillPaint(true);
843
844
845 // Collect the ooptional series for an easy selection in the menu list
846 evoSeriesCheckList = new JPopupMenu();
847
848 // min fitness in the population
849 XYLineAndShapeRenderer renderer2 =
850 new XYLineAndShapeRenderer(true, false);
851 evoPlot.setDataset(2, datasetPopMin);
852 evoPlot.setRenderer(2, renderer2);
853 renderer2.setSeriesPaint(0, Color.blue);
854 //NB: 'rstView' button assumes this item string begins with "Min"
855 JCheckBoxMenuItem cbmiMin = new JCheckBoxMenuItem(
856 "Minimum Fitness in Population");
857 cbmiMin.setForeground(Color.blue);
858 cbmiMin.setSelected(true);
859 cbmiMin.addItemListener(new ItemListener(){
860 @Override
861 public void itemStateChanged(ItemEvent e)
862 {
863 if (cbmiMin.isSelected())
864 {
865 renderer2.setSeriesVisible(0, true);
866 } else {
867 renderer2.setSeriesVisible(0, false);
868 }
869 }
870 });
871 evoSeriesCheckList.add(cbmiMin);
872
873 // max fitness in the population
874 XYLineAndShapeRenderer renderer3 =
875 new XYLineAndShapeRenderer(true, false);
876 evoPlot.setDataset(3, datasetPopMax);
877 evoPlot.setRenderer(3, renderer3);
878 renderer3.setSeriesPaint(0, Color.blue);
879 //NB: 'rstView' button assumes this item string begins with "Max"
880 JCheckBoxMenuItem cbmiMax = new JCheckBoxMenuItem(
881 "Maximum Fitness in Population");
882 cbmiMax.setForeground(Color.blue);
883 cbmiMax.setSelected(true);
884 cbmiMax.addItemListener(new ItemListener(){
885 @Override
886 public void itemStateChanged(ItemEvent e)
887 {
888 if (cbmiMax.isSelected())
889 {
890 renderer3.setSeriesVisible(0, true);
891 } else {
892 renderer3.setSeriesVisible(0, false);
893 }
894 }
895 });
896 evoSeriesCheckList.add(cbmiMax);
897
898 // mean fitness in the population
899 XYLineAndShapeRenderer renderer4 =
900 new XYLineAndShapeRenderer(true, false);
901 evoPlot.setDataset(4, datasetPopMean);
902 evoPlot.setRenderer(4, renderer4);
903 renderer4.setSeriesPaint(0, Color.red);
904 renderer4.setSeriesStroke(0, new BasicStroke(
905 2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
906 1.0f, new float[] {10.0f, 6.0f}, 0.0f));
907 renderer4.setSeriesVisible(0, false);
908 JCheckBoxMenuItem cbmiMean = new JCheckBoxMenuItem(
909 "Mean of Fitness in Population");
910 cbmiMean.setForeground(Color.red);
911 cbmiMean.setSelected(false);
912 cbmiMean.addItemListener(new ItemListener(){
913 @Override
914 public void itemStateChanged(ItemEvent e)
915 {
916 if (cbmiMean.isSelected())
917 {
918 renderer4.setSeriesVisible(0, true);
919 } else {
920 renderer4.setSeriesVisible(0, false);
921 }
922 }
923 });
924 evoSeriesCheckList.add(cbmiMean);
925
926 // median fitness in the population
927 XYLineAndShapeRenderer renderer5 =
928 new XYLineAndShapeRenderer(true, false);
929 evoPlot.setDataset(5, datasetPopMedian);
930 evoPlot.setRenderer(5, renderer5);
931 renderer5.setSeriesPaint(0, Color.decode("#22BB22"));
932 renderer5.setSeriesStroke(0, new BasicStroke(
933 2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
934 1.0f, new float[] {3.0f, 6.0f}, 0.0f));
935 renderer5.setSeriesVisible(0, false);
936 JCheckBoxMenuItem cbmiMedian = new JCheckBoxMenuItem(
937 "Median of Fitness in Population");
938 cbmiMedian.setForeground(Color.decode("#22BB22"));
939 cbmiMedian.setSelected(false);
940 cbmiMedian.addItemListener(new ItemListener(){
941 @Override
942 public void itemStateChanged(ItemEvent e)
943 {
944 if (cbmiMedian.isSelected())
945 {
946 renderer5.setSeriesVisible(0, true);
947 } else {
948 renderer5.setSeriesVisible(0, false);
949 }
950 }
951 });
952 evoSeriesCheckList.add(cbmiMedian);
953
954
955 // Create the actual panel that contains the chart
956 evoChartPanel = new ChartPanel(evoChart);
957
958 // Adapt chart size to the size of the panel
959 rightUpPanel.addComponentListener(new ComponentAdapter() {
960 @Override
961 public void componentResized(ComponentEvent e) {
962 evoChartPanel.setMaximumDrawHeight(e.getComponent().getHeight());
963 evoChartPanel.setMaximumDrawWidth(e.getComponent().getWidth());
964 evoChartPanel.setMinimumDrawWidth(e.getComponent().getWidth());
965 evoChartPanel.setMinimumDrawHeight(e.getComponent().getHeight());
966 // WARNING: this update is needed to make the new size affective
967 // also after movement of the JSplitPane divider, which is
968 // otherwise felt by this listener but the new sizes do not
969 // take effect.
970 ChartEditor ce = ChartEditorManager.getChartEditor(evoChart);
971 ce.updateChart(evoChart);
972 }
973 });
974
975 // Setting toolTip when on top of an series item in the chart
976 XYToolTipGenerator ttg = new XYToolTipGenerator() {
977 @Override
978 public String generateToolTip(XYDataset data, int sId, int itemId)
979 {
980 CandidateLW itemOnTop = candsWithFitnessMap.get(itemId);
981 // Is there more than one item in the stack?
982 // One overlapping neighbor is enough to say there
983 // is more than one item in the tack.
984 List<CandidateLW> overlappingItems = getOverlappingItems(
985 itemOnTop, 2);
986 if (overlappingItems.size()>1)
987 return "Overlapping Items";
988 else
989 return candsWithFitnessMap.get(itemId).getName();
990 }
991 };
992 renderer1.setDefaultToolTipGenerator(ttg);
993
994 // Click-based selection of item, possibly displaying mol structure
995 evoChartPanel.addChartMouseListener(new ChartMouseListener() {
996
997 @Override
998 public void chartMouseMoved(ChartMouseEvent e) {
999 //nothing to do
1000 }
1001
1002 @Override
1003 public void chartMouseClicked(ChartMouseEvent e)
1004 {
1005 if (e.getEntity() instanceof XYItemEntity)
1006 {
1007 XYDataset ds = ((XYItemEntity)e.getEntity()).getDataset();
1008 if (!ds.equals(datasetAllFit))
1009 {
1010 return;
1011 }
1012
1013 int serId = ((XYItemEntity)e.getEntity()).getSeriesIndex();
1014 if (serId == 0)
1015 {
1016 int itemId = ((XYItemEntity) e.getEntity()).getItem();
1017 CandidateLW item = candsWithFitnessMap.get(itemId);
1018
1019 // The even can carry only one item, but there could be
1020 // many items overlapping each other.
1021 // Search for overlapping items and ask which one to the
1022 // user wants to see.
1023 List<CandidateLW> overlappingItems = getOverlappingItems(
1024 item,25);
1026 evoChartPanel, overlappingItems);
1027 if (choosenItem!=null)
1028 renderViewWithSelectedItem(choosenItem);
1029 }
1030 //do we do anything if we select other series? not now...
1031 }
1032 else if (e.getEntity() instanceof PlotEntity)
1033 {
1035 }
1036 }
1037 });
1038
1039 rightUpPanel.add(evoChartPanel,BorderLayout.CENTER);
1040
1041 buildAndFillMonitorPlot(file, parent);
1042
1043 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1044 }
1045
1046//------------------------------------------------------------------------------
1047
1048 private void readOneGeneration(File genFolder, String summaryName,
1049 int genId,
1050 Component parent,
1051 Map<Integer,double[]> popProperties)
1052 {
1053 // Read Generation summary file
1054 File genSummary = new File(genFolder, summaryName);
1055 System.out.println("Reading "+genSummary);
1056 boolean readPopMembers = false;
1057 try {
1058 popProperties.put(genId, DenoptimIO.readPopulationProps(
1059 genSummary));
1060 readPopMembers = true;
1061 } catch (DENOPTIMException e2) {
1062 JOptionPane.showMessageDialog(parent,
1063 "<html>File '" + genSummary + "' not found!<br>"
1064 + "There will be holes in the min/max/mean profile."
1065 + "</html>",
1066 "Error",
1067 JOptionPane.PLAIN_MESSAGE,
1068 UIManager.getIcon("OptionPane.errorIcon"));
1069 popProperties.put(genId, new double[] {
1070 Double.NaN, Double.NaN, Double.NaN, Double.NaN});
1071 }
1072
1073 // Read candidates from file (if present)
1074 boolean foundCandidateFilesInThisGen = false;
1075 for (File fitFile : genFolder.listFiles(new FileFilter() {
1076
1077 @Override
1078 public boolean accept(File pathname) {
1079 if (pathname.getName().endsWith(
1081 {
1082 return true;
1083 }
1084 return false;
1085 }
1086 }))
1087 {
1088 CandidateLW one;
1089 try {
1090 //WARNING: here we assume one candidate per file
1091 one = DenoptimIO.readLightWeightCandidate(fitFile).get(0);
1092 } catch (DENOPTIMException e1) {
1093 e1.printStackTrace();
1094 JOptionPane.showMessageDialog(parent,
1095 "Could not read data from to '" + fitFile + "'! "
1096 + NL + e1.getMessage(),
1097 "Error",
1098 JOptionPane.PLAIN_MESSAGE,
1099 UIManager.getIcon("OptionPane.errorIcon"));
1100 return;
1101 }
1102 if (one.hasFitness())
1103 {
1105 }
1106 one.setGeneration(genId);
1107 allIndividuals.add(one);
1108 foundCandidateFilesInThisGen = true;
1109 }
1110
1111 // Read traces of candidates if candidate's files are not present
1112 if (!foundCandidateFilesInThisGen)
1113 {
1115 {
1116 JOptionPane.showMessageDialog(parent,
1117 String.format("<html><body width='%1s'>"
1118 + "This evolutionary experiment seems to "
1119 + "have been run with the "
1120 + "'FP-DontWriteCandidatesOnDisk' option. "
1121 + "Therefore, the definition of candidates "
1122 + "encountered during the evolution is not "
1123 + "present on disk. "
1124 + "We'll show only how the trace of such "
1125 + "candidates in the evolution. You may try "
1126 + "to inspect the final generation, "
1127 + "if present, by clicking on '"
1128 + openFinalPopGraphs.getText() + "'"
1129 + "</html>", 400),
1130 "Warning",
1131 JOptionPane.WARNING_MESSAGE,
1132 UIManager.getIcon("OptionPane.errorIcon"));
1134 }
1135 readPopMembers = false;
1136 try
1137 {
1138 for (CandidateLW cand :
1140 {
1141 // We keep only the oldest version of a candidate.
1142 // To this end, note that the equality of CandidateLW
1143 // considers only name and UID.
1144 if (allIndividuals.contains(cand))
1145 {
1146 CandidateLW otherTracePfCand = allIndividuals.get(
1147 allIndividuals.indexOf(cand));
1148 if (otherTracePfCand.getGeneration() > genId)
1149 {
1150 allIndividuals.remove(otherTracePfCand);
1152 } else {
1153 continue;
1154 }
1155 }
1156 cand.setGeneration(genId);
1158 allIndividuals.add(cand);
1159 }
1160 } catch (DENOPTIMException e1)
1161 {
1162 // Should never happen unless the file becomes unreadable
1163 // between the previous read and this one.
1164 e1.printStackTrace();
1165 }
1166 }
1167
1168 //Read population members from summary
1169 if (readPopMembers)
1170 {
1171 try
1172 {
1173 List<String> membersPathnames = new ArrayList<String>(
1175 candsPerGeneration.put(genId, membersPathnames);
1176 } catch (DENOPTIMException e1)
1177 {
1178 e1.printStackTrace();
1179 JOptionPane.showMessageDialog(parent,
1180 String.format("<html><body width='%1s'>"
1181 + "File '" + genSummary + "' has been found, "
1182 + "but pathnames to population members could "
1183 + "not be read.</html>", 400),
1184 "Error",
1185 JOptionPane.PLAIN_MESSAGE,
1186 UIManager.getIcon("OptionPane.errorIcon"));
1187 }
1188 }
1189 }
1190
1191//------------------------------------------------------------------------------
1192
1196 /*
1197 private class LineExamplePanel extends GUIModalDialog
1198 {
1199 public LineExamplePanel()
1200 {
1201 super(false);
1202 this.setBounds(150, 150, 500, 200);
1203 this.setTitle("LineExamples");
1204 JPanel mainPanel = new JPanel();
1205 mainPanel.setLayout(new BoxLayout(mainPanel, SwingConstants.VERTICAL));
1206 JScrollPane scrolPane = new JScrollPane(mainPanel);
1207 addToCentralPane(scrolPane);
1208
1209 int iColor = 0;
1210 int iStroke = 0;
1211 for (int iSeries=0; iSeries<100; iSeries++)
1212 {
1213 Color color = colors[iColor];
1214 BasicStroke stroke = strokes[iStroke];
1215 JPanel linePanel = new JPanel() {
1216 protected void paintComponent(Graphics g) {
1217 super.paintComponent(g);
1218 g.setColor(color);
1219 ((Graphics2D) g).setStroke(stroke);
1220 g.drawLine(10,10, 5000, 15);
1221 };
1222 };
1223 JPanel locPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
1224 mainPanel.add(linePanel);
1225 mainPanel.add(new JLabel("Color: "+ iColor+" Stroke: "+iStroke));
1226
1227 iColor++;
1228 if (iColor >= colors.length)
1229 {
1230 iColor = 0;
1231 if (iStroke < strokes.length-1)
1232 {
1233 iStroke++;
1234 } else {
1235 iStroke = 0;
1236 }
1237 }
1238 }
1239 }
1240 }
1241 */
1242
1243//------------------------------------------------------------------------------
1244
1245 private void buildAndFillMonitorPlot(File runFolder, JComponent parent)
1246 {
1247 File eaMonitorDumps = new File(runFolder + ".eaMonitor");
1248 if (!eaMonitorDumps.exists())
1249 {
1250 rightDownPanel.add(new JLabel("Monitor file " + eaMonitorDumps
1251 + "not found."));
1252 return;
1253 }
1254 ArrayList<String> lines = null;
1255 try
1256 {
1257 lines = DenoptimIO.readList(eaMonitorDumps.getAbsolutePath());
1258 } catch (DENOPTIMException e1)
1259 {
1260 e1.printStackTrace();
1261 rightDownPanel.add(new JLabel("Cannot read " + eaMonitorDumps));
1262 return;
1263 }
1264 if (lines.size()<2)
1265 {
1266 rightDownPanel.add(new JLabel("Not enough data to plot"));
1267 return;
1268 }
1269
1270 String[] words = lines.get(0).trim().split("\\s+");
1271 String[] headers = IntStream.range(3, words.length)
1272 .mapToObj(i -> words[i])
1273 .toArray(String[]::new);
1274
1275 // Prepare data storage structure...
1276 List<double[][]> xyData = new ArrayList<double[][]>();
1277 for (int iSeries=0; iSeries<headers.length; iSeries++)
1278 xyData.add(new double[2][lines.size()-1]);
1279 // ...and fill it with actual data
1280 int iRecordsKept = -1;
1281 for (int iRecordr=1; iRecordr<lines.size(); iRecordr++)
1282 {
1283 String line = lines.get(iRecordr).trim();
1284
1285 // TODO: change. Now, we ignore dumps more frequent than generations
1286 if (!line.startsWith("SUMMARY"))
1287 continue;
1288
1289 iRecordsKept++;
1290 String[] values = line.split("\\s+");
1291 for (int iSeries=3; iSeries<values.length; iSeries++)
1292 {
1293 xyData.get(iSeries-3)[0][iRecordsKept] =
1294 Double.valueOf(values[2]); // generation ID
1295 xyData.get(iSeries-3)[1][iRecordsKept] =
1296 Double.valueOf(values[iSeries]); // counter value
1297 }
1298 }
1299
1300 // Done with collecting data, not build the plot
1301
1302 NumberAxis xAxis = new NumberAxis("Generation");
1303 //"-0.5" because includes 0
1304 xAxis.setRange(-0.5, Double.valueOf(iRecordsKept)-0.5);
1305 xAxis.setAutoRangeIncludesZero(false);
1306 // By default we show the first series (should be the number of attempts
1307 // to create candidates)
1308 NumberAxis yAxis = new NumberAxis("#");
1309 yAxis.setAutoRangeIncludesZero(false);
1310
1311 monitorPlot = new XYPlot(null,xAxis,yAxis,null);
1312
1313 monitorChart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT,
1315 if (monitorChart.getLegend()!=null)
1316 monitorChart.getLegend().setPosition(RectangleEdge.BOTTOM);
1317
1318 monitorPlot.getDomainAxis().setLowerBound(-0.5); //min X-axis
1319 monitorPlot.setBackgroundPaint(Color.WHITE);
1320 monitorPlot.setDomainGridlinePaint(Color.LIGHT_GRAY);
1321 monitorPlot.setRangeGridlinePaint(Color.LIGHT_GRAY);
1322 // NB: ineffective
1323 //monitorPlot.setDomainGridlinesVisible(true);
1324 //monitorPlot.setRangeGridlinesVisible(true);
1325 // Instead, this is needed to show the grid.
1326 XYLineAndShapeRenderer renderer0 =
1327 new XYLineAndShapeRenderer(false, true);
1328 monitorPlot.setDataset(0, new DefaultXYDataset());
1329 monitorPlot.setRenderer(0, renderer0);
1330
1331 int iColor = 0;
1332 int iStroke = 0;
1333 for (int iSeries=0; iSeries<headers.length; iSeries++)
1334 {
1335 DefaultXYDataset dataset = new DefaultXYDataset();
1336 dataset.addSeries(headers[iSeries], xyData.get(iSeries));
1337 monitorDatasets.put(CounterID.valueOf(headers[iSeries]), dataset);
1338
1339 XYLineAndShapeRenderer serierRenderer =
1340 new XYLineAndShapeRenderer(true, false);
1341 monitorPlot.setDataset(iSeries, dataset);
1342 monitorPlot.setRenderer(iSeries, serierRenderer);
1343
1344 serierRenderer.setSeriesPaint(0, colors[iColor]);
1345 serierRenderer.setSeriesStroke(0, strokes[iStroke]);
1346
1347 //Form here New with JCheckBox
1348 JCheckBox cbi = new JCheckBox(
1349 CounterID.valueOf(headers[iSeries]).getPrettyName());
1350 cbi.setForeground(colors[iColor]);
1351 cbi.setToolTipText(String.format("<html><body width='%1s'>"
1352 + CounterID.valueOf(headers[iSeries]).getDescription()
1353 + ".</html>", 300));
1354
1355 // We do this before setting the listener to avoid having to bypass
1356 if (iSeries!=0)
1357 {
1358 serierRenderer.setSeriesVisible(0, false);
1359 } else {
1360 nameFirstMonitorSeries = cbi.getText();
1361 cbi.setSelected(true);
1362 }
1363
1364 cbi.addItemListener(new ItemListener(){
1365 @Override
1366 public void itemStateChanged(ItemEvent e)
1367 {
1368 if (cbi.isSelected())
1369 {
1370 serierRenderer.setSeriesVisible(0, true);
1371 } else {
1372 serierRenderer.setSeriesVisible(0, false);
1373 }
1374 }
1375 });
1377
1378 // Restart color sequence from beginning
1379 iColor++;
1380 if (iColor >= colors.length)
1381 {
1382 iColor = 0;
1383 if (iStroke < strokes.length-1)
1384 {
1385 iStroke++;
1386 } else {
1387 iStroke = 0;
1388 }
1389 }
1390 }
1391
1392 // Create the actual panel that contains the chart
1393 monitorChartPanel = new ChartPanel(monitorChart);
1394
1395 // Adapt chart size to the size of the panel
1396 rightDownPanel.addComponentListener(new ComponentAdapter() {
1397 @Override
1398 public void componentResized(ComponentEvent e) {
1399 monitorChartPanel.setMaximumDrawHeight(e.getComponent().getHeight());
1400 monitorChartPanel.setMaximumDrawWidth(e.getComponent().getWidth());
1401 monitorChartPanel.setMinimumDrawWidth(e.getComponent().getWidth());
1402 monitorChartPanel.setMinimumDrawHeight(e.getComponent().getHeight());
1403 // WARNING: this update is needed to make the new size affective
1404 // also after movement of the JSplitPane divider, which is
1405 // otherwise felt by this listener but the new sizes do not
1406 // take effect.
1407 ChartEditor ce = ChartEditorManager.getChartEditor(monitorChart);
1408 ce.updateChart(monitorChart);
1409 }
1410 });
1411
1412 rightDownPanel.add(monitorChartPanel,BorderLayout.CENTER);
1413 }
1414
1415//------------------------------------------------------------------------------
1416
1417 private List<CandidateLW> getOverlappingItems(CandidateLW item,
1418 int maxNeighbours)
1419 {
1420 int initPos = allIndividuals.indexOf(item);
1421 double toleranceY = Math.abs(evoPlot.getRangeAxis()
1422 .getRange().getLength() * 0.02);
1423
1424 double toleranceX = Math.abs(evoPlot.getDomainAxis()
1425 .getRange().getLength() * 0.01);
1426 int nItems = 0;
1427 List<CandidateLW> overlappingItems =
1428 new ArrayList<CandidateLW>();
1429 while (nItems<maxNeighbours &&
1430 (initPos+nItems)<allIndividuals.size())
1431 {
1432 CandidateLW c = allIndividuals.get(initPos + nItems);
1433 if (!c.hasFitness())
1434 {
1435 nItems++;
1436 continue;
1437 }
1438 double deltaY = Math.abs(item.getFitness()
1439 - c.getFitness());
1440 if (deltaY > toleranceY)
1441 break;
1442 double deltaX = Math.abs(item.getGeneration()
1443 - c.getGeneration());
1444 if (deltaX > toleranceX)
1445 break;
1446 overlappingItems.add(c);
1447 nItems++;
1448 }
1449 nItems = 1;
1450 while (nItems<maxNeighbours && (initPos-nItems)>-1)
1451 {
1452 CandidateLW c = allIndividuals.get(initPos - nItems);
1453 if (!c.hasFitness())
1454 {
1455 nItems++;
1456 continue;
1457 }
1458 double deltaY = Math.abs(item.getFitness()
1459 - c.getFitness());
1460 if (deltaY > toleranceY)
1461 break;
1462 double deltaX = Math.abs(item.getGeneration()
1463 - c.getGeneration());
1464 if (deltaX > toleranceX)
1465 break;
1466 overlappingItems.add(0,c);
1467 nItems++;
1468 }
1469 return overlappingItems;
1470 }
1471
1472//------------------------------------------------------------------------------
1473
1475 List<CandidateLW> overlappingItems)
1476 {
1477 switch (overlappingItems.size())
1478 {
1479 case 0:
1480 return null;
1481 case 1:
1482 return overlappingItems.get(0);
1483 }
1484
1485 DefaultListModel<String> listModel = new DefaultListModel<String>();
1486 JList<String> optionsList = new JList<String>(listModel);
1487 overlappingItems.stream().forEach(c -> listModel.addElement(c.getName()));
1488 optionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1489
1490 JPanel chooseItem = new JPanel();
1491 JLabel header = new JLabel("Select item to visualize:");
1492 JScrollPane scrollPane = new JScrollPane(optionsList);
1493 chooseItem.add(header);
1494 chooseItem.add(scrollPane);
1495
1496 int res = JOptionPane.showConfirmDialog(parent,
1497 chooseItem,
1498 "Choose Among Overlapping Items",
1499 JOptionPane.OK_CANCEL_OPTION,
1500 JOptionPane.PLAIN_MESSAGE,
1501 null);
1502 if (res != JOptionPane.OK_OPTION)
1503 {
1504 return null;
1505 }
1506 return overlappingItems.get(optionsList.getSelectedIndex());
1507 }
1508
1509//------------------------------------------------------------------------------
1510
1511 private class PlottedCandidatesComparator implements Comparator<CandidateLW>
1512 {
1513 @Override
1515 {
1516 int byGen = Integer.compare(c1.getGeneration(), c2.getGeneration());
1517 if (byGen!=0)
1518 return byGen;
1519 if (c1.hasFitness() && c2.hasFitness())
1520 return Double.compare(c1.getFitness(), c2.getFitness());
1521 else if (c1.hasFitness())
1522 return 1;
1523 else if (c2.hasFitness())
1524 return -1;
1525 return 0;
1526 }
1527 }
1528
1529//-----------------------------------------------------------------------------
1530
1532 {
1533 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1534 // Update series of selected (chart is updated automatically)
1535 double[][] selectedCandsData = new double[2][1]; //NB: for now allow only one
1536 int j = -1;
1537 for (int i=0; i<1; i++) //NB: for now allow only one selected item
1538 {
1539 j++;
1540 selectedCandsData[0][j] = item.getGeneration();
1541 selectedCandsData[1][j] = item.getFitness();
1542 }
1543 datasetSelected.removeSeries("Selected_candidates");
1544 datasetSelected.addSeries("Selected_candidates", selectedCandsData);
1545 // NB the '0' is determined by initialization at HERE@HERE
1546 evoPlot.setDataset(0, datasetSelected);
1547
1548 // Update the molecular viewer
1551 openSingleGraph.setEnabled(true);
1552
1553 mainPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1554 }
1555
1556//-----------------------------------------------------------------------------
1557
1559 {
1560 datasetSelected.removeSeries("Selected_candidates");
1561 //TODO: we could avoid 'zap-ping' jmol by covering it with an opaque card
1562 molViewer.clearAll(false);
1563 openSingleGraph.setEnabled(false);
1564 }
1565
1566//-----------------------------------------------------------------------------
1567
1568}
General set of constants used in DENOPTIM.
static final String FITFILENAMEEXTOUT
Ending and extension of output file of external fitness provider.
static void mergeIntoOneFile(String destinationPathname, List< String > sourcePathnames)
Copies the content of all the files specified in the list of sources and places it into the destinati...
Definition: FileUtils.java:768
A light-weight candidate is a very low-demanding collection of data upon a specific candidate item.
void setGeneration(int genId)
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.
Modal dialog that asks the user for a generation number.
A panel that allows to inspect the output of an artificial evolution experiment.
static final long serialVersionUID
Version UID.
final BasicStroke[] strokes
Predefined line strokes.
Map< CounterID, DefaultXYDataset > monitorDatasets
void readOneGeneration(File genFolder, String summaryName, int genId, Component parent, Map< Integer, double[]> popProperties)
void buildAndFillMonitorPlot(File runFolder, JComponent parent)
Modal dialog to display visual examples of line colors and strokes.
void renderViewWithSelectedItem(CandidateLW item)
Map< Integer, List< String > > candsPerGeneration
Pathways of population members collected by generation id.
String nameFirstMonitorSeries
Records the name of the first series in the monitor plot to facilitate its recovery upon chart reset.
List< CandidateLW > getOverlappingItems(CandidateLW item, int maxNeighbours)
ArrayList< CandidateLW > allIndividuals
void importGARunData(File file, JComponent parent)
static AtomicInteger evolInspectorTabUID
Unique identified for instances of this handler.
JButton openGeneratinGraphs
Button offering the possibility to load the graphs of the population at a given time (i....
ScrollableJPupupMenu monitorSeriesCheckList
JButton openFinalPopGraphs
Button offering the possibility to load the graphs of the final population.
Map< Integer, CandidateLW > candsWithFitnessMap
void initialize()
Initialize the panel and add buttons.
JButton openSingleGraph
Button offering the possibility to load the graph inspector for a selected item.
final Color[] colors
Predefined list of data series colors.
GUIInspectGARun(GUIMainPanel mainPanel)
Constructor.
String pathToSelectedItem
Storage of pathname to the item selected in the chart.
CandidateLW choseAmongPossiblyOverlapping(JComponent parent, List< CandidateLW > overlappingItems)
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.
Object showDialog()
Shows the dialog and restrains the modality to it, until the dialog gets closed.
The collection of tunable preferences.
static boolean showLegenInMonitorPlot
Choice of displaying legend in monitor plot.
static boolean showLegenInEvolutionPlot
Choice of displaying legend in evolution plot.
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.
A popup menu' that has a fixed size and can be scrolled to see menu items that do not fit into the fi...
void showMenu(Component invoker, int x, int y)
Displays the menu with the components that have been added so far.
void addCheckBox(JCheckBox item)
Add a check box to the list of check boxes to display in the menu.
List< JCheckBox > getAllBChekBoxes()
Returns the list of check boxes that is displayed in the menu.
static String getTempFile(String tmpFileName)
Returns the pathname to a tmp file.
Definition: Utils.java:36
Utility methods for input/output.
static List< String > readPopulationMemberPathnames(File file)
Read the pathnames to the population members from a FileFormat#GENSUMMARY file.
static double[] readPopulationProps(File file)
Read the min, max, mean, and median of a population from FileFormat#GENSUMMARY file.
static List< CandidateLW > readLightWeightCandidate(File file)
Read only selected data from a GA produced items.
static ArrayList< String > readList(String fileName)
Read list of data as text.
static List< CandidateLW > readPopulationMembersTraces(File file)
Read the minimal info that can be found in a FileFormat#GENSUMMARY file about the members of a popula...
static String getPaddedString(int count, int number)
returns the padded string with zeroes placed to the left of 'number' up to reach the desired number o...
Identifier of a counter.
Definition: CounterID.java:29
String getPrettyName()
Returns a string representing the mane of this counter in a way that is pretty enough to be shown in ...
Definition: CounterID.java:349