edu.cmu.tetradapp.editor.search.AlgorithmCard Maven / Gradle / Ivy
/*
* Copyright (C) 2019 University of Pittsburgh.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package edu.cmu.tetradapp.editor.search;
import edu.cmu.tetrad.algcomparison.algorithm.Algorithm;
import edu.cmu.tetrad.algcomparison.algorithm.AlgorithmFactory;
import edu.cmu.tetrad.algcomparison.algorithm.oracle.cpdag.SingleGraphAlg;
import edu.cmu.tetrad.algcomparison.utils.HasKnowledge;
import edu.cmu.tetrad.algcomparison.utils.TakesExternalGraph;
import edu.cmu.tetrad.annotation.*;
import edu.cmu.tetrad.data.*;
import edu.cmu.tetrad.util.TetradLogger;
import edu.cmu.tetradapp.app.TetradDesktop;
import edu.cmu.tetradapp.model.GeneralAlgorithmRunner;
import edu.cmu.tetradapp.ui.PaddingPanel;
import edu.cmu.tetradapp.ui.model.*;
import edu.cmu.tetradapp.util.DesktopController;
import javax.swing.*;
import javax.swing.LayoutStyle.ComponentPlacement;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.*;
/**
* Apr 15, 2019 11:31:10 AM
*
* @author Kevin V. Bui ([email protected])
*/
public class AlgorithmCard extends JPanel {
private static final long serialVersionUID = -7552068626783685630L;
// private static final Logger LOGGER = LoggerFactory.getLogger(AlgorithmCard.class);
private final String ALGO_PARAM = "algo";
private final String IND_TEST_PARAM = "ind_test";
private final String SCORE_PARAM = "score";
private final String ALGO_TYPE_PARAM = "algo_type";
private final String DATASET_FILTER = "dataset_filter";
private final String KNOWLEDGE_PARAM = "knowledge";
private final List algoTypeOpts = new ArrayList<>();
private final DefaultListModel algoModels = new DefaultListModel<>();
private final ButtonGroup algoFilterBtnGrp = new ButtonGroup();
private final ButtonGroup datasetFilterBtnGrp = new ButtonGroup();
private final Map> defaultIndTestModels = new HashMap<>();
private final Map> defaultScoreModels = new HashMap<>();
private final JCheckBox knowledgeChkBox = new JCheckBox("accepts knowledge");
private final JRadioButton linearGaussianRadBtn = new JRadioButton("Linear, Gaussian");
private final JRadioButton mixedRadBtn = new JRadioButton("Mixed Discrete/Gaussian");
private final JRadioButton generalRadBtn = new JRadioButton("General");
private final JRadioButton allRadBtn = new JRadioButton("All");
private final JComboBox indTestComboBox = new JComboBox<>();
private final JComboBox scoreComboBox = new JComboBox<>();
private final JList algorithmList = new JList<>(this.algoModels);
private final JTextArea algoDescTextArea = new JTextArea();
private final JTextArea scoreDescTextArea = new JTextArea();
private final JTextArea testDescTextArea = new JTextArea();
private final GeneralAlgorithmRunner algorithmRunner;
private final DataType dataType;
private final TetradDesktop desktop;
private final boolean multiDataAlgo;
private boolean updatingTestModels;
private boolean updatingScoreModels;
public AlgorithmCard(GeneralAlgorithmRunner algorithmRunner) {
this.algorithmRunner = algorithmRunner;
this.dataType = getDataType(algorithmRunner);
this.desktop = (TetradDesktop) DesktopController.getInstance();
this.multiDataAlgo = algorithmRunner.getSourceGraph() == null && algorithmRunner.getDataModelList().size() > 1;
initComponents();
initListeners();
resetAllSettings();
this.algorithmList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
private void initComponents() {
initDescriptionTextAreas();
JButton resetSettingsBtn = new JButton("Reset All Settings");
resetSettingsBtn.addActionListener(e -> {
resetAllSettings();
});
JPanel westMainSouthPanel = new JPanel(new BorderLayout(0, 10));
westMainSouthPanel.add(new TestAndScorePanel(), BorderLayout.CENTER);
westMainSouthPanel.add(resetSettingsBtn, BorderLayout.SOUTH);
JPanel westMainWestPanel = new JPanel(new BorderLayout(0, 10));
westMainWestPanel.add(new AlgorithmFilterPanel(), BorderLayout.CENTER);
westMainWestPanel.add(westMainSouthPanel, BorderLayout.SOUTH);
JPanel westMainPanel = new JPanel(new BorderLayout(5, 0));
westMainPanel.add(westMainWestPanel, BorderLayout.WEST);
westMainPanel.add(new AlgorithmListPanel(), BorderLayout.EAST);
JPanel testAndScoreDescPanel = new JPanel();
testAndScoreDescPanel.setLayout(new BoxLayout(testAndScoreDescPanel, BoxLayout.Y_AXIS));
testAndScoreDescPanel.add(new DescriptionPanel("Test Description", this.testDescTextArea));
testAndScoreDescPanel.add(Box.createVerticalStrut(10));
testAndScoreDescPanel.add(new DescriptionPanel("Score Description", this.scoreDescTextArea));
JPanel centerMainPanel = new JPanel(new BorderLayout(0, 10));
centerMainPanel.add(new DescriptionPanel("Algorithm Description", this.algoDescTextArea), BorderLayout.CENTER);
centerMainPanel.add(testAndScoreDescPanel, BorderLayout.SOUTH);
centerMainPanel.setPreferredSize(new Dimension(235, 200));
setLayout(new BorderLayout(10, 0));
add(westMainPanel, BorderLayout.WEST);
add(centerMainPanel, BorderLayout.CENTER);
if (this.algorithmRunner.hasMissingValues()) {
setPreferredSize(new Dimension(308, 291));
} else {
setPreferredSize(new Dimension(308, 241));
}
}
private void initListeners() {
this.knowledgeChkBox.addActionListener(e -> {
refreshAlgorithmList();
});
this.linearGaussianRadBtn.addActionListener(e -> {
refreshTestAndScoreList();
});
this.mixedRadBtn.addActionListener(e -> {
refreshTestAndScoreList();
});
this.generalRadBtn.addActionListener(e -> {
refreshTestAndScoreList();
});
this.allRadBtn.addActionListener(e -> {
refreshTestAndScoreList();
});
this.algorithmList.addListSelectionListener(e -> {
if (!(e.getValueIsAdjusting() || this.algorithmList.isSelectionEmpty())) {
setAlgorithmDescription();
refreshTestAndScoreList();
validateAlgorithmOption();
}
});
this.indTestComboBox.addActionListener(e -> {
if (!this.updatingTestModels && this.indTestComboBox.getSelectedIndex() >= 0) {
setIndepTestDescription();
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
Map map = this.defaultIndTestModels.get(algoModel);
if (map == null) {
map = new EnumMap<>(DataType.class);
this.defaultIndTestModels.put(algoModel, map);
}
map.put(this.dataType, this.indTestComboBox.getItemAt(this.indTestComboBox.getSelectedIndex()));
}
});
this.scoreComboBox.addActionListener(e -> {
if (!this.updatingScoreModels && this.scoreComboBox.getSelectedIndex() >= 0) {
setScoreDescription();
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
Map map = this.defaultScoreModels.get(algoModel);
if (map == null) {
map = new EnumMap<>(DataType.class);
this.defaultScoreModels.put(algoModel, map);
}
map.put(this.dataType, this.scoreComboBox.getItemAt(this.scoreComboBox.getSelectedIndex()));
}
});
}
private void initDescriptionTextAreas() {
this.algoDescTextArea.setWrapStyleWord(true);
this.algoDescTextArea.setLineWrap(true);
this.algoDescTextArea.setEditable(false);
this.scoreDescTextArea.setWrapStyleWord(true);
this.scoreDescTextArea.setLineWrap(true);
this.scoreDescTextArea.setEditable(false);
this.scoreDescTextArea.setRows(6);
this.testDescTextArea.setWrapStyleWord(true);
this.testDescTextArea.setLineWrap(true);
this.testDescTextArea.setEditable(false);
this.testDescTextArea.setRows(6);
}
private DataType getDataType(GeneralAlgorithmRunner algorithmRunner) {
DataModelList dataModelList = algorithmRunner.getDataModelList();
if (dataModelList.containsEmptyData()) {
if (algorithmRunner.getSourceGraph() == null) {
return null;
} else {
return DataType.Graph;
}
} else {
DataModel dataSet = dataModelList.get(0);
if (dataSet.isContinuous() && !(dataSet instanceof ICovarianceMatrix)) {
// covariance dataset is continuous at the same time - Zhou
return DataType.Continuous;
} else if (dataSet.isDiscrete()) {
return DataType.Discrete;
} else if (dataSet.isMixed()) {
return DataType.Mixed;
} else if (dataSet instanceof ICovarianceMatrix) { // Better to add an isCovariance() - Zhou
return DataType.Covariance;
} else {
return null;
}
}
}
public AlgorithmModel getSelectedAlgorithm() {
return this.algorithmList.getSelectedValue();
}
public IndependenceTestModel getSelectedIndependenceTest() {
if (this.indTestComboBox.isEnabled()) {
return this.indTestComboBox.getItemAt(this.indTestComboBox.getSelectedIndex());
}
return null;
}
public ScoreModel getSelectedScore() {
if (this.scoreComboBox.isEnabled()) {
this.scoreComboBox.getItemAt(this.scoreComboBox.getSelectedIndex());
}
return null;
}
private void rememberUserAlgoSelections(Map userAlgoSelections) {
userAlgoSelections.put(this.IND_TEST_PARAM, this.indTestComboBox.getSelectedItem());
userAlgoSelections.put(this.SCORE_PARAM, this.scoreComboBox.getSelectedItem());
userAlgoSelections.put(this.ALGO_TYPE_PARAM, this.algoFilterBtnGrp.getSelection().getActionCommand());
userAlgoSelections.put(this.DATASET_FILTER, this.datasetFilterBtnGrp.getSelection().getActionCommand());
userAlgoSelections.put(this.KNOWLEDGE_PARAM, this.knowledgeChkBox.isSelected());
// When there's a search result, we store the algo string name from the search so we wont' lose it
// when the upstream nodes change.
// Otherwise, we use the one that users selcted on the UI - Zhou
if (this.algorithmRunner.getGraphs() != null && !this.algorithmRunner.getGraphs().isEmpty()) {
userAlgoSelections.put(this.ALGO_PARAM, this.algorithmRunner.getAlgorithm().getClass().getAnnotation(edu.cmu.tetrad.annotation.Algorithm.class).name());
} else {
userAlgoSelections.put(this.ALGO_PARAM, this.algorithmList.getSelectedValue().toString());
}
}
/**
* This restore mechanism won't restore user selections other than selected algo name when user changes the upstream
* (after clicking the "Execute" button), because a new algo algorithmRunner is created and we lose the stored
* models from the old algorithmRunner - Zhou
*
* // * @param models
*/
private void restoreUserAlgoSelections(Map userAlgoSelections) {
Object obj = userAlgoSelections.get(this.DATASET_FILTER);
if ((obj != null) && (obj instanceof String)) {
String actCmd = String.valueOf(obj);
for (Enumeration e = this.datasetFilterBtnGrp.getElements(); e.hasMoreElements(); ) {
JRadioButton radBtn = (JRadioButton) e.nextElement();
if (radBtn.getActionCommand().equals(actCmd)) {
radBtn.setSelected(true);
break;
}
}
}
obj = userAlgoSelections.get(this.KNOWLEDGE_PARAM);
if ((obj != null) && (obj instanceof Boolean)) {
this.knowledgeChkBox.setSelected((Boolean) obj);
}
obj = userAlgoSelections.get(this.ALGO_TYPE_PARAM);
if ((obj != null) && (obj instanceof String)) {
String actCmd = String.valueOf(obj);
Optional opt = this.algoTypeOpts.stream()
.filter(e -> e.getActionCommand().equals(actCmd))
.findFirst();
opt.ifPresent(jRadioButton -> jRadioButton.setSelected(true));
}
refreshAlgorithmList();
refreshTestAndScoreList();
// Restore the algo name from search when there's a search result.
// Otherwise use the stored name form algorithmRunner.getModels(), which will be lost when the upstream nodes change - Zhou
String selectedAlgoName = null;
if (this.algorithmRunner.getGraphs() != null && this.algorithmRunner.getGraphs().size() > 0) {
selectedAlgoName = this.algorithmRunner.getAlgorithm().getClass().getAnnotation(edu.cmu.tetrad.annotation.Algorithm.class).name();
} else {
obj = userAlgoSelections.get(this.ALGO_PARAM);
if ((obj != null) && (obj instanceof String)) {
selectedAlgoName = (String) obj;
}
}
Enumeration enums = this.algoModels.elements();
while (enums.hasMoreElements()) {
AlgorithmModel model = enums.nextElement();
if (model.toString().equals(selectedAlgoName)) {
this.algorithmList.setSelectedValue(model, true);
break;
}
}
obj = userAlgoSelections.get(this.IND_TEST_PARAM);
if ((obj != null) && (obj instanceof IndependenceTestModel)) {
String value = obj.toString();
ComboBoxModel comboBoxModels = this.indTestComboBox.getModel();
int size = comboBoxModels.getSize();
for (int i = 0; i < size; i++) {
IndependenceTestModel model = comboBoxModels.getElementAt(i);
if (model.toString().equals(value)) {
userAlgoSelections.put(this.IND_TEST_PARAM, model);
this.indTestComboBox.getModel().setSelectedItem(model);
break;
}
}
}
obj = userAlgoSelections.get(this.SCORE_PARAM);
if ((obj != null) && (obj instanceof ScoreModel)) {
String value = obj.toString();
ComboBoxModel comboBoxModels = this.scoreComboBox.getModel();
int size = comboBoxModels.getSize();
for (int i = 0; i < size; i++) {
ScoreModel model = comboBoxModels.getElementAt(i);
if (model.toString().equals(value)) {
userAlgoSelections.put(this.SCORE_PARAM, model);
this.scoreComboBox.getModel().setSelectedItem(model);
break;
}
}
}
}
public void refresh() {
restoreUserAlgoSelections(this.algorithmRunner.getUserAlgoSelections());
}
public void saveStates() {
rememberUserAlgoSelections(this.algorithmRunner.getUserAlgoSelections());
}
/**
* Initialize algorithm
*
* @param algoModel
* @param indTestModel
* @param scoreModel
* @return Algorithm
*/
public Algorithm getAlgorithmFromInterface(AlgorithmModel algoModel, IndependenceTestModel indTestModel, ScoreModel scoreModel) {
Class algoClass = algoModel.getAlgorithm().clazz();
Class indTestClass = (indTestModel == null) ? null : indTestModel.getIndependenceTest().clazz();
Class scoreClass = (scoreModel == null) ? null : scoreModel.getScore().clazz();
Algorithm algorithm = null;
try {
algorithm = AlgorithmFactory.create(algoClass, indTestClass, scoreClass);
} catch (IllegalAccessException | InstantiationException | InvocationTargetException exception) {
TetradLogger.getInstance().forceLogMessage(exception.toString());
}
// Those pairwise algos (R3, RShew, Skew..) require source graph to initialize - Zhou
if (algorithm != null && algorithm instanceof TakesExternalGraph && this.algorithmRunner.getSourceGraph() != null && !this.algorithmRunner.getDataModelList().isEmpty()) {
Algorithm externalGraph = new SingleGraphAlg(this.algorithmRunner.getSourceGraph());
((TakesExternalGraph) algorithm).setExternalGraph(externalGraph);
}
return algorithm;
}
public boolean isAllValid() {
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
IndependenceTestModel indTestModel = this.indTestComboBox.getItemAt(this.indTestComboBox.getSelectedIndex());
ScoreModel scoreModel = this.scoreComboBox.getItemAt(this.scoreComboBox.getSelectedIndex());
boolean missingTest = algoModel.isRequiredTest() && (indTestModel == null);
boolean missingScore = algoModel.isRequiredScore() && (scoreModel == null);
if (missingTest && missingScore) {
String msg = String.format("%s requires both test and score.",
algoModel.getAlgorithm().annotation().name());
JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE);
return false;
} else if (missingTest) {
String msg = String.format("%s requires independence test.",
algoModel.getAlgorithm().annotation().name());
JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE);
return false;
} else if (missingScore) {
String msg = String.format("%s requires score.",
algoModel.getAlgorithm().annotation().name());
JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE);
return false;
} else {
this.algorithmRunner.setAlgorithm(getAlgorithmFromInterface(algoModel, indTestModel, scoreModel));
return true;
}
}
private void validateAlgorithmOption() {
firePropertyChange("algoFwdBtn", null, true);
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
Class algoClass = algoModel.getAlgorithm().clazz();
if (algoClass.isAnnotationPresent(Nonexecutable.class)) {
String msg;
try {
Object algo = algoClass.newInstance();
Method m = algoClass.getDeclaredMethod("getDescription");
m.setAccessible(true);
try {
msg = String.valueOf(m.invoke(algo));
} catch (InvocationTargetException exception) {
msg = "";
}
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException exception) {
TetradLogger.getInstance().forceLogMessage(exception.toString());
msg = "";
}
firePropertyChange("algoFwdBtn", null, false);
JOptionPane.showMessageDialog(this.desktop, msg, "Please Note", JOptionPane.INFORMATION_MESSAGE);
} else {
// Check if initial graph is provided for those pairwise algorithms
if (TakesExternalGraph.class.isAssignableFrom(algoClass)) {
if (this.algorithmRunner.getSourceGraph() == null || this.algorithmRunner.getDataModelList().isEmpty()) {
try {
Object algo = algoClass.newInstance();
Method m = algoClass.getDeclaredMethod("setExternalGraph", Algorithm.class);
m.setAccessible(true);
try {
Algorithm algorithm = null;
m.invoke(algo, algorithm);
} catch (InvocationTargetException | IllegalArgumentException exception) {
firePropertyChange("algoFwdBtn", null, false);
JOptionPane.showMessageDialog(this.desktop, exception.getCause().getMessage(), "Please Note", JOptionPane.INFORMATION_MESSAGE);
}
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException exception) {
TetradLogger.getInstance().forceLogMessage(exception.toString());
}
}
}
// SVAR (SvarFci, SvarGfci) algorithms need lagged data
String cmd = algoModel.getAlgorithm().annotation().command();
if (cmd.equalsIgnoreCase("ts-fci")
|| cmd.equalsIgnoreCase("ts-gfci")
|| cmd.equalsIgnoreCase("ts-imgs")) {
DataModel dataModel = this.algorithmRunner.getDataModel();
Knowledge knowledge = this.algorithmRunner.getKnowledge();
if ((knowledge == null || knowledge.isEmpty())
&& (dataModel.getKnowledge() == null || dataModel.getKnowledge().isEmpty())) {
firePropertyChange("algoFwdBtn", null, false);
JOptionPane.showMessageDialog(this.desktop, "Time-series algorithm needs lagged data", "Please Note", JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
private void refreshAlgorithmList() {
this.algoModels.clear();
ButtonModel selectedAlgoType = this.algoFilterBtnGrp.getSelection();
if (selectedAlgoType != null) {
AlgorithmModels algorithmModels = AlgorithmModels.getInstance();
String algoType = selectedAlgoType.getActionCommand();
if ("all".equals(algoType)) {
if (this.knowledgeChkBox.isSelected()) {
algorithmModels.getModels(this.dataType, this.multiDataAlgo).stream()
.filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().clazz()))
.forEach(e -> this.algoModels.addElement(e));
} else {
algorithmModels.getModels(this.dataType, this.multiDataAlgo).stream()
.forEach(e -> this.algoModels.addElement(e));
}
} else {
if (this.knowledgeChkBox.isSelected()) {
algorithmModels.getModels(AlgType.valueOf(algoType), this.dataType, this.multiDataAlgo).stream()
.filter(e -> HasKnowledge.class.isAssignableFrom(e.getAlgorithm().clazz()))
.forEach(e -> this.algoModels.addElement(e));
} else {
algorithmModels.getModels(AlgType.valueOf(algoType), this.dataType, this.multiDataAlgo).stream()
.forEach(e -> this.algoModels.addElement(e));
}
}
if (this.algoModels.isEmpty()) {
this.algoDescTextArea.setText("");
firePropertyChange("algoFwdBtn", null, false);
} else {
this.algorithmList.setSelectedIndex(0);
firePropertyChange("algoFwdBtn", null, true);
}
}
this.scoreComboBox.setEnabled(this.scoreComboBox.getItemCount() > 0);
}
private void refreshTestList() {
this.updatingTestModels = true;
this.indTestComboBox.removeAllItems();
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
if (algoModel != null && algoModel.isRequiredTest()) {
List models = IndependenceTestModels.getInstance().getModels(this.dataType);
if (this.linearGaussianRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(LinearGaussian.class))
.forEach(e -> this.indTestComboBox.addItem(e));
} else if (this.mixedRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(Mixed.class))
.forEach(e -> this.indTestComboBox.addItem(e));
} else if (this.generalRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getIndependenceTest().clazz().isAnnotationPresent(General.class))
.forEach(e -> this.indTestComboBox.addItem(e));
} else if (this.allRadBtn.isSelected()) {
models.stream()
.forEach(e -> this.indTestComboBox.addItem(e));
}
}
this.updatingTestModels = false;
if (this.indTestComboBox.getItemCount() > 0) {
this.indTestComboBox.setEnabled(true);
Map map = this.defaultIndTestModels.get(algoModel);
if (map == null) {
map = new EnumMap<>(DataType.class);
this.defaultIndTestModels.put(algoModel, map);
}
IndependenceTestModel testModel = map.get(this.dataType);
if (testModel == null) {
testModel = IndependenceTestModels.getInstance().getDefaultModel(this.dataType);
if (testModel == null) {
testModel = this.indTestComboBox.getItemAt(0);
}
}
this.indTestComboBox.setSelectedItem(testModel);
this.indTestComboBox.getSelectedIndex();
} else {
this.indTestComboBox.setEnabled(false);
}
if (this.indTestComboBox.getSelectedIndex() == -1) {
this.testDescTextArea.setText("");
}
}
private void refreshScoreList() {
this.updatingScoreModels = true;
this.scoreComboBox.removeAllItems();
AlgorithmModel algoModel = this.algorithmList.getSelectedValue();
if (algoModel != null && algoModel.isRequiredScore()) {
List models = ScoreModels.getInstance().getModels(this.dataType);
if (this.linearGaussianRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getScore().clazz().isAnnotationPresent(LinearGaussian.class))
.forEach(e -> this.scoreComboBox.addItem(e));
} else if (this.mixedRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getScore().clazz().isAnnotationPresent(Mixed.class))
.forEach(e -> this.scoreComboBox.addItem(e));
} else if (this.generalRadBtn.isSelected()) {
models.stream()
.filter(e -> e.getScore().clazz().isAnnotationPresent(General.class))
.forEach(e -> this.scoreComboBox.addItem(e));
} else if (this.allRadBtn.isSelected()) {
models.stream()
.forEach(e -> this.scoreComboBox.addItem(e));
}
}
this.updatingScoreModels = false;
if (this.scoreComboBox.getItemCount() > 0) {
this.scoreComboBox.setEnabled(true);
Map map = this.defaultScoreModels.get(algoModel);
if (map == null) {
map = new EnumMap<>(DataType.class);
this.defaultScoreModels.put(algoModel, map);
}
ScoreModel scoreModel = map.get(this.dataType);
if (scoreModel == null) {
scoreModel = ScoreModels.getInstance().getDefaultModel(this.dataType);
if (scoreModel == null) {
scoreModel = this.scoreComboBox.getItemAt(0);
}
}
this.scoreComboBox.setSelectedItem(scoreModel);
} else {
this.scoreComboBox.setEnabled(false);
}
if (this.scoreComboBox.getSelectedIndex() == -1) {
this.scoreDescTextArea.setText("");
}
}
private void refreshTestAndScoreList() {
refreshTestList();
refreshScoreList();
}
private void resetAllSettings() {
// clear cache
this.defaultIndTestModels.clear();
this.defaultScoreModels.clear();
// uncheck all checkboxes
this.datasetFilterBtnGrp.setSelected(this.allRadBtn.getModel(), true);
this.knowledgeChkBox.setSelected(false);
if (!this.algoTypeOpts.isEmpty()) {
this.algoTypeOpts.get(0).setSelected(true);
}
refreshAlgorithmList();
refreshTestList();
refreshScoreList();
}
private void setAlgorithmDescription() {
AlgorithmModel model = this.algorithmList.getSelectedValue();
if (model == null) {
this.algoDescTextArea.setText("");
} else {
this.algoDescTextArea.setText(model.getDescription());
this.algoDescTextArea.setCaretPosition(0);
}
}
private void setScoreDescription() {
ScoreModel model = this.scoreComboBox.getItemAt(this.scoreComboBox.getSelectedIndex());
if (model == null) {
this.scoreDescTextArea.setText("");
} else {
this.scoreDescTextArea.setText(model.getDescription());
this.scoreDescTextArea.setCaretPosition(0);
}
}
private void setIndepTestDescription() {
IndependenceTestModel model = this.indTestComboBox.getItemAt(this.indTestComboBox.getSelectedIndex());
if (model == null) {
this.testDescTextArea.setText("");
} else {
this.testDescTextArea.setText(model.getDescription());
this.testDescTextArea.setCaretPosition(0);
}
}
private static class DescriptionPanel extends JPanel {
private static final long serialVersionUID = 2329356999486712496L;
final String borderTitle;
final Component view;
public DescriptionPanel(String borderTitle, Component view) {
this.borderTitle = borderTitle;
this.view = view;
initComponents();
}
private void initComponents() {
JScrollPane scrollPane = new JScrollPane(this.view);
setBorder(BorderFactory.createTitledBorder(this.borderTitle));
setPreferredSize(new Dimension(235, 150));
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 366, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
.addContainerGap())
);
}
}
private class AlgorithmListPanel extends JPanel {
private static final long serialVersionUID = -7068543172769683902L;
public AlgorithmListPanel() {
this.initComponents();
}
private void initComponents() {
JScrollPane scrollPane = new JScrollPane(algorithmList);
this.setBorder(BorderFactory.createTitledBorder("Choose Algorithm"));
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 206, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)
.addContainerGap())
);
}
}
private class AlgorithmFilterPanel extends JPanel {
private static final long serialVersionUID = -3120503093689632462L;
public AlgorithmFilterPanel() {
this.populateAlgoTypeOptions();
this.initComponents();
}
private void initComponents() {
// Filter based on algo types dropdown
Box algoTypesBox = Box.createVerticalBox();
// Algo types label box
Box algTypesBoxLabelBox = Box.createHorizontalBox();
algTypesBoxLabelBox.add(new JLabel("Show algorithms that: "));
algTypesBoxLabelBox.setAlignmentX(Component.LEFT_ALIGNMENT);
// Add label to containing box
algoTypesBox.add(algTypesBoxLabelBox);
// All option
Box algoTypeOptionAllBox = Box.createHorizontalBox();
algoTypeOptionAllBox.setAlignmentX(Component.LEFT_ALIGNMENT);
// Add all option to containing box
algoTypesBox.add(algoTypeOptionAllBox);
// add radio buttons to panel
if (!algoTypeOpts.isEmpty()) {
Dimension indentSize = new Dimension(10, 20);
algoTypeOpts.forEach(btn -> {
Box box = Box.createHorizontalBox();
box.setAlignmentX(Component.LEFT_ALIGNMENT);
box.add(Box.createRigidArea(indentSize));
box.add(btn);
algoTypesBox.add(box);
});
}
// Is there a prior knowledge file?
Box priorKnowledgeBox = Box.createVerticalBox();
// Add label into this label box to size
Box priorKnowledgeLabelBox = Box.createHorizontalBox();
priorKnowledgeLabelBox.add(new JLabel("Show only: "));
priorKnowledgeLabelBox.setAlignmentX(Component.LEFT_ALIGNMENT);
// Checkbox container
Box priorKnowledgeOptionBox = Box.createHorizontalBox();
priorKnowledgeOptionBox.setAlignmentX(Component.LEFT_ALIGNMENT);
// Add padding and option
priorKnowledgeOptionBox.add(Box.createRigidArea(new Dimension(10, 20)));
priorKnowledgeOptionBox.add(knowledgeChkBox);
// Add to containg box
priorKnowledgeBox.add(priorKnowledgeLabelBox);
priorKnowledgeBox.add(priorKnowledgeOptionBox);
Box algoFiltersBox = Box.createVerticalBox();
algoFiltersBox.setAlignmentX(Component.LEFT_ALIGNMENT);
algoFiltersBox.add(algoTypesBox);
algoFiltersBox.add(Box.createVerticalStrut(10));
algoFiltersBox.add(priorKnowledgeBox);
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createTitledBorder("Algorithm Filters"));
this.add(new PaddingPanel(algoFiltersBox), BorderLayout.CENTER);
}
/**
* Create new radio buttons and add them to both the radio button list and radio button group.
*/
private void populateAlgoTypeOptions() {
JRadioButton showAllRadBtn = new JRadioButton("show all");
showAllRadBtn.setActionCommand("all");
showAllRadBtn.addActionListener(e -> {
AlgorithmCard.this.refreshAlgorithmList();
});
algoTypeOpts.add(showAllRadBtn);
algoFilterBtnGrp.add(showAllRadBtn);
Arrays.stream(AlgType.values()).forEach(item -> {
String name = item.name();
JRadioButton radioButton = new JRadioButton(name.replace("_", " "));
radioButton.setActionCommand(name);
radioButton.addActionListener(e -> {
AlgorithmCard.this.refreshAlgorithmList();
});
algoTypeOpts.add(radioButton);
algoFilterBtnGrp.add(radioButton);
});
}
}
private class TestAndScorePanel extends JPanel {
private static final long serialVersionUID = -1594897454478052884L;
public TestAndScorePanel() {
this.initComponents();
}
private void initComponents() {
linearGaussianRadBtn.setActionCommand("linear-gaussian");
mixedRadBtn.setActionCommand("mixed");
generalRadBtn.setActionCommand("general");
allRadBtn.setActionCommand("all");
datasetFilterBtnGrp.add(linearGaussianRadBtn);
datasetFilterBtnGrp.add(mixedRadBtn);
datasetFilterBtnGrp.add(generalRadBtn);
datasetFilterBtnGrp.add(allRadBtn);
datasetFilterBtnGrp.setSelected(allRadBtn.getModel(), true);
JLabel assumptionsLabel = new JLabel();
JLabel testLabel = new JLabel();
JLabel scoreLabel = new JLabel();
this.setBorder(BorderFactory.createTitledBorder("Choose Statistical Test and Score"));
assumptionsLabel.setText("Filter by dataset properties:");
testLabel.setText("Test:");
scoreLabel.setText("Score:");
if (algorithmRunner.hasMissingValues()) {
JLabel missingValueAlert = new JLabel();
JLabel testwiseDeletionAlert = new JLabel();
Color red = new Color(255, 0, 0);
missingValueAlert.setForeground(red);
missingValueAlert.setText("Dataset contains missing values;");
testwiseDeletionAlert.setForeground(red);
testwiseDeletionAlert.setText("testwise deletion will be used.");
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(testLabel)
.addComponent(scoreLabel))
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(indTestComboBox, 0, 239, Short.MAX_VALUE)
.addComponent(scoreComboBox, 0, 239, Short.MAX_VALUE)))
.addComponent(assumptionsLabel)
.addGroup(layout.createSequentialGroup()
// .addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(mixedRadBtn)
.addComponent(linearGaussianRadBtn)
.addComponent(generalRadBtn)
.addComponent(allRadBtn)))
.addComponent(missingValueAlert)
.addComponent(testwiseDeletionAlert))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(assumptionsLabel)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(linearGaussianRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(mixedRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(generalRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(allRadBtn)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(missingValueAlert)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(testwiseDeletionAlert)
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(testLabel)
.addComponent(indTestComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(scoreComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(scoreLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
} else {
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(testLabel)
.addComponent(scoreLabel))
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(indTestComboBox, 0, 239, Short.MAX_VALUE)
.addComponent(scoreComboBox, 0, 239, Short.MAX_VALUE)))
.addComponent(assumptionsLabel)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(mixedRadBtn)
.addComponent(linearGaussianRadBtn)
.addComponent(generalRadBtn)
.addComponent(allRadBtn))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(assumptionsLabel)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(linearGaussianRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(mixedRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(generalRadBtn)
// .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(allRadBtn)
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(testLabel)
.addComponent(indTestComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(AlgorithmCard.this.scoreComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(scoreLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}
}
}
}