Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
package beastfx.app.inputeditor;







import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import beast.base.core.BEASTInterface;
import beast.base.core.Input;
import beast.base.inference.Distribution;
import beast.base.parser.PartitionContext;
import beast.base.spec.domain.Int;
import beast.base.spec.domain.NonNegativeInt;
import beast.base.spec.domain.NonNegativeReal;
import beast.base.spec.domain.PositiveInt;
import beast.base.spec.domain.PositiveReal;
import beast.base.spec.domain.Real;
import beast.base.spec.domain.*;
import beast.base.spec.inference.distribution.ScalarDistribution;
import beast.base.spec.inference.distribution.TensorDistribution;
import beast.base.spec.inference.parameter.BoolScalarParam;
import beast.base.spec.inference.parameter.IntScalarParam;
import beast.base.spec.inference.parameter.IntVectorParam;
import beast.base.spec.inference.parameter.RealScalarParam;
import beast.base.spec.inference.parameter.RealVectorParam;
import beast.base.spec.type.IntScalar;
import beast.base.spec.type.IntVector;
import beast.base.spec.type.RealScalar;
import beast.base.spec.type.RealVector;
import beast.base.spec.type.Scalar;
import beast.base.spec.inference.parameter.*;
import beast.base.spec.type.*;
import beastfx.app.util.FXUtils;
import javafx.scene.Node;
import javafx.scene.control.Button;
Expand All @@ -42,6 +20,10 @@
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TensorDistributionInputEditor extends BEASTObjectInputEditor implements HasExpandBox {

public TensorDistributionInputEditor() {
Expand Down Expand Up @@ -420,6 +402,16 @@ private String getParameters() {
b.append(',');
b.append(p.getInput("value").get().toString().trim());
}
} else if (o != null && o instanceof RealVectorParam<?> || o instanceof IntVectorParam<?> || o instanceof BoolVectorParam) {
// vector hyperparameters (e.g. alpha of Dirichlet)
BEASTInterface p = (BEASTInterface) o;
if (b == null) {
b = new StringBuilder();
b.append(p.getInput("value").get().toString().trim());
} else {
b.append(',');
b.append(p.getInput("value").get().toString().trim());
}
} else if (o != null && o instanceof Double && !input.getName().equals("offset")) {
Double p = (Double) o;
if (b == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
package beastfx.app.inputeditor.spec;

import beast.base.core.BEASTInterface;
import beast.base.core.Input;
import beast.base.inference.Operator;
import beast.base.inference.StateNode;
import beast.base.spec.inference.distribution.TensorDistribution;
import beast.base.spec.inference.parameter.BoolVectorParam;
import beast.base.spec.inference.parameter.IntVectorParam;
import beast.base.spec.inference.parameter.RealVectorParam;
import beast.base.spec.type.Vector;
import beastfx.app.inputeditor.BEASTObjectInputEditor;
import beastfx.app.inputeditor.BEASTObjectPanel;
import beastfx.app.inputeditor.BeautiDoc;
import beastfx.app.util.FXUtils;
import javafx.geometry.Insets;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;

import java.util.List;

/**
* InputEditor for spec vector parameters: RealVectorParam, IntVectorParam,
* BoolVectorParam (and their subclasses, e.g. SimplexParam).
*
* Displays all element values in a single space-separated text field, an
* isEstimated checkbox, and an edit button for accessing dimension / domain /
* key settings via BEASTObjectDialog.
*
* Handles IntVector and BoolVector via the same text-field pattern, which is
* consistent with how ParameterInputEditor handles the legacy Parameter.Base.
*/
public class VectorInputEditor extends BEASTObjectInputEditor {

public CheckBox m_isEstimatedBox;

public VectorInputEditor() {
super();
}

public VectorInputEditor(BeautiDoc doc) {
super(doc);
}

@Override
public Class<?> type() {
return Vector.class;
}

/**
* Register all three concrete vector-param base classes.
* Subclasses (e.g. SimplexParam extends RealVectorParam) are found
* automatically through InputEditorFactory's superclass walk.
*/
@Override
public Class<?>[] types() {
return new Class<?>[] {
RealVectorParam.class,
IntVectorParam.class,
BoolVectorParam.class,
};
}

@Override
public void init(Input<?> input, BEASTInterface beastObject, int itemNr,
ExpandOption isExpandOption, boolean addButtons) {
if ("param".equals(input.getName()) && beastObject instanceof TensorDistribution) {
// TensorDistributionInputEditor shows paramInput via the range button; suppress here
pane = FXUtils.newHBox();
setVisible(false);
setManaged(false);
return;
}
super.init(input, beastObject, itemNr, isExpandOption, addButtons);
m_beastObject = beastObject;
pane.setPadding(new Insets(5));
}

// --- value helpers ---------------------------------------------------

private Object resolveParam() {
if (itemNr < 0) {
return m_input.get();
}
return ((List<?>) m_input.get()).get(itemNr);
}

/** Space-separated string of all element values. */
private String valuesToString(Object param) {
StringBuilder sb = new StringBuilder();
if (param instanceof RealVectorParam<?> rvp) {
for (double v : rvp.getValues()) {
if (sb.length() > 0) sb.append(' ');
sb.append(v);
}
} else if (param instanceof IntVectorParam<?> ivp) {
for (int v : ivp.getValues()) {
if (sb.length() > 0) sb.append(' ');
sb.append(v);
}
} else if (param instanceof BoolVectorParam bvp) {
for (boolean v : bvp.getValues()) {
if (sb.length() > 0) sb.append(' ');
sb.append(v);
}
}
return sb.toString();
}

// --- InputEditor.Base overrides -------------------------------------

@Override
protected void setUpEntry() {
super.setUpEntry();
// wider field: vectors can have many elements
m_entry.setPrefWidth(300);
m_entry.setMaxWidth(500);
}

@Override
protected void initEntry() {
Object param = resolveParam();
if (param == null) return;
m_entry.setText(valuesToString(param));
}

@Override
protected void processEntry() {
try {
Object param = resolveParam();
String text = m_entry.getText().trim();

if (param instanceof RealVectorParam<?> rvp) {
String oldValue = valuesToString(rvp);
int oldDim = rvp.size();
rvp.valuesInput.setValue(text, rvp);
rvp.initAndValidate();
if (rvp.size() != oldDim) {
rvp.setDimension(oldDim);
rvp.valuesInput.setValue(oldValue, rvp);
rvp.initAndValidate();
throw new IllegalArgumentException("Entry caused change in dimension");
}
} else if (param instanceof IntVectorParam<?> ivp) {
String oldValue = valuesToString(ivp);
int oldDim = ivp.size();
ivp.valuesInput.setValue(text, ivp);
ivp.initAndValidate();
if (ivp.size() != oldDim) {
ivp.setDimension(oldDim);
ivp.valuesInput.setValue(oldValue, ivp);
ivp.initAndValidate();
throw new IllegalArgumentException("Entry caused change in dimension");
}
} else if (param instanceof BoolVectorParam bvp) {
bvp.valuesInput.setValue(text, bvp);
bvp.initAndValidate();
}

validateInput();
} catch (Exception ex) {
if (m_validateLabel != null) {
m_validateLabel.setVisible(true);
m_validateLabel.setTooltip(new Tooltip(
"Parsing error: " + ex.getMessage() +
". Value was left at " + resolveParam() + "."));
m_validateLabel.setColor("orange");
}
repaint();
}
}

/**
* Replaces the generic BEASTObject combobox with a text field showing
* all element values, an isEstimated checkbox, and an edit button.
*/
@Override
protected void addComboBox(Pane box, Input<?> input, BEASTInterface beastObject) {
Object parameter = (itemNr >= 0)
? ((List<?>) input.get()).get(itemNr)
: input.get();

if (parameter == null) {
super.addComboBox(box, input, beastObject);
return;
}

HBox paramBox = FXUtils.newHBox();

setUpEntry();
paramBox.getChildren().add(m_entry);
FXUtils.createHMCButton(paramBox, m_beastObject, m_input);

if (m_bAddButtons && BEASTObjectPanel.countInputs(parameter, doc) > 0) {
paramBox.getChildren().add(createEditButton(input));
}

if (parameter instanceof StateNode sn) {
m_isEstimatedBox = new CheckBox(
doc.beautiConfig.getInputLabel(
(BEASTInterface) parameter, sn.isEstimatedInput.getName()));
m_isEstimatedBox.setId(input.getName() + ".isEstimated");
m_isEstimatedBox.setMaxWidth(Double.POSITIVE_INFINITY);
box.setMaxWidth(Double.POSITIVE_INFINITY);
m_isEstimatedBox.setSelected(sn.isEstimatedInput.get());
m_isEstimatedBox.setTooltip(
new Tooltip("Estimate value of this parameter in the MCMC chain"));
m_isEstimatedBox.setVisible(doc.isExpertMode());

for (Object output : ((BEASTInterface) parameter).getOutputs()) {
if (output instanceof Operator) {
m_isEstimatedBox.setVisible(true);
break;
}
}

m_isEstimatedBox.setOnAction(e -> {
try {
sn.isEstimatedInput.setValue(m_isEstimatedBox.isSelected(), sn);
hardSync();
refreshPanel();
} catch (Exception ex) {
// ignore
}
});

paramBox.getChildren().add(m_isEstimatedBox);
}

box.getChildren().add(paramBox);
}

@Override
protected void addValidationLabel() {
super.addValidationLabel();
// hide the edit button when the isEstimated checkbox is hidden
if (m_editBEASTObjectButton != null && m_isEstimatedBox != null) {
m_editBEASTObjectButton.setVisible(m_isEstimatedBox.isVisible());
}
}

@Override
protected void refresh() {
Object param = resolveParam();
if (param != null && m_entry != null) {
m_entry.setText(valuesToString(param));
}
if (m_isEstimatedBox != null && param instanceof StateNode sn) {
m_isEstimatedBox.setSelected(sn.isEstimatedInput.get());
}
repaint();
}
}
1 change: 1 addition & 0 deletions beast-fx/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
beastfx.app.beauti.TreeDistributionInputEditor,
beastfx.app.inputeditor.spec.SiteModelInputEditor,
beastfx.app.inputeditor.spec.ScalarInputEditor,
beastfx.app.inputeditor.spec.VectorInputEditor,
beastfx.app.inputeditor.ScalarDistributionInputEditor,
beastfx.app.inputeditor.TensorDistributionInputEditor,
beastfx.app.inputeditor.IIDInputEditor;
Expand Down
10 changes: 5 additions & 5 deletions beast-fx/src/main/resources/beast.fx/fxtemplates/Standard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,8 @@ ClusterTree/clusterType/,
<taxonset id='TaxonSet.$(n)' spec='beast.base.evolution.alignment.TaxonSet' alignment='@$(n)' />
<plugin spec='beast.base.evolution.tree.Tree' id='Tree.t:$(n)' taxonset='@TaxonSet.$(n)'/>

<!--plugin spec='beast.base.evolution.tree.coalescent.RandomTree' id='RandomTree.t:$(n)' estimate='false' trait='@datetrait.$(n)' initial='@Tree.t:$(n)'-->
<plugin spec='beast.base.evolution.tree.coalescent.RandomTree' id='RandomTree.t:$(n)' estimate='false' initial='@Tree.t:$(n)'>
<!--plugin spec='beast.base.spec.evolution.tree.coalescent.RandomTree' id='RandomTree.t:$(n)' estimate='false' trait='@datetrait.$(n)' initial='@Tree.t:$(n)'-->
<plugin spec='beast.base.spec.evolution.tree.coalescent.RandomTree' id='RandomTree.t:$(n)' estimate='false' initial='@Tree.t:$(n)'>
<taxa idref='data'/>
<populationModel id='ConstantPopulation0.t:$(n)' spec='ConstantPopulation'>
<popSize id='randomPopSize.t:$(n)' spec='parameter.RealParameter' value='1'/>
Expand Down Expand Up @@ -473,7 +473,7 @@ ClusterTree/clusterType/,
<!-- Tree initialisation -->
<!-- Random tree -->

<subtemplate id='RandomTree' class='beast.base.evolution.tree.coalescent.RandomTree' mainid='RandomTree.t:$(n)'>
<subtemplate id='RandomTree' class='beast.base.spec.evolution.tree.coalescent.RandomTree' mainid='RandomTree.t:$(n)'>
<![CDATA[
<tree spec='beast.base.evolution.tree.coalescent.RandomTree' id='RandomTree.t:$(n)' estimate='false' initial="@Tree.t:$(n)">
<taxa idref='data'/>
Expand All @@ -486,9 +486,9 @@ ClusterTree/clusterType/,

<!-- Cluster tree (defaults to UPGMA) -->

<subtemplate id='ClusterTree' class='beast.base.evolution.tree.ClusterTree' mainid='ClusterTree.t:$(n)'>
<subtemplate id='ClusterTree' class='beast.base.spec.evolution.tree.ClusterTree' mainid='ClusterTree.t:$(n)'>
<![CDATA[
<tree spec='beast.base.evolution.tree.ClusterTree' id='ClusterTree.t:$(n)' initial="@Tree.t:$(n)" clusterType='upgma' estimate='false' taxa='@$(n)'/>
<tree spec='beast.base.spec.evolution.tree.ClusterTree' id='ClusterTree.t:$(n)' initial="@Tree.t:$(n)" clusterType='upgma' estimate='false' taxa='@$(n)'/>
]]>
</subtemplate>

Expand Down
Loading