All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.cmu.tetradapp.editor.LoadDataSettings Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// This program is free software; you can redistribute it and/or modify      //
// it under the terms of the GNU General Public License as published by      //
// the Free Software Foundation; either version 2 of the License, or         //
// (at your option) any later version.                                       //
//                                                                           //
// This program 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 General Public License for more details.                              //
//                                                                           //
// You should have received a copy of the GNU General Public License         //
// along with this program; if not, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////
package edu.cmu.tetradapp.editor;

import edu.cmu.tetrad.data.DataModel;
import edu.cmu.tetrad.util.DataConvertUtils;
import edu.cmu.tetradapp.util.ImageUtils;
import edu.cmu.tetradapp.util.IntTextField;
import edu.cmu.tetradapp.util.StringTextField;
import edu.pitt.dbmi.data.reader.*;
import edu.pitt.dbmi.data.reader.covariance.CovarianceData;
import edu.pitt.dbmi.data.reader.covariance.CovarianceDataReader;
import edu.pitt.dbmi.data.reader.covariance.LowerCovarianceDataFileReader;
import edu.pitt.dbmi.data.reader.metadata.Metadata;
import edu.pitt.dbmi.data.reader.metadata.MetadataFileReader;
import edu.pitt.dbmi.data.reader.metadata.MetadataReader;
import edu.pitt.dbmi.data.reader.tabular.TabularColumnFileReader;
import edu.pitt.dbmi.data.reader.tabular.TabularColumnReader;
import edu.pitt.dbmi.data.reader.tabular.TabularDataFileReader;
import edu.pitt.dbmi.data.reader.tabular.TabularDataReader;
import edu.pitt.dbmi.data.reader.util.TextFileUtils;
import edu.pitt.dbmi.data.reader.validation.ValidationResult;
import edu.pitt.dbmi.data.reader.validation.covariance.CovarianceValidation;
import edu.pitt.dbmi.data.reader.validation.covariance.LowerCovarianceDataFileValidation;
import edu.pitt.dbmi.data.reader.validation.tabular.TabularColumnFileValidation;
import edu.pitt.dbmi.data.reader.validation.tabular.TabularColumnValidation;
import edu.pitt.dbmi.data.reader.validation.tabular.TabularDataFileValidation;
import edu.pitt.dbmi.data.reader.validation.tabular.TabularDataValidation;

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.io.Serial;
import java.util.List;
import java.util.*;
import java.util.prefs.Preferences;

/**
 * Panel (to be put in a dialog) for letting the user choose how a data file should be loaded.
 *
 * @author josephramsey
 * @version $Id: $Id
 */
public final class LoadDataSettings extends JPanel {

    @Serial
    private static final long serialVersionUID = -7597768949622586036L;

    /**
     * The files to be loaded.
     */
    private final List files;

    /**
     * The color of the separator lines.
     */
    private final Color separatorColor;

    /**
     * The size of the labels.
     */
    private final Dimension labelSize;

    /**
     * The metadata file.
     */
    private File metadataFile;

    /**
     * The metadata.
     */
    private Metadata metadata;

    /**
     * The first row variable names: yes radio button.
     */
    private JRadioButton firstRowVarNamesYesRadioButton;

    /**
     * The first row variable names: no radio button.
     */
    private JRadioButton firstRowVarNamesNoRadioButton;

    /**
     * The tabular data radio button.
     */
    private JRadioButton tabularRadioButton;

    /**
     * The covariance data radio button.
     */
    private JRadioButton covarianceRadioButton;

    /**
     * The continuous data radio button.
     */
    private JRadioButton contRadioButton;

    /**
     * The discrete data radio button.
     */
    private JRadioButton discRadioButton;

    /**
     * The mixed data radio button.
     */
    private JRadioButton mixedRadioButton;

    /**
     * The maximum number of discrete categories field.
     */
    private IntTextField maxNumOfDiscCategoriesField;

    /**
     * The whitespace delimiter radio button.
     */
    private JRadioButton commentDoubleSlashRadioButton;

    /**
     * The pound delimiter radio button.
     */
    private JRadioButton commentPondRadioButton;

    /**
     * The other delimiter radio button.
     */
    private JRadioButton commentOtherRadioButton;

    /**
     * The comment string field.
     */
    private StringTextField commentStringField;

    /**
     * The whitespace delimiter radio button.
     */
    private JRadioButton whitespaceDelimiterRadioButton;

    /**
     * The single character delimiter radio button.
     */
    private JRadioButton singleCharDelimiterRadioButton;

    /**
     * The single character delimiter combo box.
     */
    private JComboBox singleCharDelimiterComboBox;

    /**
     * The double quote radio button.
     */
    private JRadioButton doubleQuoteRadioButton;

    /**
     * The single quote radio button.
     */
    private JRadioButton singleQuoteRadioButton;

    /**
     * The metadata file button.
     */
    private JButton metadataFileButton;

    /**
     * The first row variable names: yes radio button.
     */
    private JRadioButton idNoneRadioButton;

    /**
     * The first row variable names: yes radio button.
     */
    private JRadioButton idUnlabeledFirstColRadioButton;

    /**
     * The first row variable names: yes radio button.
     */
    private JRadioButton idLabeledColRadioButton;

    /**
     * The first row variable names: yes radio button.
     */
    private StringTextField idStringField;

    /**
     * The missing value: star radio button.
     */
    private JRadioButton missingValueStarRadioButton;

    /**
     * The missing value: question radio button.
     */
    private JRadioButton missingValueQuestionRadioButton;

    /**
     * The missing value: other radio button.
     */
    private StringTextField missingStringField;

    //================================CONSTRUCTOR=======================//

