/* * PriorSettingsPanel.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.priorsPanel; import dr.app.beauti.options.Parameter; import dr.app.beauti.types.PriorType; import dr.app.gui.chart.Axis; import dr.app.gui.chart.JChart; import dr.app.gui.chart.LinearAxis; import dr.app.gui.chart.PDFPlot; import dr.app.util.OSType; import dr.math.distributions.Distribution; import dr.util.NumberFormatter; import jam.panels.OptionsPanel; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.HashMap; import java.util.Map; /** * @author Andrew Rambaut * @author Alexei Drummond * @author Walter Xie * @version $Id: PriorDialog.java,v 1.4 2006/09/05 13:29:34 rambaut Exp $ */ public class PriorSettingsPanel extends JPanel { private final JFrame frame; private JDialog dialog; private final Map<PriorType, PriorOptionsPanel> optionsPanels = new HashMap<PriorType, PriorOptionsPanel>(); private JComboBox priorCombo; private JLabel citationText; private JLabel oneOverXCaution; private JLabel improperCaution; private JChart chart; private JPanel quantilePanel; private JTextArea quantileText; private Parameter parameter; public PriorSettingsPanel(JFrame frame) { this.frame = frame; optionsPanels.put(PriorType.NONE_FIXED, PriorOptionsPanel.INFINITE_UNIFORM); optionsPanels.put(PriorType.NONE_IMPROPER, PriorOptionsPanel.INFINITE_UNIFORM); optionsPanels.put(PriorType.UNIFORM_PRIOR, PriorOptionsPanel.UNIFORM); optionsPanels.put(PriorType.EXPONENTIAL_PRIOR, PriorOptionsPanel.EXPONENTIAL); optionsPanels.put(PriorType.LAPLACE_PRIOR, PriorOptionsPanel.LAPLACE); optionsPanels.put(PriorType.NORMAL_PRIOR, PriorOptionsPanel.NORMAL); optionsPanels.put(PriorType.LOGNORMAL_PRIOR, PriorOptionsPanel.LOG_NORMAL); optionsPanels.put(PriorType.GAMMA_PRIOR, PriorOptionsPanel.GAMMA); optionsPanels.put(PriorType.INVERSE_GAMMA_PRIOR, PriorOptionsPanel.INVERSE_GAMMA); optionsPanels.put(PriorType.BETA_PRIOR, PriorOptionsPanel.BETA); optionsPanels.put(PriorType.CTMC_RATE_REFERENCE_PRIOR, PriorOptionsPanel.CTMC_RATE_REFERENCE); optionsPanels.put(PriorType.ONE_OVER_X_PRIOR, PriorOptionsPanel.ONE_OVER_X); // optionsPanels.put(PriorType.NORMAL_HPM_PRIOR, new NormalHPMOptionsPanel()); // optionsPanels.put(PriorType.LOGNORMAL_HPM_PRIOR, new LognormalHPMOptionsPanel()); // optionsPanels.put(PriorType.GMRF_PRIOR, new GMRFOptionsPanel()); chart = new JChart(new LinearAxis(Axis.AT_MINOR_TICK, Axis.AT_MINOR_TICK), new LinearAxis(Axis.AT_ZERO, Axis.AT_DATA)); JLabel quantileLabels = new JLabel(); quantileLabels.setFont(quantileLabels.getFont().deriveFont(10.0f)); quantileLabels.setOpaque(false); quantileLabels.setText("<html><p align=\"right\">Quantiles: 2.5%:<br>5%:<br>Median:<br>95%:<br>97.5%:</p></html>"); quantileText = new JTextArea(0, 5); quantileText.setFont(quantileText.getFont().deriveFont(10.0f)); quantileText.setOpaque(false); quantileText.setEditable(false); quantileLabels.setHorizontalAlignment(JLabel.LEFT); quantilePanel = new JPanel(); quantilePanel.add(quantileLabels); quantilePanel.add(quantileText); citationText = new JLabel(); citationText.setFont(quantileLabels.getFont().deriveFont(11.0f)); citationText.setOpaque(false); citationText.setText( "<html>Approximate continuous time Markov chain rate <br>" + "reference prior developed in Ferreira & Suchard (2008).<br>" + "Use when explicit prior information is unavailable</html>"); oneOverXCaution = new JLabel(); oneOverXCaution.setFont(quantileLabels.getFont().deriveFont(11.0f)); oneOverXCaution.setOpaque(false); oneOverXCaution.setText( "<html>This improper distribution often leads to an improper posterior. <br>" + "This distribution is likely appropriate when used for the <br>" + "constant population size under the Coalescent.</html>"); improperCaution = new JLabel(); improperCaution.setFont(quantileLabels.getFont().deriveFont(11.0f)); improperCaution.setOpaque(false); improperCaution.setText( "<html>A uniform prior with infinite bounds is not a proper prior <br>" + "(it doesn't integrate to 1). This choice is not recommended.</html>"); setLayout(new GridBagLayout()); } /** * Set the parameter to be controlled * q * @param parameter */ public void setParameter(final Parameter parameter) { this.parameter = parameter; priorCombo = new JComboBox(); for (PriorType priorType : PriorType.getPriorTypes(parameter)) { priorCombo.addItem(priorType); } if (parameter.priorType != null) { priorCombo.setSelectedItem(parameter.priorType); } setupComponents(); // setArguments here priorCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { setupComponents(); dialog.pack(); dialog.repaint(); } }); for (PriorOptionsPanel optionsPanel : optionsPanels.values()) { optionsPanel.removeAllListeners(); optionsPanel.addListener(new PriorOptionsPanel.Listener() { public void optionsPanelChanged() { setupChart(); dialog.pack(); dialog.repaint(); } }); } } public void getArguments(Parameter parameter) { // if (parameter.isNodeHeight || parameter.isStatistic) { // parameter.priorType = (PriorType) priorCombo.getSelectedItem(); // if (parameter.priorType == PriorType.NONE_TREE_PRIOR || parameter.priorType == PriorType.NONE_STATISTIC) { // parameter.initial = Double.NaN; // return; // } // } else { // parameter.priorType = (PriorType) priorCombo.getSelectedItem(); // } // // if (!parameter.isStatistic && initialField.getValue() != null) parameter.initial = initialField.getValue(); // // if (parameter.priorType != PriorType.ONE_OVER_X_PRIOR) // optionsPanels.get(parameter.priorType).setParameterPrior(parameter); parameter.priorType = (PriorType) priorCombo.getSelectedItem(); PriorOptionsPanel panel = optionsPanels.get(parameter.priorType); if (panel != null) { panel.getArguments(parameter, parameter.priorType); } } private void setupComponents() { removeAll(); OptionsPanel optionsPanel = new OptionsPanel(12, (OSType.isMac() ? 6 : 24)); JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER)); panel1.add(optionsPanel); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.weightx = 1.0; gbc.weighty = 0.0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.PAGE_START; gbc.gridwidth = GridBagConstraints.REMAINDER; add(panel1, gbc); PriorType priorType = (PriorType) priorCombo.getSelectedItem(); if (!parameter.isPriorFixed) { optionsPanel.addComponentWithLabel("Prior Distribution: ", priorCombo); } else { optionsPanel.addComponentWithLabel("Prior Distribution: ", new JLabel(priorType.toString())); } PriorOptionsPanel panel3 = optionsPanels.get(priorType); if (panel3 != null) { panel3.setArguments(parameter, priorType); // important to make init field appear during switch optionsPanel.addSpanningComponent(panel3); } if (priorType == PriorType.CTMC_RATE_REFERENCE_PRIOR) { optionsPanel.addSpanningComponent(citationText); } if (priorType == PriorType.ONE_OVER_X_PRIOR) { optionsPanel.addSpanningComponent(oneOverXCaution); } if (priorType == PriorType.NONE_IMPROPER) { optionsPanel.addSpanningComponent(improperCaution); } if (priorType.isPlottable()) { optionsPanel.addSeparator(); setupChart(); chart.setMinimumSize(new Dimension(120, 120)); chart.setPreferredSize(new Dimension(300, 200)); chart.setFontSize(8); gbc.gridy = 1; gbc.weighty = 1.0; gbc.fill = GridBagConstraints.BOTH; add(chart, gbc); gbc.gridy = 2; gbc.weighty = 0.0; gbc.anchor = GridBagConstraints.PAGE_END; gbc.fill = GridBagConstraints.HORIZONTAL; add(quantilePanel, gbc); } repaint(); } NumberFormatter formatter = new NumberFormatter(4); void setupChart() { chart.removeAllPlots(); if (hasInvalidInput(false)) { quantileText.setText("Invalid input"); return; } PriorType priorType = (PriorType) priorCombo.getSelectedItem(); if (priorType == null) { priorType = parameter.priorType; priorCombo.setSelectedItem(priorType); } // ExponentialDistribution(1.0 / mean) // if (priorType == PriorType.EXPONENTIAL_PRIOR && parameter.mean == 0) parameter.mean = 1; PriorOptionsPanel priorOptionsPanel = optionsPanels.get(priorType); double offset = 0.0; // TODO is this used or duplicated to OffsetPositiveDistribution? // this does not refresh dist from parameter truncation lower/upper, it get them from GUI Distribution distribution = priorOptionsPanel.getDistribution(parameter); chart.addPlot(new PDFPlot(distribution, offset)); if (distribution != null) { quantileText.setText(formatter.format(distribution.quantile(0.025)) + "\n" + formatter.format(distribution.quantile(0.05)) + "\n" + formatter.format(distribution.quantile(0.5)) + "\n" + formatter.format(distribution.quantile(0.95)) + "\n" + formatter.format(distribution.quantile(0.975))); } } public boolean hasInvalidInput(boolean showError) { PriorType priorType = (PriorType) priorCombo.getSelectedItem(); PriorOptionsPanel panel = optionsPanels.get(priorType); if (panel != null) { if (panel.hasInvalidInput(priorType)) { if (showError) JOptionPane.showMessageDialog(frame, panel.error, "Invalid input", JOptionPane.ERROR_MESSAGE); return true; } else { return false; } } // if there is no panel for this prior type then assume it is valid return false; // throw new IllegalComponentStateException("Cannot get PriorOptionsPanel"); } public void setDialog(final JDialog dialog) { this.dialog = dialog; } }