/* * Copyright (c) 2009 The Jackson Laboratory * * This software was developed by Gary Churchill's Lab at The Jackson * Laboratory (see http://research.jax.org/faculty/churchill). * * This 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 3 of the License, or * (at your option) any later version. * * This software 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 software. If not, see <http://www.gnu.org/licenses/>. */ package org.jax.qtl.graph; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Hashtable; import java.util.StringTokenizer; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import org.jax.qtl.QTL; import org.jax.qtl.cross.Cross; import org.jax.qtl.gui.SaveGraphImageAction; /** * The panel that holds the genotype plot * @see GenoPlot * @author Hao Wu * @author Keith Sheppard (minor modifications to integrate with J/qtl 1.0) */ @SuppressWarnings("all") public class GenoPlotPanel extends JPanel implements ActionListener { /** * */ private static final long serialVersionUID = 1007933136535351682L; private Cross cross; private boolean inMarkDist; // ui stuff private Hashtable genoPlotProperties; private JPanel headerPanel; private GenoPlot plotPanel; private JScrollPane plotPane; private JComboBox sortList, plotList; private JCheckBox interactivePlot, cbInMarkDist; private JList chrList; private JScrollPane chrScrollPane; // chromosome list private JTextField tfInd; // for individuals private JButton plotParameters; // some parameters for plot private JButton reDrawButton; //layout private GridBagConstraints gbc; // set and get genoplot properties public void setProperty(Object key, Object value) { this.genoPlotProperties.put(key, value); } public Hashtable getProperty() {return this.genoPlotProperties;} public GenoPlot getGenoPlot() {return this.plotPanel;} // constructor public GenoPlotPanel(Cross c, Hashtable properties) { this.genoPlotProperties = properties; // get some properties this.inMarkDist = ((Boolean)this.genoPlotProperties.get(FigureProperties.GENOPLOT_IN_MARKER_DIST)).booleanValue(); this.cross = c; setLayout(new BorderLayout()); // make two panels this.plotPanel = new GenoPlot(c, this.genoPlotProperties); makeHeaderPanel(); this.plotPane = new JScrollPane(); this.plotPane.getViewport().add(this.plotPanel); // put them together add(this.headerPanel, BorderLayout.NORTH); add(this.plotPane, BorderLayout.CENTER); } public void actionPerformed(ActionEvent e) { Object src = e.getSource(); // regenerate the plot if click redraw button if(src == this.reDrawButton) { // ====== get the figure properties ========= // sortby setProperty(FigureProperties.GENOPLOT_SORTBY, new Integer(this.sortList.getSelectedIndex())); //things to plot setProperty(FigureProperties.GENOPLOT_WHAT, new Integer(this.plotList.getSelectedIndex())); //plot in marker distance setProperty(FigureProperties.GENOPLOT_IN_MARKER_DIST, new Boolean(this.cbInMarkDist.isSelected())); // chromosome list int[] itmp = this.chrList.getSelectedIndices(); if(itmp[0] == 0) { // chose "all" setProperty(FigureProperties.GENOPLOT_CHROM, "all"); } else {// choose some chromosomes int[] chridx = new int[itmp.length]; for(int i=0; i<itmp.length; i++) chridx[i] = itmp[i]-1; setProperty(FigureProperties.GENOPLOT_CHROM, chridx); } // individual list - this need some thinking, I'll put it in anyway // the text will be converted into all lower case letters String indStr = this.tfInd.getText().toLowerCase(); if(indStr.equals("all")) // all setProperty(FigureProperties.GENOPLOT_IND, indStr); else { // something else - the valid syntax will be "1:30, 50:60" // means to plot individuals 1 to 30 and 50 to 60 // -------------------------------------------------------- // note that this is the individual *INDEX* after sorting. // I might need to change them to the actually individual // index. But I think to use sorting-based index makes more sense // Hao Wu Mar 21, 2005 // ----------------------------------------------------------- int nind = 0; // number of individuals // allocate memory, trim later int[] indidx = new int[this.cross.getNumberOfIndividuals()]; String tmpStr; // parse the string StringTokenizer t1, t2; t1 = new StringTokenizer(indStr, ","); try{ do { tmpStr = t1.nextToken(); t2 = new StringTokenizer(tmpStr, ":"); // t2 should have one or two tokens if(t2.countTokens() == 1) { indidx[nind] = Integer.parseInt(tmpStr)-1; nind ++; } else if(t2.countTokens() == 2) { int start = Integer.parseInt(t2.nextToken().trim()); int end = Integer.parseInt(t2.nextToken().trim()); for(int i=start-1; i<end; i++) { indidx[nind] = i; nind ++; } } else { // error String msg = "Error in Individual index - \"" + tmpStr + "\""; JOptionPane.showMessageDialog(this, msg, "Individual Index Error", JOptionPane.ERROR_MESSAGE); } } while(t1.hasMoreTokens()); // trim indidx int[] tmp = new int[nind]; System.arraycopy(indidx, 0, tmp, 0, nind); setProperty(FigureProperties.GENOPLOT_IND, tmp); } catch(Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(this, "Error happened", "Individual Index Error", JOptionPane.ERROR_MESSAGE); } } // redraw the figure if(this.plotPanel != null) { this.plotPanel.reDraw(); } } else if(src == this.plotParameters) { // plot parameter button // what to plot int plotidx = this.plotList.getSelectedIndex(); PlotParamDialog d = new PlotParamDialog(plotidx); d.setVisible(true); } if(src == this.plotList) { // change sort list if(this.plotParameters==null) return; int plotidx = this.plotList.getSelectedIndex(); // no parameters for plotting crossover, missing or error lod this.plotParameters.setEnabled(plotidx == 0); } /* else if(src == plotList) { // change things to plot int plotidx = plotList.getSelectedIndex(); boolean plotgeno = (plotidx==0); // enable/disable combobox and buttons according to plotgeno if(interactivePlot != null) interactivePlot.setEnabled(plotgeno); if(GenoColorButton != null) { for(int i=0; i<GenoColorButton.length; i++) if(GenoColorButton[i] != null) GenoColorButton[i].setEnabled(plotgeno); } setProperty(FigureProperties.GENOPLOT_WHAT, new Integer(plotidx)); if(plotPanel != null) { plotPanel.reDraw(); } } else if(src == interactivePlot) { // interactive plot boolean b = interactivePlot.isSelected(); setProperty(FigureProperties.GENOPLOT_INT, new Boolean(b)); if(plotPanel != null) { plotPanel.reDraw(); } } else if(src instanceof JButton) { final int buttonIdx = Integer.valueOf(((JButton)src).getActionCommand()).intValue(); Color defaultColor = ((JButton)src).getBackground(); final JColorChooser chooser = new JColorChooser(defaultColor); //Color selected JDialog dialog = JColorChooser.createDialog(qtl.mainFrame, "test", true, chooser, new ActionListener() { // for ok button public void actionPerformed(ActionEvent e) { setGenoColor(buttonIdx, chooser.getColor()); } } , null); dialog.show(); } */ } // function to set the color for a genotype /* private void setGenoColor(int idx, Color color) { Color[] genocolor = (Color[])GenoPlotProperties.get(FigureProperties.GENOPLOT_PALETTE); genocolor[idx] = color; // save the property change setProperty(FigureProperties.GENOPLOT_PALETTE, genocolor); // set the button GenoColorButton[idx].setBackground(color); // redraw the figure plotPanel.reDraw(); } */ // function to make the control panel for genoplot private void makeHeaderPanel() { // start to build the header panel this.headerPanel = new JPanel(); this.headerPanel.setBackground(Color.white); // set layout this.headerPanel.setLayout(new GridBagLayout()); this.gbc = new GridBagConstraints(); this.gbc.anchor = GridBagConstraints.WEST; this.gbc.fill = GridBagConstraints.BOTH; //gbc.ipadx = 30; this.gbc.insets = new Insets(3,5,3,5); // ========== sortby list ============== String[] pnames = this.cross.getPhenotypeData().getDataNames(); String[] sortByPnames = new String[pnames.length+1]; sortByPnames[0] = "Input Order"; for(int i=1; i<pnames.length+1; i++ ) sortByPnames[i] = pnames[i-1]; // make a combo box for sort list this.sortList = new JComboBox(sortByPnames); this.sortList.setBackground(Color.white); this.sortList.addActionListener(this); int sortbyidx = ((Integer)this.genoPlotProperties.get(FigureProperties.GENOPLOT_SORTBY)).intValue(); this.sortList.setSelectedIndex(sortbyidx); // set a border // sortList.setBorder(BorderFactory.createTitledBorder( // BorderFactory.createEmptyBorder(0, 0, 0, 0), "Sort By")); add(this.headerPanel, new JLabel("Sort By"), this.gbc, 0,0,1,1); add(this.headerPanel, this.sortList, this.gbc, 1,0,1,1); // ========== plot list ============== String[] whattoplot = {"Genotype", "Crossovers", "Missing data", "Genotyping Error"}; this.plotList = new JComboBox(whattoplot); this.plotList.setBackground(Color.white); this.plotList.addActionListener(this); int plotidx = ((Integer)this.genoPlotProperties.get(FigureProperties.GENOPLOT_WHAT)).intValue(); this.plotList.setSelectedIndex(plotidx); // set a border // plotList.setBorder(BorderFactory.createTitledBorder( // BorderFactory.createEmptyBorder(0, 0, 0, 0), "Things to plot")); add(this.headerPanel, new JLabel("Things to plot"), this.gbc, 0,1,1,1); add(this.headerPanel, this.plotList, this.gbc, 1,1,1,1); this.plotParameters = new JButton("Plot Colors"); this.plotParameters.addActionListener(this); add(this.headerPanel, this.plotParameters, this.gbc, 2,1,1,1); // ========== individual list ============== add(this.headerPanel, new JLabel("Choose Individuals"), this.gbc, 0,2,1,1); add(this.headerPanel, this.tfInd=new JTextField("all"), this.gbc, 1,2,1,1); // ========== plot in real marker ============== this.cbInMarkDist = new JCheckBox("Plot in real marker distance"); this.cbInMarkDist.setBackground(Color.white); this.cbInMarkDist.setSelected(this.inMarkDist); add(this.headerPanel, this.cbInMarkDist, this.gbc, 0,3,2,1); JButton exportImageButton = new JButton( new SaveGraphImageAction(this.plotPanel)); this.gbc.fill = GridBagConstraints.NONE; this.add( this.headerPanel, exportImageButton, this.gbc, 0, 4, 2, 1); this.gbc.fill = GridBagConstraints.BOTH; // ========== chromosome list ============== int nchr = this.cross.getNumberOfChromosomes(); String[] chrs = new String[nchr+1]; chrs[0] = "All"; for(int i=1; i<=nchr; i++) chrs[i] = "Chromosome " + this.cross.getGenotypeData().get(i-1).getChromosomeName(); this.chrList = new JList(chrs); this.chrList.setSelectedIndex(0); this.chrScrollPane = new JScrollPane(this.chrList); this.chrScrollPane.setPreferredSize(new Dimension(150, 85)); /* chrScrollPane.setBackground(Color.white); chrScrollPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(0, 0, 0, 0), "Choose Chromosome")); // add(headerPanel, new JLabel("Choose Chromosome"), gbc, 3,0,1,1); */ add(this.headerPanel, this.chrScrollPane, this.gbc, 3,0,1,4); // ========== redraw button ============== this.reDrawButton = new JButton("Redraw"); this.reDrawButton.addActionListener(this); add(this.headerPanel, this.reDrawButton, this.gbc, 3,4,1,1); /* // make buttons for choosing color String[] genocode = cross.getGenoCode(); JPanel PalettePanel = new JPanel(); PalettePanel.setBackground(Color.white); Color[] genocolor = (Color[])GenoPlotProperties.get(FigureProperties.GENOPLOT_PALETTE); GenoColorButton = new JButton[genocolor.length]; for(int i=0; i<genocolor.length; i++) { if(genocode[i].length() > 0) { GenoColorButton[i] = new JButton(); GenoColorButton[i].setPreferredSize(new Dimension(25,25)); GenoColorButton[i].setBackground(genocolor[i]); GenoColorButton[i].setActionCommand(""+i); GenoColorButton[i].addActionListener(this); PalettePanel.add(new JLabel(ReadDataDialogBox.genoNameString[i])); PalettePanel.add(GenoColorButton[i]); } } PalettePanel.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(0, 30, 0, 0), "Choose Color")); headerPanel.add(PalettePanel); // checkbox for interactive plot interactivePlot = new JCheckBox("Interactive plot"); boolean inter = ((Boolean)(GenoPlotProperties.get(FigureProperties.GENOPLOT_INT))).booleanValue(); interactivePlot.setSelected(inter); interactivePlot.setBackground(Color.white); interactivePlot.addActionListener(this); headerPanel.add(interactivePlot); */ // add an empty border this.headerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); } // for gridbaglayout private void add(Container mother, Component child, GridBagConstraints gbc, int x, int y, int w, int h) { gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = w; gbc.gridheight = h; mother.add(child, gbc); } // Several internal classes for plot properties // for plot parameter private class PlotParamDialog extends JDialog implements ActionListener { /** * */ private static final long serialVersionUID = -8508002897781827481L; private JPanel contentPanel, buttonPanel; private JButton okButton, cancelButton; private JButton[] GenoColorButton; private boolean ok=false; public boolean getOk() {return this.ok;} // constructor PlotParamDialog(int what) { super((JFrame)null, "Genotype plot properties"); // make content panel makeContentPanel(what); // make button panel makeButtonPanel(); // put together // make the dialog Container c = getContentPane(); c.add(this.contentPanel, "North"); c.add(this.buttonPanel, "South"); // center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = this.getPreferredSize(); setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); pack(); } // function to make button panel private void makeButtonPanel() { this.buttonPanel = new JPanel(); this.okButton = new JButton("OK"); this.okButton.addActionListener(this); this.buttonPanel.add(this.okButton); this.cancelButton = new JButton("Cancel"); this.cancelButton.addActionListener(this); this.buttonPanel.add(this.cancelButton); /* JButton helpButton = new JButton("Help"); helpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String title = "Calculate genotype probability"; JDialog help = new HelpDialogBox("GenoPlotPanel", title, GenoPlotPanel.this); help.show(); } }); helpButton.setPreferredSize(new Dimension(80, 30)); buttonPanel.add(helpButton);*/ this.buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); } // function to make content panel private void makeContentPanel(int what) { this.contentPanel = new JPanel(); if(what == 0) { // plot geno JColorChooser chooser; this.contentPanel.setBackground(Color.white); Color[] genocolor = (Color[])GenoPlotPanel.this.genoPlotProperties.get(FigureProperties.GENOPLOT_PALETTE); this.GenoColorButton = new JButton[genocolor.length]; // String[] genocode = cross.getGenoCode(); String[] genocode = GenoPlotPanel.this.cross.getCrossSubType().getMarkerDataCategoricalValues(); for(int i=0; i<genocolor.length; i++) { this.GenoColorButton[i] = new JButton(); this.GenoColorButton[i].setPreferredSize(new Dimension(25,25)); this.GenoColorButton[i].setBackground(genocolor[i]); this.GenoColorButton[i].setActionCommand(""+i); this.GenoColorButton[i].addActionListener(this); if(i < genocode.length) { this.contentPanel.add(new JLabel(genocode[i])); } else { this.contentPanel.add(new JLabel("Missing")); } this.contentPanel.add(this.GenoColorButton[i]); } this.contentPanel.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(0, 30, 0, 0), "Choose Color")); } } // function to set the color for a genotype private void setGenoColor(int idx, Color color) { Color[] genocolor = (Color[])GenoPlotPanel.this.genoPlotProperties.get(FigureProperties.GENOPLOT_PALETTE); genocolor[idx] = color; // save the property change setProperty(FigureProperties.GENOPLOT_PALETTE, genocolor); // set the button this.GenoColorButton[idx].setBackground(color); // redraw the figure // plotPanel.reDraw(); } // respond mouse click public void actionPerformed(ActionEvent e) { Object src = e.getSource(); if(src == this.cancelButton) { dispose(); } else if(src == this.okButton) { this.ok = true; dispose(); } else if(src instanceof JButton) { // show palette final int buttonIdx = Integer.valueOf( ((JButton)src).getActionCommand()).intValue(); Color defaultColor = ((JButton)src).getBackground(); final JColorChooser chooser = new JColorChooser(defaultColor); // Color selected JDialog dialog = JColorChooser.createDialog( QTL.getInstance().getApplicationFrame(), "test", true, chooser, new ActionListener() { public void actionPerformed(ActionEvent e) { setGenoColor(buttonIdx, chooser.getColor()); } }, null); dialog.setVisible(true); } } } /* private class GenoPaletteDialog extends JDialog implements ActionListener { private JButton ok, cancel; private JPanel buttonPanel; private JColorChooser chooser; public GenoPaletteDialog() { super(frame, "Choose color", true); // make button panel buttonPanel = new JPanel(); ok = new JButton("OK"); ok.addActionListener(this); buttonPanel.add(ok); cancel = new JButton("Cancel"); cancel.addActionListener(this); buttonPanel.add(cancel); buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); // make color chooser chooser = new JColorChooser(); // make the dialog Container c = getContentPane(); c.add(chooser, "North"); c.add(buttonPanel, "South"); // center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = this.getPreferredSize(); setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); pack(); } // respond mouse click public void actionPerformed(ActionEvent e) { if(e.getSource() == cancel) { dispose(); } else if(e.getSource() == ok) { } } } */ }