    /**
     * 

Constructor for LoadDataSettings.

* * @param files a {@link java.util.List} object */ public LoadDataSettings(List files) { this.files = files; this.metadataFile = null; this.metadata = null; // All labels should share the save size - Zhou this.labelSize = new Dimension(200, 30); this.separatorColor = new Color(221, 221, 221); } // Step 1 items /** *

basicSettings.

* * @return a {@link javax.swing.Box} object * @throws java.io.IOException if any. */ public Box basicSettings() throws IOException { // Data loading params layout Box basicSettingsBox = Box.createVerticalBox(); // Variable names in first row of data? Box firstRowVarNamesBox = Box.createHorizontalBox(); // Yes/No buttons this.firstRowVarNamesYesRadioButton = new JRadioButton("Yes"); this.firstRowVarNamesNoRadioButton = new JRadioButton("No"); // Button group ButtonGroup firstRowVarNamesBtnGrp = new ButtonGroup(); firstRowVarNamesBtnGrp.add(this.firstRowVarNamesYesRadioButton); firstRowVarNamesBtnGrp.add(this.firstRowVarNamesNoRadioButton); // Make Yes button selected by default this.firstRowVarNamesYesRadioButton.setSelected(true); // Event listener this.firstRowVarNamesYesRadioButton.addActionListener((ActionEvent actionEvent) -> { JRadioButton button = (JRadioButton) actionEvent.getSource(); if (button.isSelected()) { // Enable metadata file upload this.metadataFileButton.setEnabled(true); // Enable specifying column labeled option if (!this.idLabeledColRadioButton.isEnabled()) { this.idLabeledColRadioButton.setEnabled(true); } if (!this.idStringField.isEnabled()) { this.idStringField.setEnabled(true); } } }); // When there's no header, disable the metadata button and column exculsions this.firstRowVarNamesNoRadioButton.addActionListener((ActionEvent actionEvent) -> { JRadioButton button = (JRadioButton) actionEvent.getSource(); if (button.isSelected()) { // No need to use metadata file when no header this.metadataFileButton.setEnabled(false); // Disable the "Column labeled" option of ignoring column this.idLabeledColRadioButton.setEnabled(false); this.idStringField.setEnabled(false); } }); // Add label into this label box to size Box firstRowVarNamesLabelBox = Box.createHorizontalBox(); firstRowVarNamesLabelBox.setPreferredSize(this.labelSize); firstRowVarNamesLabelBox.add(new JLabel("First row variable names:")); // Add info icon next to label to show tooltip on mouseover JLabel firstRowVarNamesLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon firstRowVarNamesLabelInfoIcon.setToolTipText("Whether the column variable names are presented in the first row of data"); firstRowVarNamesLabelBox.add(firstRowVarNamesLabelInfoIcon); // Option 1 Box firstRowVarNamesOption1Box = Box.createHorizontalBox(); firstRowVarNamesOption1Box.setPreferredSize(new Dimension(160, 30)); firstRowVarNamesOption1Box.add(this.firstRowVarNamesYesRadioButton); // Option 2 Box firstRowVarNamesOption2Box = Box.createHorizontalBox(); firstRowVarNamesOption2Box.setPreferredSize(new Dimension(160, 30)); firstRowVarNamesOption2Box.add(this.firstRowVarNamesNoRadioButton); // Add to firstRowVarNamesBox firstRowVarNamesBox.add(firstRowVarNamesLabelBox); firstRowVarNamesBox.add(Box.createRigidArea(new Dimension(10, 1))); firstRowVarNamesBox.add(firstRowVarNamesOption1Box); firstRowVarNamesBox.add(firstRowVarNamesOption2Box); firstRowVarNamesBox.add(Box.createHorizontalGlue()); basicSettingsBox.add(firstRowVarNamesBox); // File type: Tabular/Covariance Box fileTypeBox = Box.createHorizontalBox(); this.tabularRadioButton = new JRadioButton("Tabular data"); this.covarianceRadioButton = new JRadioButton("Covariance data (lower triangle)"); // We need to group the radio buttons, otherwise all can be selected ButtonGroup fileTypeBtnGrp = new ButtonGroup(); fileTypeBtnGrp.add(this.tabularRadioButton); fileTypeBtnGrp.add(this.covarianceRadioButton); // Tabular data is selected by default this.tabularRadioButton.setSelected(true); // Event listener this.tabularRadioButton.addActionListener(actionEvent -> { JRadioButton button = (JRadioButton) actionEvent.getSource(); // Just enable disabled buttons, do not change the previous selections - Zhou if (button.isSelected()) { // Enable metadata file upload when there's also column header if (LoadDataSettings.this.firstRowVarNamesYesRadioButton.isSelected()) { LoadDataSettings.this.metadataFileButton.setEnabled(true); } // Enable the discrete/mixed radio button if it's disabled by clicking covariance data if (!LoadDataSettings.this.discRadioButton.isEnabled()) { LoadDataSettings.this.discRadioButton.setEnabled(true); } if (!LoadDataSettings.this.mixedRadioButton.isEnabled()) { LoadDataSettings.this.mixedRadioButton.setEnabled(true); } // Enable variable names in first row if (!LoadDataSettings.this.firstRowVarNamesYesRadioButton.isEnabled()) { LoadDataSettings.this.firstRowVarNamesYesRadioButton.setEnabled(true); } if (!LoadDataSettings.this.firstRowVarNamesNoRadioButton.isEnabled()) { LoadDataSettings.this.firstRowVarNamesNoRadioButton.setEnabled(true); } // Enable case Id options if (!LoadDataSettings.this.idUnlabeledFirstColRadioButton.isEnabled()) { LoadDataSettings.this.idUnlabeledFirstColRadioButton.setEnabled(true); } if (!LoadDataSettings.this.idLabeledColRadioButton.isEnabled()) { LoadDataSettings.this.idLabeledColRadioButton.setEnabled(true); } if (!LoadDataSettings.this.idStringField.isEnabled()) { LoadDataSettings.this.idStringField.setEnabled(true); } } }); // Event listener this.covarianceRadioButton.addActionListener((ActionEvent actionEvent) -> { JRadioButton button = (JRadioButton) actionEvent.getSource(); if (button.isSelected()) { // No need metadata file this.metadataFileButton.setEnabled(false); // When Covariance data is selected, data type can only be Continuous, this.contRadioButton.setSelected(true); //will disallow the users to choose Discrete and mixed data this.discRadioButton.setEnabled(false); this.mixedRadioButton.setEnabled(false); // Both Yes and No of Variable names in first row need to be disabled // Because the first row should be number of cases this.firstRowVarNamesYesRadioButton.setEnabled(false); this.firstRowVarNamesNoRadioButton.setEnabled(false); // select None for Case IDs, disable other options, // since no Case column should be in covariance data this.idNoneRadioButton.setSelected(true); this.idUnlabeledFirstColRadioButton.setEnabled(false); this.idLabeledColRadioButton.setEnabled(false); this.idStringField.setEnabled(false); } }); // Add label into this label box to size Box fileTypeLabelBox = Box.createHorizontalBox(); fileTypeLabelBox.setPreferredSize(this.labelSize); fileTypeLabelBox.add(new JLabel("Data file type:")); // Option 1 Box fileTypeOption1Box = Box.createHorizontalBox(); fileTypeOption1Box.setPreferredSize(new Dimension(160, 30)); fileTypeOption1Box.add(this.tabularRadioButton); // Option 2 Box fileTypeOption2Box = Box.createHorizontalBox(); // Make this longer since the text is long - Zhou fileTypeOption2Box.setPreferredSize(new Dimension(300, 30)); fileTypeOption2Box.add(this.covarianceRadioButton); // Add to file type box fileTypeBox.add(fileTypeLabelBox); fileTypeBox.add(Box.createRigidArea(new Dimension(10, 1))); fileTypeBox.add(fileTypeOption1Box); fileTypeBox.add(fileTypeOption2Box); fileTypeBox.add(Box.createHorizontalGlue()); // Add to format container basicSettingsBox.add(fileTypeBox); // Add seperator line JSeparator separator1 = new JSeparator(SwingConstants.HORIZONTAL); separator1.setForeground(this.separatorColor); basicSettingsBox.add(separator1); // Metadata to interventional dataset Box metadataFileBox = Box.createHorizontalBox(); // Add label into this label box to size Box metadataFileLabelBox = Box.createHorizontalBox(); metadataFileLabelBox.setPreferredSize(this.labelSize); metadataFileLabelBox.add(new JLabel("Metadata JSON file:")); // Add info icon next to label to show tooltip on mouseover JLabel metadataFileLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon metadataFileLabelInfoIcon.setToolTipText("Metadata file is REQUIRED for observational and interventional data"); metadataFileLabelBox.add(metadataFileLabelInfoIcon); // Metadata file load button this.metadataFileButton = new JButton("Load..."); JLabel selectedMetadataFileName = new JLabel("No metadata file slected"); // Add file button listener this.metadataFileButton.addActionListener(e -> { // Show file chooser JFileChooser fileChooser = new JFileChooser(); String sessionSaveLocation = Preferences.userRoot().get("fileSaveLocation", ""); fileChooser.setCurrentDirectory(new File(sessionSaveLocation)); fileChooser.setFileFilter(new FileNameExtensionFilter("*.json", "json")); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); // Only allow to add one file at a time fileChooser.setMultiSelectionEnabled(true); // Customize dialog title bar text fileChooser.setDialogTitle("Load metadata JSON file"); // The second argument sets both the title for the dialog window and the label for the approve button int _ret = fileChooser.showDialog(SwingUtilities.getWindowAncestor(LoadDataSettings.this.metadataFileButton), "Choose"); if (_ret == JFileChooser.CANCEL_OPTION) { return; } // Now we have the interventional metadata file LoadDataSettings.this.metadataFile = fileChooser.getSelectedFile(); // Show the selected file name selectedMetadataFileName.setText(LoadDataSettings.this.metadataFile.getName()); }); // File choose button box Box metadataFileButtonBox = Box.createHorizontalBox(); metadataFileButtonBox.setPreferredSize(new Dimension(680, 30)); metadataFileButtonBox.add(this.metadataFileButton); metadataFileButtonBox.add(Box.createHorizontalStrut(10)); metadataFileButtonBox.add(selectedMetadataFileName); // Put together metadataFileBox.add(metadataFileLabelBox); metadataFileBox.add(Box.createRigidArea(new Dimension(10, 1))); metadataFileBox.add(metadataFileButtonBox); metadataFileBox.add(Box.createHorizontalGlue()); basicSettingsBox.add(metadataFileBox); // Add seperator line JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL); separator.setForeground(this.separatorColor); basicSettingsBox.add(separator); // Vertical gap //basicSettingsBox.add(Box.createVerticalStrut(5)); // Data type - moved from the old Fast tab - Zhou Box dataTypeBox = Box.createHorizontalBox(); // Data type: continuous, discrete, or mixed this.contRadioButton = new JRadioButton("Continuous"); this.discRadioButton = new JRadioButton("Discrete"); this.mixedRadioButton = new JRadioButton("Mixed"); ButtonGroup dataTypeBtnGrp = new ButtonGroup(); dataTypeBtnGrp.add(this.contRadioButton); dataTypeBtnGrp.add(this.discRadioButton); dataTypeBtnGrp.add(this.mixedRadioButton); // Continuous radion button is selected by default this.contRadioButton.setSelected(true); // Add label into this label box to size Box dataTypeLabelBox = Box.createHorizontalBox(); dataTypeLabelBox.setPreferredSize(this.labelSize); dataTypeLabelBox.add(new JLabel("Data type:")); // Option 1 Box dataTypeOption1Box = Box.createHorizontalBox(); dataTypeOption1Box.setPreferredSize(new Dimension(160, 30)); dataTypeOption1Box.add(this.contRadioButton); // Option 2 Box dataTypeOption2Box = Box.createHorizontalBox(); dataTypeOption2Box.setPreferredSize(new Dimension(160, 30)); dataTypeOption2Box.add(this.discRadioButton); // Option 3 Box dataTypeOption3Box = Box.createHorizontalBox(); dataTypeOption3Box.setPreferredSize(new Dimension(320, 30)); dataTypeOption3Box.add(this.mixedRadioButton); // Threshold label JLabel maxDiscCatLabel = new JLabel(", max discrete categories: "); // Add info icon next to label to show tooltip on mouseover JLabel maxDiscCatLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon maxDiscCatLabelInfoIcon.setToolTipText("Integral columns with up to N (specify here) distinct values are discrete."); // Max number of discrete categories this.maxNumOfDiscCategoriesField = new IntTextField(0, 3); // 0 by default this.maxNumOfDiscCategoriesField.setValue(0); this.maxNumOfDiscCategoriesField.setFilter((int value, int oldValue) -> { if (value >= 0) { return value; } else { return oldValue; } }); // Event listener this.maxNumOfDiscCategoriesField.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); // Select the "Mixed" radio button when users click the input field if (!LoadDataSettings.this.mixedRadioButton.isSelected()) { LoadDataSettings.this.mixedRadioButton.setSelected(true); } } }); dataTypeOption3Box.add(maxDiscCatLabel); dataTypeOption3Box.add(maxDiscCatLabelInfoIcon); dataTypeOption3Box.add(this.maxNumOfDiscCategoriesField); dataTypeBox.add(dataTypeLabelBox); dataTypeBox.add(Box.createRigidArea(new Dimension(10, 1))); dataTypeBox.add(dataTypeOption1Box); dataTypeBox.add(dataTypeOption2Box); dataTypeBox.add(dataTypeOption3Box); dataTypeBox.add(Box.createHorizontalGlue()); basicSettingsBox.add(dataTypeBox); // Add seperator line JSeparator separator2 = new JSeparator(SwingConstants.HORIZONTAL); separator2.setForeground(this.separatorColor); basicSettingsBox.add(separator2); //basicSettingsBox.add(Box.createVerticalStrut(5)); // Value Delimiter box Box valueDelimiterBox = Box.createHorizontalBox(); // Value Delimiter this.whitespaceDelimiterRadioButton = new JRadioButton("Whitespace"); this.singleCharDelimiterRadioButton = new JRadioButton("Single character: "); // Dropdown options for commo box String[] singleCharDelimiterOptions = {"Comma", "Colon", "Tab", "Space", "Semicolon", "Pipe"}; //Create the combo box this.singleCharDelimiterComboBox = new JComboBox(singleCharDelimiterOptions); this.singleCharDelimiterComboBox.setMaximumSize(new Dimension(90, 30)); // select first item by default, index starts at 0 this.singleCharDelimiterComboBox.setSelectedIndex(0); ButtonGroup delimiterBtnGrp = new ButtonGroup(); delimiterBtnGrp.add(this.whitespaceDelimiterRadioButton); delimiterBtnGrp.add(this.singleCharDelimiterRadioButton); // Defaults to whitespace if the inferred delimiter is not in Combo box // We can't infer whitespcace. // Otherwise, select the inferred delimiter from ComboBox and // check the singleCharDelimiterRadioButton // Only infer delimiter based on the first file - Zhou char inferredDelimiter = getInferredDelimiter(this.files.get(0)); switch (inferredDelimiter) { case ',': this.singleCharDelimiterRadioButton.setSelected(true); this.singleCharDelimiterComboBox.setSelectedItem("Comma"); break; case '\t': this.singleCharDelimiterRadioButton.setSelected(true); this.singleCharDelimiterComboBox.setSelectedItem("Tab"); break;// Whitespace covers space, so we use whitespace instead of space here case ':': this.singleCharDelimiterRadioButton.setSelected(true); this.singleCharDelimiterComboBox.setSelectedItem("Colon"); break; case ';': this.singleCharDelimiterRadioButton.setSelected(true); this.singleCharDelimiterComboBox.setSelectedItem("Semicolon"); break; case '|': this.singleCharDelimiterRadioButton.setSelected(true); this.singleCharDelimiterComboBox.setSelectedItem("Pipe"); break; default: // Just use whitespace as default if can't infer this.whitespaceDelimiterRadioButton.setSelected(true); break; } // Event listener // ComboBox is actually a container this.singleCharDelimiterComboBox.addActionListener((ActionEvent actionEvent) -> { // Select the "Single character:" radio button when users click the combo box if (!this.singleCharDelimiterRadioButton.isSelected()) { this.singleCharDelimiterRadioButton.setSelected(true); } }); // Add label into this label box to size Box valueDelimiterLabelBox = Box.createHorizontalBox(); valueDelimiterLabelBox.setPreferredSize(this.labelSize); valueDelimiterLabelBox.add(new JLabel("Value delimiter:")); // Add info icon next to label to show tooltip on mouseover JLabel valueDelimiterLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon valueDelimiterLabelInfoIcon.setToolTipText("Delimiter used to seperate the variable names and data values"); valueDelimiterLabelBox.add(valueDelimiterLabelInfoIcon); // Option 1 Box valueDelimiterOption1Box = Box.createHorizontalBox(); valueDelimiterOption1Box.setPreferredSize(new Dimension(160, 30)); valueDelimiterOption1Box.add(this.whitespaceDelimiterRadioButton); // Option 2 Box valueDelimiterOption2Box = Box.createHorizontalBox(); // Make this box wider so we can see the combo box - Zhou valueDelimiterOption2Box.setPreferredSize(new Dimension(300, 30)); valueDelimiterOption2Box.add(this.singleCharDelimiterRadioButton); valueDelimiterOption2Box.add(this.singleCharDelimiterComboBox); valueDelimiterBox.add(valueDelimiterLabelBox); valueDelimiterBox.add(Box.createRigidArea(new Dimension(10, 1))); valueDelimiterBox.add(valueDelimiterOption1Box); valueDelimiterBox.add(valueDelimiterOption2Box); valueDelimiterBox.add(Box.createHorizontalGlue()); basicSettingsBox.add(valueDelimiterBox); // Add seperator line JSeparator separator3 = new JSeparator(SwingConstants.HORIZONTAL); separator3.setForeground(this.separatorColor); basicSettingsBox.add(separator3); // Use a titled border with 5 px inside padding - Zhou final String borderTitle = "Basic Settings (apply to all files)"; basicSettingsBox.setBorder(new CompoundBorder(BorderFactory.createTitledBorder(borderTitle), new EmptyBorder(5, 5, 5, 5))); return basicSettingsBox; } // Step 2 items /** *

advancedSettings.

* * @return a {@link javax.swing.Box} object */ public Box advancedSettings() { // Data loading params layout Box advancedSettingsBox = Box.createVerticalBox(); // Columns to exclude/ignore Box caseIdProvidedBox = Box.createHorizontalBox(); // ID radio buttons this.idNoneRadioButton = new JRadioButton("None"); this.idUnlabeledFirstColRadioButton = new JRadioButton("First column"); this.idLabeledColRadioButton = new JRadioButton("Column labeled: "); this.idStringField = new StringTextField("", 6); ButtonGroup caseIdBtnGrp = new ButtonGroup(); caseIdBtnGrp.add(this.idNoneRadioButton); caseIdBtnGrp.add(this.idUnlabeledFirstColRadioButton); caseIdBtnGrp.add(this.idLabeledColRadioButton); // Defaults to none this.idNoneRadioButton.setSelected(true); // Event listener this.idStringField.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); // Select the "Column labeled:" radio button when users click the text field if (LoadDataSettings.this.idStringField.isEnabled() && !LoadDataSettings.this.idLabeledColRadioButton.isSelected()) { LoadDataSettings.this.idLabeledColRadioButton.setSelected(true); } } }); // Add label into this label box to size Box caseIdProvidedLabelBox = Box.createHorizontalBox(); caseIdProvidedLabelBox.setPreferredSize(this.labelSize); caseIdProvidedLabelBox.add(new JLabel("Case column to exclude/ignore:")); // Option 1 Box caseIdProvidedOption1Box = Box.createHorizontalBox(); caseIdProvidedOption1Box.setPreferredSize(new Dimension(160, 30)); caseIdProvidedOption1Box.add(this.idNoneRadioButton); // Option 2 Box caseIdProvidedOption2Box = Box.createHorizontalBox(); caseIdProvidedOption2Box.setPreferredSize(new Dimension(160, 30)); caseIdProvidedOption2Box.add(this.idUnlabeledFirstColRadioButton); // Option 3 Box caseIdProvidedOption3Box = Box.createHorizontalBox(); // Make this box a little longer because we don't want the text field too small caseIdProvidedOption3Box.setPreferredSize(new Dimension(300, 30)); caseIdProvidedOption3Box.add(this.idLabeledColRadioButton); caseIdProvidedOption3Box.add(this.idStringField); caseIdProvidedBox.add(caseIdProvidedLabelBox); caseIdProvidedBox.add(Box.createRigidArea(new Dimension(10, 1))); caseIdProvidedBox.add(caseIdProvidedOption1Box); caseIdProvidedBox.add(caseIdProvidedOption2Box); caseIdProvidedBox.add(caseIdProvidedOption3Box); caseIdProvidedBox.add(Box.createHorizontalGlue()); advancedSettingsBox.add(caseIdProvidedBox); // Add seperator line JSeparator separator1 = new JSeparator(SwingConstants.HORIZONTAL); separator1.setForeground(this.separatorColor); advancedSettingsBox.add(separator1); //advancedSettingsBox.add(Box.createVerticalStrut(5)); // Comment Marker Box commentMarkerBox = Box.createHorizontalBox(); this.commentDoubleSlashRadioButton = new JRadioButton("//"); this.commentPondRadioButton = new JRadioButton("#"); this.commentOtherRadioButton = new JRadioButton("Other: "); ButtonGroup commentMarkerBtnGrp = new ButtonGroup(); commentMarkerBtnGrp.add(this.commentDoubleSlashRadioButton); commentMarkerBtnGrp.add(this.commentPondRadioButton); commentMarkerBtnGrp.add(this.commentOtherRadioButton); // Comment string field this.commentStringField = new StringTextField("", 6); // Select double slash by default this.commentDoubleSlashRadioButton.setSelected(true); // Event listener this.commentStringField.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); // Select the "Other:" radio button when users click the text field if (!LoadDataSettings.this.commentOtherRadioButton.isSelected()) { LoadDataSettings.this.commentOtherRadioButton.setSelected(true); } } }); // Add label into this label box to size Box commentMarkerLabelBox = Box.createHorizontalBox(); commentMarkerLabelBox.setPreferredSize(this.labelSize); commentMarkerLabelBox.add(new JLabel("Comment marker:")); // Add info icon next to label to show tooltip on mouseover JLabel commentMarkerLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon commentMarkerLabelInfoIcon.setToolTipText("Validation and data loading will ingnore the rows started with the comment marker."); commentMarkerLabelBox.add(commentMarkerLabelInfoIcon); // Option 1 Box commentMarkerOption1Box = Box.createHorizontalBox(); commentMarkerOption1Box.setPreferredSize(new Dimension(160, 30)); commentMarkerOption1Box.add(this.commentDoubleSlashRadioButton); // Option 2 Box commentMarkerOption2Box = Box.createHorizontalBox(); commentMarkerOption2Box.setPreferredSize(new Dimension(160, 30)); commentMarkerOption2Box.add(this.commentPondRadioButton); // Option 3 Box commentMarkerOption3Box = Box.createHorizontalBox(); commentMarkerOption3Box.setPreferredSize(new Dimension(260, 30)); commentMarkerOption3Box.add(this.commentOtherRadioButton); commentMarkerOption3Box.add(this.commentStringField); commentMarkerBox.add(commentMarkerLabelBox); commentMarkerBox.add(Box.createRigidArea(new Dimension(10, 1))); commentMarkerBox.add(commentMarkerOption1Box); commentMarkerBox.add(commentMarkerOption2Box); commentMarkerBox.add(commentMarkerOption3Box); commentMarkerBox.add(Box.createHorizontalGlue()); advancedSettingsBox.add(commentMarkerBox); // Add seperator line JSeparator separator2 = new JSeparator(SwingConstants.HORIZONTAL); separator2.setForeground(this.separatorColor); advancedSettingsBox.add(separator2); //advancedSettingsBox.add(Box.createVerticalStrut(5)); // Quote Character Box quoteCharBox = Box.createHorizontalBox(); JRadioButton noneQuoteRadioButton = new JRadioButton("None"); this.doubleQuoteRadioButton = new JRadioButton("\""); this.singleQuoteRadioButton = new JRadioButton("'"); ButtonGroup quoteCharBtnGrp = new ButtonGroup(); quoteCharBtnGrp.add(noneQuoteRadioButton); quoteCharBtnGrp.add(this.doubleQuoteRadioButton); quoteCharBtnGrp.add(this.singleQuoteRadioButton); // Select None by default noneQuoteRadioButton.setSelected(true); // Add label into this label box to size Box quoteCharLabelBox = Box.createHorizontalBox(); quoteCharLabelBox.setPreferredSize(this.labelSize); quoteCharLabelBox.add(new JLabel("Quote character:")); // Add info icon next to label to show tooltip on mouseover JLabel quoteCharLabelInfoIcon = new JLabel(new ImageIcon(ImageUtils.getImage(this, "information_small_white.png"))); // Add tooltip on mouseover the info icon quoteCharLabelInfoIcon.setToolTipText("If variable names or/and actual data are quoted, choose either single quote or double quotes. "); quoteCharLabelBox.add(quoteCharLabelInfoIcon); // Option 1 Box quoteCharOption1Box = Box.createHorizontalBox(); quoteCharOption1Box.setPreferredSize(new Dimension(160, 30)); quoteCharOption1Box.add(noneQuoteRadioButton); // Option 2 Box quoteCharOption2Box = Box.createHorizontalBox(); quoteCharOption2Box.setPreferredSize(new Dimension(160, 30)); quoteCharOption2Box.add(this.doubleQuoteRadioButton); // Option 3 Box quoteCharOption3Box = Box.createHorizontalBox(); quoteCharOption3Box.setPreferredSize(new Dimension(260, 30)); quoteCharOption3Box.add(this.singleQuoteRadioButton); quoteCharBox.add(quoteCharLabelBox); quoteCharBox.add(Box.createRigidArea(new Dimension(10, 1))); quoteCharBox.add(quoteCharOption1Box); quoteCharBox.add(quoteCharOption2Box); quoteCharBox.add(quoteCharOption3Box); quoteCharBox.add(Box.createHorizontalGlue()); advancedSettingsBox.add(quoteCharBox); // Add seperator line JSeparator separator3 = new JSeparator(SwingConstants.HORIZONTAL); separator3.setForeground(this.separatorColor); advancedSettingsBox.add(separator3); // Missing value marker Box missingDataMarkerBox = Box.createHorizontalBox(); this.missingValueStarRadioButton = new JRadioButton("*"); this.missingValueQuestionRadioButton = new JRadioButton("?"); JRadioButton missingValueOtherRadioButton = new JRadioButton("Other: "); ButtonGroup missingDataMarkerBtnGrp = new ButtonGroup(); missingDataMarkerBtnGrp.add(this.missingValueStarRadioButton); missingDataMarkerBtnGrp.add(this.missingValueQuestionRadioButton); missingDataMarkerBtnGrp.add(missingValueOtherRadioButton); // Missing string field: other this.missingStringField = new StringTextField("", 6); this.missingStringField.setText(""); // * is selected as the default this.missingValueStarRadioButton.setSelected(true); // Option 1 Box missingDataMarkerOption1Box = Box.createHorizontalBox(); missingDataMarkerOption1Box.setPreferredSize(new Dimension(160, 30)); missingDataMarkerOption1Box.add(this.missingValueStarRadioButton); // Option 2 Box missingDataMarkerOption2Box = Box.createHorizontalBox(); missingDataMarkerOption2Box.setPreferredSize(new Dimension(160, 30)); missingDataMarkerOption2Box.add(this.missingValueQuestionRadioButton); // Option 3 Box missingDataMarkerOption3Box = Box.createHorizontalBox(); missingDataMarkerOption3Box.setPreferredSize(new Dimension(260, 30)); missingDataMarkerOption3Box.add(missingValueOtherRadioButton); missingDataMarkerOption3Box.add(this.missingStringField); // Add label into this label box to size Box missingDataMarkerLabelBox = Box.createHorizontalBox(); missingDataMarkerLabelBox.setPreferredSize(this.labelSize); missingDataMarkerLabelBox.add(new JLabel("Missing value marker:")); missingDataMarkerBox.add(missingDataMarkerLabelBox); missingDataMarkerBox.add(Box.createRigidArea(new Dimension(10, 1))); missingDataMarkerBox.add(missingDataMarkerOption1Box); missingDataMarkerBox.add(missingDataMarkerOption2Box); missingDataMarkerBox.add(missingDataMarkerOption3Box); missingDataMarkerBox.add(Box.createHorizontalGlue()); advancedSettingsBox.add(missingDataMarkerBox); advancedSettingsBox.add(Box.createVerticalStrut(5)); // Use a titled border with 5 px inside padding - Zhou final String borderTitle = "Advanced Settings (apply to all files)"; advancedSettingsBox.setBorder(new CompoundBorder(BorderFactory.createTitledBorder(borderTitle), new EmptyBorder(5, 5, 5, 5))); return advancedSettingsBox; } /** * This works for both validation(column and data) and data reading(column reader and data reader) */ private void setQuoteChar(DataReader dataReader) { if (this.doubleQuoteRadioButton.isSelected()) { dataReader.setQuoteCharacter('"'); } if (this.singleQuoteRadioButton.isSelected()) { dataReader.setQuoteCharacter('\''); } } private String getCommentMarker() { if (this.commentDoubleSlashRadioButton.isSelected()) { return "//"; } else if (this.commentPondRadioButton.isSelected()) { return "#"; } else if (this.commentOtherRadioButton.isSelected()) { return this.commentStringField.getText(); } else { throw new IllegalArgumentException("Unexpected Comment Marker selection."); } } /** * Determine the delimiter for a text data file. */ private char getInferredDelimiter(File file) throws IOException { System.out.println("Infer demiliter for file: " + file.getName()); // The number of lines to read to make the inference final int n = 20; // The number of lines to skip at top of file before processing // Here we use 2 because covariance data has total number of cases at line 1, // and sometimes a commented line as well final int skip = 2; final String comment = "//"; final char quoteCharacter = '"'; char[] delims = {'\t', ' ', ',', ':', ';', '|'}; // https://rdrr.io/cran/reader/man/get.delim.html return TextFileUtils.inferDelimiter(file, n, skip, comment, quoteCharacter, delims); } /** * Get delimiter character */ private Delimiter getDelimiterType() { if (this.whitespaceDelimiterRadioButton.isSelected()) { return Delimiter.WHITESPACE; } else if (this.singleCharDelimiterRadioButton.isSelected()) { String singleCharDelimiter = Objects.requireNonNull(this.singleCharDelimiterComboBox.getSelectedItem()).toString(); switch (singleCharDelimiter) { case "Comma": return Delimiter.COMMA; case "Space": return Delimiter.SPACE; case "Tab": return Delimiter.TAB; case "Colon": return Delimiter.COLON; case "Semicolon": return Delimiter.SEMICOLON; case "Pipe": return Delimiter.PIPE; default: throw new IllegalArgumentException("Unexpected Value delimiter selection."); } } else { throw new IllegalArgumentException("Unexpected Value delimiter selection."); } } private boolean isVarNamesFirstRow() { if (this.firstRowVarNamesYesRadioButton.isSelected()) { return true; } else if (this.firstRowVarNamesNoRadioButton.isSelected()) { return false; } else { throw new IllegalArgumentException("Unexpected Variable Names in First Row selection."); } } /** * To check if the label is specified while that radio button is selected * * @return a boolean */ public boolean isColumnLabelSpecified() { if (this.idLabeledColRadioButton.isSelected()) { return !this.idStringField.getText().isEmpty(); } else { return true; } } /** * To check if comment marker is supplied while Other radio button is selected * * @return a boolean */ public boolean isOtherCommentMarkerSpecified() { if (this.commentOtherRadioButton.isSelected()) { return !this.commentStringField.getText().isEmpty(); } else { return true; } } private String getMissingDataMarker() { if (this.missingValueStarRadioButton.isSelected()) { return "*"; } else if (this.missingValueQuestionRadioButton.isSelected()) { return "?"; } else { return this.missingStringField.getText(); } } private int getMaxNumOfDiscCategories() { return this.maxNumOfDiscCategoriesField.getValue(); } /** * Genearate the column header when not provided */ private DataColumn[] generateTabularColumns(File file, Delimiter delimiter) throws IOException { DataColumn[] dataColumns = null; String commentMarker = getCommentMarker(); TabularColumnReader columnFileReader = new TabularColumnFileReader(file.toPath(), delimiter); columnFileReader.setCommentMarker(commentMarker); setQuoteChar(columnFileReader); // Set data type for each column // It really doesn't matter for mixed data boolean isDiscrete = this.discRadioButton.isSelected(); // Generate data columns with exclusions // Handle case ID column based on different selections if (this.idNoneRadioButton.isSelected()) { dataColumns = columnFileReader.generateColumns(new int[0], isDiscrete); } else if (this.idUnlabeledFirstColRadioButton.isSelected()) { // Exclude the first column dataColumns = columnFileReader.generateColumns(new int[]{1}, isDiscrete); } return dataColumns; } /** * Validate each file based on the specified settings * * @param file a {@link java.io.File} object * @return a {@link java.util.List} object * @throws java.io.IOException if any. */ public List validateDataWithSettings(File file) throws IOException { Delimiter delimiter = getDelimiterType(); boolean hasHeader = isVarNamesFirstRow(); String commentMarker = getCommentMarker(); String missingDataMarker = getMissingDataMarker(); if (this.tabularRadioButton.isSelected()) { DataColumn[] dataColumns; List tabularColumnValidationResults = new LinkedList<>(); // Generate the columns if not present and skip the column validation if (!hasHeader) { dataColumns = generateTabularColumns(file, delimiter); } else { // Step 1: validate the columns TabularColumnValidation tabularColumnValidation = new TabularColumnFileValidation(file.toPath(), delimiter); // Specify settings for column validation tabularColumnValidation.setCommentMarker(commentMarker); setQuoteChar(tabularColumnValidation); // Handle case ID column based on different selections if (this.idNoneRadioButton.isSelected()) { // No column exclusion tabularColumnValidationResults = tabularColumnValidation.validate(); } else if (this.idUnlabeledFirstColRadioButton.isSelected()) { // Exclude the first column tabularColumnValidationResults = tabularColumnValidation.validate(new int[]{1}); } else if (this.idLabeledColRadioButton.isSelected() && !this.idStringField.getText().isEmpty()) { // Exclude the specified labled columns tabularColumnValidationResults = tabularColumnValidation.validate(new HashSet<>( Collections.singletonList(this.idStringField.getText()))); } // Step 2: Read in columns for later use if nothing wrong with the columns validation dataColumns = readInTabularColumns(file); } List validationInfos = new LinkedList<>(); List validationWarnings = new LinkedList<>(); List validationErrors = new LinkedList<>(); for (ValidationResult result : tabularColumnValidationResults) { switch (result.getCode()) { case INFO: validationInfos.add(result); break; case WARNING: validationWarnings.add(result); break; default: validationErrors.add(result); } } // Stop here and return the column validation results if there's any error if (validationErrors.size() > 0) { return tabularColumnValidationResults; } else { if (this.mixedRadioButton.isSelected()) { TabularDataReader dataReader = new TabularDataFileReader(file.toPath(), delimiter); dataReader.setCommentMarker(commentMarker); dataReader.setMissingDataMarker(missingDataMarker); setQuoteChar(dataReader); dataReader.determineDiscreteDataColumns(dataColumns, getMaxNumOfDiscCategories(), hasHeader); } if (this.metadataFile != null) { MetadataReader metadataReader = new MetadataFileReader(this.metadataFile.toPath()); this.metadata = metadataReader.read(); dataColumns = DataColumns.update(dataColumns, this.metadata); } // Step 3: Data validation // when we at this step, it means the column validation is all good without any errors TabularDataValidation tabularDataValidation = new TabularDataFileValidation(file.toPath(), delimiter); // Specify the setting again for data validation tabularDataValidation.setCommentMarker(commentMarker); setQuoteChar(tabularDataValidation); // Missing data marker setting for data validaiton only, not for column validation tabularDataValidation.setMissingDataMarker(missingDataMarker); // At this point, no need to use the column validation results at all return tabularDataValidation.validate(dataColumns, hasHeader); } } else if (this.covarianceRadioButton.isSelected()) { CovarianceValidation covarianceValidation = new LowerCovarianceDataFileValidation(file.toPath(), delimiter); // Header in first row is required // Cpvariance never has missing value marker covarianceValidation.setCommentMarker(commentMarker); setQuoteChar(covarianceValidation); // No case ID on covarianced data return covarianceValidation.validate(); } else { throw new UnsupportedOperationException("You can only choose either tabular data or covariance data!"); } } private DataColumn[] readInTabularColumns(File file) throws IOException { DataColumn[] dataColumns = null; Delimiter delimiter = getDelimiterType(); String commentMarker = getCommentMarker(); TabularColumnReader columnReader = new TabularColumnFileReader(file.toPath(), delimiter); columnReader.setCommentMarker(commentMarker); setQuoteChar(columnReader); // Set data type for each column // It really doesn't matter for mixed data boolean isDiscrete = this.discRadioButton.isSelected(); // Handle case ID column based on different selections if (this.idNoneRadioButton.isSelected()) { // No column exclusion dataColumns = columnReader.readInDataColumns(new int[0], isDiscrete); } else if (this.idUnlabeledFirstColRadioButton.isSelected()) { // Exclude the first column dataColumns = columnReader.readInDataColumns(new int[]{1}, isDiscrete); } else if (this.idLabeledColRadioButton.isSelected() && !this.idStringField.getText().isEmpty()) { // Exclude the specified labled columns dataColumns = columnReader.readInDataColumns(new HashSet<>( Collections.singletonList(this.idStringField.getText())), isDiscrete); } return dataColumns; } /** * Kevin's data reader * * @param file a {@link java.io.File} object * @return a {@link edu.cmu.tetrad.data.DataModel} object * @throws java.io.IOException if any. */ public DataModel loadDataWithSettings(File file) throws IOException { DataModel dataModel; Delimiter delimiter = getDelimiterType(); boolean hasHeader = isVarNamesFirstRow(); String commentMarker = getCommentMarker(); String missingDataMarker = getMissingDataMarker(); DataColumn[] dataColumns; if (this.tabularRadioButton.isSelected()) { // Generate columns if no header present if (!hasHeader) { dataColumns = generateTabularColumns(file, delimiter); // When no header, no metadata } else { dataColumns = readInTabularColumns(file); } // Now read in the data rows TabularDataReader dataReader = new TabularDataFileReader(file.toPath(), delimiter); // Need to specify commentMarker, .... again to the TabularDataFileReader dataReader.setCommentMarker(commentMarker); dataReader.setMissingDataMarker(missingDataMarker); setQuoteChar(dataReader); // When users select mixed data, we need to determine num of discrete categories before the metadata kicks in // It's possible that the users select mixed, but excluded either all continuous or discrete columns, // and as a result, the final data is either discrete or continuous instead of mixed - Zhou if (this.mixedRadioButton.isSelected()) { dataReader.determineDiscreteDataColumns(dataColumns, getMaxNumOfDiscCategories(), hasHeader); } // Read metadata file when provided and update the dataColumns if (this.metadataFile != null) { MetadataReader metadataReader = new MetadataFileReader(this.metadataFile.toPath()); this.metadata = metadataReader.read(); dataColumns = DataColumns.update(dataColumns, this.metadata); } // Now we read in the actual data with metadata object (if provided) Data data; if (this.metadata != null) { data = dataReader.read(dataColumns, hasHeader, this.metadata); // Box Data to DataModel to display in spreadsheet dataModel = DataConvertUtils.toDataModel(data, this.metadata); } else { data = dataReader.read(dataColumns, hasHeader); // Box Data to DataModel to display in spreadsheet dataModel = DataConvertUtils.toDataModel(data); } } else if (this.covarianceRadioButton.isSelected()) { // Covariance data can only be continuous CovarianceDataReader dataFileReader = new LowerCovarianceDataFileReader(file.toPath(), delimiter); dataFileReader.setCommentMarker(commentMarker); setQuoteChar(dataFileReader); CovarianceData covarianceData = dataFileReader.readInData(); // Box Dataset to DataModel dataModel = DataConvertUtils.toDataModel(covarianceData); } else { throw new UnsupportedOperationException("Unsupported selection of File Type!"); } return dataModel; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy