/* * PartitionTreePriorPanel.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST 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 * of the License, or (at your option) any later version. * * BEAST 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 BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.app.beauti.treespanel; import dr.app.beauti.options.PartitionTreeModel; import dr.app.beauti.options.PartitionTreePrior; import dr.app.beauti.types.PopulationSizeModelType; import dr.app.beauti.types.TreePriorParameterizationType; import dr.app.beauti.types.TreePriorType; import dr.app.beauti.util.PanelUtils; import dr.app.gui.components.RealNumberField; import dr.app.gui.components.WholeNumberField; import dr.app.util.OSType; import dr.evomodel.coalescent.VariableDemographicModel; import dr.evomodelxml.speciation.BirthDeathModelParser; import dr.evomodelxml.speciation.BirthDeathSerialSamplingModelParser; import jam.panels.OptionsPanel; import javax.swing.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.EnumSet; /** * @author Andrew Rambaut * @author Alexei Drummond * @author Walter Xie * @version $Id: PriorsPanel.java,v 1.9 2006/09/05 13:29:34 rambaut Exp $ */ public class PartitionTreePriorPanel extends OptionsPanel { private static final long serialVersionUID = 5016996360264782252L; private JComboBox treePriorCombo = new JComboBox(); private JComboBox parameterizationCombo = new JComboBox(EnumSet.range(TreePriorParameterizationType.GROWTH_RATE, TreePriorParameterizationType.DOUBLING_TIME).toArray()); // private JComboBox parameterizationCombo1 = new JComboBox(EnumSet.of(TreePriorParameterizationType.DOUBLING_TIME).toArray()); private JComboBox bayesianSkylineCombo = new JComboBox(EnumSet.range(TreePriorParameterizationType.CONSTANT_SKYLINE, TreePriorParameterizationType.LINEAR_SKYLINE).toArray()); private WholeNumberField groupCountField = new WholeNumberField(2, Integer.MAX_VALUE); private JComboBox extendedBayesianSkylineCombo = new JComboBox( new VariableDemographicModel.Type[]{VariableDemographicModel.Type.LINEAR, VariableDemographicModel.Type.STEPWISE}); private JComboBox gmrfBayesianSkyrideCombo = new JComboBox(EnumSet.range(TreePriorParameterizationType.UNIFORM_SKYRIDE, TreePriorParameterizationType.TIME_AWARE_SKYRIDE).toArray()); private JComboBox skyGridPointsCombo = new JComboBox(new Integer[]{10, 20, 50, 100}); private RealNumberField skyGridInterval = new RealNumberField(0.0, Double.MAX_VALUE); // private JComboBox skyGridCombo = new JComboBox(EnumSet.range()) private JComboBox populationSizeCombo = new JComboBox(PopulationSizeModelType.values()); // private JComboBox calibrationCorrectionCombo = new JComboBox(new CalibrationPoints.CorrectionType[] // {CalibrationPoints.CorrectionType.EXACT, CalibrationPoints.CorrectionType.NONE}); // RealNumberField samplingProportionField = new RealNumberField(Double.MIN_VALUE, 1.0); // private BeautiFrame frame = null; // private BeautiOptions options = null; PartitionTreePrior partitionTreePrior; private final TreesPanel treesPanel; private boolean settingOptions = false; public PartitionTreePriorPanel(PartitionTreePrior parTreePrior, final TreesPanel parent) { super(12, (OSType.isMac() ? 6 : 24)); this.partitionTreePrior = parTreePrior; this.treesPanel = parent; setTreePriorChoices(false, false, false); PanelUtils.setupComponent(treePriorCombo); treePriorCombo.setMaximumRowCount(10); // to show Calibrated Yule treePriorCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { if (treePriorCombo.getSelectedItem() != null) { partitionTreePrior.setNodeHeightPrior((TreePriorType) treePriorCombo.getSelectedItem()); setupPanel(); parent.fireTreePriorsChanged(); } } }); PanelUtils.setupComponent(parameterizationCombo); parameterizationCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { partitionTreePrior.setParameterization((TreePriorParameterizationType) parameterizationCombo.getSelectedItem()); parent.fireTreePriorsChanged(); } }); // PanelUtils.setupComponent(parameterizationCombo1); // parameterizationCombo1.addItemListener(new ItemListener() { // public void itemStateChanged(ItemEvent ev) { // partitionTreePrior.setParameterization((TreePriorParameterizationType) parameterizationCombo1.getSelectedItem()); // } // }); PanelUtils.setupComponent(groupCountField); groupCountField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyTyped(java.awt.event.KeyEvent ev) { // move to here? // it will set value for each typing } }); PanelUtils.setupComponent(skyGridInterval); skyGridInterval.addKeyListener(new java.awt.event.KeyAdapter() { public void keyTyped(java.awt.event.KeyEvent ev) { } }); PanelUtils.setupComponent(bayesianSkylineCombo); bayesianSkylineCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { partitionTreePrior.setSkylineModel((TreePriorParameterizationType) bayesianSkylineCombo.getSelectedItem()); parent.fireTreePriorsChanged(); } }); PanelUtils.setupComponent(extendedBayesianSkylineCombo); extendedBayesianSkylineCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { partitionTreePrior.setExtendedSkylineModel(((VariableDemographicModel.Type) extendedBayesianSkylineCombo.getSelectedItem())); parent.fireTreePriorsChanged(); } }); PanelUtils.setupComponent(gmrfBayesianSkyrideCombo); gmrfBayesianSkyrideCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { partitionTreePrior.setSkyrideSmoothing((TreePriorParameterizationType) gmrfBayesianSkyrideCombo.getSelectedItem()); parent.fireTreePriorsChanged(); } }); PanelUtils.setupComponent(skyGridPointsCombo); skyGridPointsCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent itemEvent) { partitionTreePrior.setSkyGridCount((Integer) skyGridPointsCombo.getSelectedItem()); parent.fireTreePriorsChanged(); } }); PanelUtils.setupComponent(populationSizeCombo); populationSizeCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { partitionTreePrior.setPopulationSizeModel((PopulationSizeModelType) populationSizeCombo.getSelectedItem()); parent.fireTreePriorsChanged(); } } ); // PanelUtils.setupComponent(calibrationCorrectionCombo); // calibrationCorrectionCombo.addItemListener(new ItemListener() { // public void itemStateChanged(ItemEvent ev) { // partitionTreePrior.setCalibCorrectionType((CalibrationPoints.CorrectionType) calibrationCorrectionCombo.getSelectedItem()); // parent.fireTreePriorsChanged(); // } // } // ); // samplingProportionField.addKeyListener(keyListener); // need it not setupPanel(), because it contains required setSelectedItem() // to make Tree prior panel displayed properly when link/unlink tree prior setOptions(); } private void setupPanel() { removeAll(); JTextArea citationText = new JTextArea(1, 40); citationText.setLineWrap(true); citationText.setWrapStyleWord(true); citationText.setEditable(false); citationText.setFont(this.getFont()); citationText.setOpaque(false); // citationText.setBackground(this.getBackground()); // JScrollPane scrollPane = new JScrollPane(citation, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, // JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // scrollPane.setOpaque(true); String calYule = "Heled J, Drummond AJ (2011), Syst Biol, doi: 10.1093/sysbio/syr087 [Calibrated Yule]"; String citation; if (treePriorCombo.getSelectedItem() == TreePriorType.SPECIES_YULE || treePriorCombo.getSelectedItem() == TreePriorType.SPECIES_YULE_CALIBRATION || treePriorCombo.getSelectedItem() == TreePriorType.SPECIES_BIRTH_DEATH) { //*BEAST addComponentWithLabel("Species Tree Prior:", treePriorCombo); addComponentWithLabel("Population Size Model:", populationSizeCombo); addLabel("Note: *BEAST only needs to select the prior for species tree."); if (treePriorCombo.getSelectedItem() == TreePriorType.SPECIES_YULE_CALIBRATION) { // addComponentWithLabel("Calibration Correction Type:", calibrationCorrectionCombo); citation = calYule; addComponentWithLabel("Citation:", citationText); citationText.setText(citation); } } else { // non *BEAST String citationCoalescent = "Kingman JFC (1982) Stoch Proc Appl 13, 235-248 [Constant Coalescent]."; addComponentWithLabel("Tree Prior:", treePriorCombo); if (!treesPanel.linkTreePriorCheck.isEnabled()) { treesPanel.updateLinkTreePriorEnablility(); } switch ((TreePriorType) treePriorCombo.getSelectedItem()) { case CONSTANT: citation = citationCoalescent; break; case EXPONENTIAL: case LOGISTIC: case EXPANSION: addComponentWithLabel("Parameterization for growth:", parameterizationCombo); partitionTreePrior.setParameterization((TreePriorParameterizationType) parameterizationCombo.getSelectedItem()); citation = //citationCoalescent + "\n" + "Griffiths RC, Tavare S (1994) Phil Trans R Soc Lond B Biol Sci 344, 403-410 [Parametric Coalescent]."; // + "\nDrummond AJ, Rambaut A, Shapiro B, Pybus OG (2005) Mol Biol Evol 22, 1185-1192."; break; case SKYLINE: groupCountField.setColumns(6); addComponentWithLabel("Number of groups:", groupCountField); addComponentWithLabel("Skyline Model:", bayesianSkylineCombo); citation = //citationCoalescent + "\n" + "Drummond AJ, Rambaut A, Shapiro B, Pybus OG (2005) Mol Biol Evol 22, 1185-1192 [Skyline Coalescent]."; break; case EXTENDED_SKYLINE: addComponentWithLabel("Model Type:", extendedBayesianSkylineCombo); treesPanel.linkTreePriorCheck.setSelected(true); treesPanel.linkTreePriorCheck.setEnabled(false); treesPanel.updateShareSameTreePriorChanged(); citation = //citationCoalescent + "\n" + "Heled J, Drummond AJ (2008) BMC Evol Biol 8, 289 [Extended Skyline Coalescent]."; break; case GMRF_SKYRIDE: addComponentWithLabel("Smoothing:", gmrfBayesianSkyrideCombo); treesPanel.linkTreePriorCheck.setSelected(true); treesPanel.linkTreePriorCheck.setEnabled(false); //For GMRF, one tree prior has to be associated to one tree model. The validation is in BeastGenerator.checkOptions() addLabel("<html>For the Skyride, tree model/tree prior combination not implemented by BEAST. " + "The Skyride is only available for a single tree<br>model partition in this release. " + "Please try the Skygrid or link all tree models." + "</html>"); citation = //citationCoalescent + "\n" + "Minin VN, Bloomquist EW, Suchard MA (2008) Mol Biol Evol 25, 1459-1471 [Skyride Coalescent]."; break; case SKYGRID: skyGridInterval.setColumns(6); addComponentWithLabel("# parameters ( = # grid-points + 1):", skyGridPointsCombo); addComponentWithLabel("Time at last point:", skyGridInterval); addLabel("It is advisable to set this cut-off time commensurate with the expected root height for optimal model interpretability."); treesPanel.linkTreePriorCheck.setSelected(true); treesPanel.linkTreePriorCheck.setEnabled(false); treesPanel.updateShareSameTreePriorChanged(); citation = //citationCoalescent + "\n" + "Gill MS, Lemey P, Faria NR, Rambaut A, Shapiro B, Suchard MA (2013) Mol Biol Evol 30, 713-724 [SkyGrid Coalescent]."; break; case YULE: citation = "Gernhard T (2008) J Theor Biol 253, 769-778 [Yule Process]." + "\nYule GU (1925) Phil Trans R Soc Lond B Biol Sci 213, 21-87 [Yule Process]."; break; case YULE_CALIBRATION: // addComponentWithLabel("Calibration Correction Type:", calibrationCorrectionCombo); citation = calYule; break; case BIRTH_DEATH: citation = BirthDeathModelParser.getCitation(); break; case BIRTH_DEATH_INCOMPLETE_SAMPLING: citation = BirthDeathModelParser.getCitationRHO(); break; case BIRTH_DEATH_SERIAL_SAMPLING: citation = BirthDeathSerialSamplingModelParser.getCitationPsiOrg(); break; case BIRTH_DEATH_BASIC_REPRODUCTIVE_NUMBER: citation = BirthDeathSerialSamplingModelParser.getCitationRT(); break; default: throw new RuntimeException("No such tree prior has been specified so cannot refer to it"); } if (treesPanel.options.maximumTipHeight > 0) citation = citation // + "\n" + // "Rodrigo AG, Felsenstein J (1999) in Molecular Evolution of HIV (Crandall K), pp. 233-272 [Serially Sampled Data]." + "\n" + "Drummond AJ, Nicholls GK, Rodrigo AG, Solomon W (2002) Genetics 161, 1307-1320 [Serially Sampled Data]."; addComponentWithLabel("Citation:", citationText); citationText.setText(citation); } // getOptions(); // // treesPanel.treeModelPanels.get(treesPanel.currentTreeModel).setOptions(); for (PartitionTreeModel model : treesPanel.treeModelPanels.keySet()) { if (model != null) { treesPanel.treeModelPanels.get(model).setOptions(); treesPanel.treeModelPanels.get(model).setupPanel(); } } // createTreeAction.setEnabled(options != null && options.dataPartitions.size() > 0); // fireTableDataChanged(); validate(); repaint(); } public void setOptions() { if (partitionTreePrior == null) { return; } settingOptions = true; treePriorCombo.setSelectedItem(partitionTreePrior.getNodeHeightPrior()); groupCountField.setValue(partitionTreePrior.getSkylineGroupCount()); //samplingProportionField.setValue(partitionTreePrior.birthDeathSamplingProportion); parameterizationCombo.setSelectedItem(partitionTreePrior.getParameterization()); bayesianSkylineCombo.setSelectedItem(partitionTreePrior.getSkylineModel()); extendedBayesianSkylineCombo.setSelectedItem(partitionTreePrior.getExtendedSkylineModel()); gmrfBayesianSkyrideCombo.setSelectedItem(partitionTreePrior.getSkyrideSmoothing()); skyGridPointsCombo.setSelectedItem(partitionTreePrior.getSkyGridCount()); double initialCutOff = partitionTreePrior.getOptions().getPartitionTreeModels().get(0).getInitialRootHeight(); final double arbitraryScalar = 1.0; initialCutOff = roundToSignificantFigures(arbitraryScalar * initialCutOff, 2); skyGridInterval.setValue( partitionTreePrior.getSkyGridInterval() == -1.0 ? initialCutOff : partitionTreePrior.getSkyGridInterval() ); populationSizeCombo.setSelectedItem(partitionTreePrior.getPopulationSizeModel()); // calibrationCorrectionCombo.setSelectedItem(partitionTreePrior.getCalibCorrectionType()); setupPanel(); settingOptions = false; validate(); repaint(); } private static double roundToSignificantFigures(double num, int n) { if (num == 0) { return 0; } final double d = Math.ceil(Math.log10(num < 0 ? -num : num)); final int power = n - (int) d; final double magnitude = Math.pow(10, power); final long shifted = Math.round(num * magnitude); return shifted / magnitude; } public void getOptions() { if (settingOptions) return; // partitionTreePrior.setNodeHeightPrior((TreePriorType) treePriorCombo.getSelectedItem()); if (partitionTreePrior.getNodeHeightPrior() == TreePriorType.SKYLINE) { Integer groupCount = groupCountField.getValue(); if (groupCount != null) { partitionTreePrior.setSkylineGroupCount(groupCount); } else { partitionTreePrior.setSkylineGroupCount(5); } } else if (partitionTreePrior.getNodeHeightPrior() == TreePriorType.SKYGRID) { Double interval = skyGridInterval.getValue(); // TODO is != null check necessary like above? partitionTreePrior.setSkyGridInterval(interval); } else if (partitionTreePrior.getNodeHeightPrior() == TreePriorType.BIRTH_DEATH) { // Double samplingProportion = samplingProportionField.getValue(); // if (samplingProportion != null) { // partitionTreePrior.birthDeathSamplingProportion = samplingProportion; // } else { // partitionTreePrior.birthDeathSamplingProportion = 1.0; // } } // partitionTreePrior.setParameterization(parameterizationCombo.getSelectedIndex()); // partitionTreePrior.setSkylineModel(bayesianSkylineCombo.getSelectedIndex()); // partitionTreePrior.setExtendedSkylineModel(((VariableDemographicModel.Type) extendedBayesianSkylineCombo.getSelectedItem()).toString()); // // partitionTreePrior.setSkyrideSmoothing(gmrfBayesianSkyrideCombo.getSelectedIndex()); // the taxon list may not exist yet... this should be set when generating... // partitionTreePrior.skyrideIntervalCount = partitionTreePrior.taxonList.getTaxonCount() - 1; } // public void setMicrosatelliteTreePrior() { // treePriorCombo.removeAllItems(); // treePriorCombo.addItem(TreePriorType.CONSTANT); // } public void setTreePriorChoices(boolean isStartBEAST, boolean isMultiLocus, boolean isTipCalibrated) { TreePriorType type = (TreePriorType) treePriorCombo.getSelectedItem(); treePriorCombo.removeAllItems(); if (isStartBEAST) { for (TreePriorType treePriorType : EnumSet.range(TreePriorType.SPECIES_YULE, TreePriorType.SPECIES_BIRTH_DEATH)) { treePriorCombo.addItem(treePriorType); } } else { for (TreePriorType treePriorType : EnumSet.range(TreePriorType.CONSTANT, TreePriorType.BIRTH_DEATH_SERIAL_SAMPLING)) { treePriorCombo.addItem(treePriorType); } // REMOVED due to unresolved issues with model // treePriorCombo.addItem(TreePriorType.BIRTH_DEATH_BASIC_REPRODUCTIVE_NUMBER); // would be much better to disable these rather than removing them if (isMultiLocus) { treePriorCombo.removeItem(TreePriorType.SKYLINE); } if (isTipCalibrated) { // remove models that require contemporaneous tips... treePriorCombo.removeItem(TreePriorType.YULE); treePriorCombo.removeItem(TreePriorType.YULE_CALIBRATION); treePriorCombo.removeItem(TreePriorType.BIRTH_DEATH); treePriorCombo.removeItem(TreePriorType.BIRTH_DEATH_INCOMPLETE_SAMPLING); } } // this makes sure treePriorCombo selects correct prior treePriorCombo.setSelectedItem(type); if (treePriorCombo.getSelectedItem() == null) { treePriorCombo.setSelectedIndex(0); } } }