Skip to content

Commit

Permalink
fix BEAUti #8
Browse files Browse the repository at this point in the history
  • Loading branch information
walterxie committed Nov 18, 2022
1 parent 1f8c928 commit 55bcbd5
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 120 deletions.
2 changes: 1 addition & 1 deletion fxtemplates/CMSubstModels.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<plugin spec="codonmodels.M0Model" id="M0.s:$(n)">
<parameter id="M0.omega.s:$(n)" name="omega" value="1.0"/>
<parameter id="M0.kappa.s:$(n)" name="kappa" value="2.0"/>
<frequencies id="F3X4Freqs.s:$(n)" spec="codonmodels.CodonFrequencies">
<frequencies id="codonFreqs.s:$(n)" spec="codonmodels.CodonFrequencies">
<data idref="$(n)"/>
</frequencies>
</plugin>
Expand Down
96 changes: 64 additions & 32 deletions src/codonmodels/app/beauti/CodonAlignmentProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import beast.base.evolution.alignment.Alignment;
import beastfx.app.inputeditor.BeautiAlignmentProvider;
import beastfx.app.inputeditor.BeautiDoc;
import beastfx.app.util.Alert;
import codonmodels.evolution.alignment.CodonAlignment;
import codonmodels.evolution.datatype.GeneticCode;
import javafx.scene.control.ChoiceDialog;

import javax.swing.*;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;


Expand All @@ -21,40 +23,70 @@
public class CodonAlignmentProvider extends BeautiAlignmentProvider {

protected void addAlignments(BeautiDoc doc, List<BEASTInterface> selectedBEASTObjects) {
for (BEASTInterface beastObject : selectedBEASTObjects) {
if (beastObject instanceof Alignment &&
((Alignment) beastObject).getDataType().getTypeDescription()=="nucleotide") {
// ensure ID of alignment is unique
int k = 0;
String id = beastObject.getID();
boolean found = true;
while (doc.pluginmap.containsKey(id) && found) {
found = false;
for (Alignment data : doc.alignments) {
if (data.getID().equals(beastObject.getID())) {
found = true;
break;
ChoiceDialog<String> dialog = new ChoiceDialog<>(
GeneticCode.GENETIC_CODE_DESCRIPTIONS[GeneticCode.UNIVERSAL_ID],
GeneticCode.GENETIC_CODE_DESCRIPTIONS);
dialog.setHeaderText("Importing codon alignment");
dialog.setTitle("Genetic Code");
dialog.setContentText("Choose Genetic Code : ");

Optional<String> choice = dialog.showAndWait();
// GENETIC_CODE_DESCRIPTIONS
loadCodonAlignment(choice.get(), doc, selectedBEASTObjects);

}

private void loadCodonAlignment(String geneticCodeDesc, BeautiDoc doc, List<BEASTInterface> selectedBEASTObjects) {
if (geneticCodeDesc == null)
Alert.showMessageDialog(null, "Fail to select a genetic code (null) ! ",
"Null Exception", Alert.ERROR_MESSAGE);
else {
GeneticCode geneticCode = GeneticCode.findByDescription(geneticCodeDesc);
System.out.println("Choose genetic code " + geneticCode.getName());

for (BEASTInterface beastObject : selectedBEASTObjects) {
if (beastObject instanceof Alignment &&
((Alignment) beastObject).getDataType().getTypeDescription() == "nucleotide") {
// ensure ID of alignment is unique
int k = 0;
String id = beastObject.getID();
boolean found = true;
while (doc.pluginmap.containsKey(id) && found) {
found = false;
for (Alignment data : doc.alignments) {
if (data.getID().equals(beastObject.getID())) {
found = true;
break;
}
}
if (found) {
k++;
id = beastObject.getID() + k;
} else {
BEASTInterface oldData = doc.pluginmap.get(beastObject.getID());
replaceItem(doc, oldData, beastObject);
}
}
if (found) {
k++;
id = beastObject.getID() + k;
} else {
BEASTInterface oldData = doc.pluginmap.get(beastObject.getID());
replaceItem(doc, oldData, beastObject);
beastObject.setID(id);
try {
// CodonAlignment wraps alignment
CodonAlignment codonAlignment = new CodonAlignment((Alignment) beastObject, geneticCode);
sortByTaxonName(((Alignment) beastObject).sequenceInput.get());
if (getStartTemplate() != null)
doc.addAlignmentWithSubnet(codonAlignment, getStartTemplate());

} catch (RuntimeException e) {
Alert.showMessageDialog(null,
"Cannot init codon alignment given genetic code " + geneticCode.getName() +
" !\nPlease check if any stop codon exists in your alignment.\n\n" +
e.getMessage());
}
}
beastObject.setID(id);
// CodonAlignment wraps alignment
CodonAlignment codonAlignment = new CodonAlignment((Alignment) beastObject, GeneticCode.UNIVERSAL);
sortByTaxonName(((Alignment) beastObject).sequenceInput.get());
if (getStartTemplate() != null) {
doc.addAlignmentWithSubnet(codonAlignment, getStartTemplate());
}
}
}// end for
}
}


@SuppressWarnings({ "rawtypes", "unchecked" })
private void replaceItem(BeautiDoc doc, BEASTInterface oldData, BEASTInterface newData) {
doc.pluginmap.remove(newData.getID());
Expand All @@ -77,14 +109,14 @@ private void replaceItem(BeautiDoc doc, BEASTInterface oldData, BEASTInterface n
}

@Override
public
public
void editAlignment(Alignment alignment, BeautiDoc doc) {
if (alignment instanceof CodonAlignment) {
if (alignment instanceof CodonAlignment codonAlignment) {
try {
CodonAlignmentViewer viewer = new CodonAlignmentViewer((CodonAlignment) alignment);
CodonAlignmentViewer viewer = new CodonAlignmentViewer(codonAlignment);
viewer.showInDialog();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
Alert.showMessageDialog(null,
"Something went wrong viewing the codon alignment: " + e.getMessage());
e.printStackTrace();
}
Expand Down
200 changes: 120 additions & 80 deletions src/codonmodels/app/beauti/CodonAlignmentViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@

import beast.base.evolution.alignment.Alignment;
import beast.base.evolution.datatype.DataType;
import beast.base.parser.NexusParser;
import beast.pkgmgmt.BEASTClassLoader;
import beastfx.app.beauti.ThemeProvider;
import codonmodels.evolution.alignment.CodonAlignment;
import codonmodels.evolution.datatype.Codon;
import codonmodels.evolution.datatype.GeneticCode;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingNode;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -21,7 +33,7 @@ public class CodonAlignmentViewer extends JPanel {
boolean useColor = false;
// flag to indicate that the most frequently occurring character is shown as a dot
boolean useDots = true;
CodonAlignment m_alignment;
final CodonAlignment m_alignment;
Map<Character, Color> m_customColorMap = new HashMap<>();

JTable mainTable;
Expand All @@ -39,15 +51,14 @@ public CodonAlignmentViewer(Alignment data) {
int siteCount = data.getSiteCount();
int taxonCount = data.getTaxonCount();
tableData = new Object[taxonCount][siteCount + 1];
char[] headerChar = updateTableData();

// set up row labels
for (int i = 0; i < taxonCount; i++) {
tableData[i][0] = data.getTaxaNames().get(i);
}

// set up column labels
columnData = new Object[siteCount + 1];

char[] headerChar = updateTableData();
updateColumnData(headerChar);

// create table in scrollpane with first column fixed
Expand Down Expand Up @@ -131,9 +142,85 @@ public Object getValueAt(int row, int column) {
scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
scrollPane.setRowHeaderView(viewport);


setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);



Box buttonBox = Box.createHorizontalBox();
JCheckBox useDotsCheckBox = new JCheckBox("Use dots", true);
useDotsCheckBox.addActionListener(e -> {
JCheckBox _useDots = (JCheckBox) e.getSource();
useDots = _useDots.isSelected();
updateTableData();
repaint();
});
buttonBox.add(useDotsCheckBox);

JCheckBox useColorCheckBox = new JCheckBox("Use Color");
useColorCheckBox.setName("UseColor");
useColorCheckBox.addActionListener(e -> {
JCheckBox hasColor = (JCheckBox) e.getSource();
useColor = hasColor.isSelected();
updateTableData();
repaint();
});
buttonBox.add(useColorCheckBox);

JLabel label = new JLabel(" Genetic code : " + m_alignment.getGeneticCode().getDescription());
buttonBox.add(label);

/* after BEAST 2.7 exception thrown if stop codon.
JComboBox geneticCodeComboBox = new JComboBox(GeneticCode.GENETIC_CODE_NAMES);
int idx = 0;
for (int i = 0; i < GeneticCode.GENETIC_CODE_NAMES.length; i++) {
String gcName = GeneticCode.GENETIC_CODE_NAMES[i];
if (gcName.equalsIgnoreCase(m_alignment.getGeneticCode().getName())) {
idx = i;
break;
}
}
geneticCodeComboBox.setSelectedIndex(idx);
geneticCodeComboBox.addActionListener(e -> {
JComboBox cb = (JComboBox)e.getSource();
String geneticCodeName = (String)cb.getSelectedItem();
GeneticCode geneticCode = GeneticCode.findByName(geneticCodeName);
try {
m_alignment.setGeneticCode(geneticCode);
} catch (RuntimeException ex) {
JOptionPane.showMessageDialog(this,
ex.getMessage(),"Find stop codon", JOptionPane.ERROR_MESSAGE);
}
char[] header = updateTableData();
// System.out.println(header);
updateColumnData(header);
JTableHeader th = mainTable.getTableHeader();
TableColumnModel tcm = th.getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++) {
TableColumn tc = tcm.getColumn(i);
tc.setHeaderValue( columnData[i+1] );
}
th.repaint();
repaint();
});
buttonBox.add(geneticCodeComboBox);
JButton checkStopCodonJButton = new JButton("Check Stop Codon");
checkStopCodonJButton.addActionListener(e -> {
if (stopCodonSite < 0) {
JOptionPane.showMessageDialog(this,
"There is no stop codon,\nthe genetic code is valid for this alignment.",
"No stop codon", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this,
"Find a stop codon at triplet " + (stopCodonSite+1) +
",\nplease choose the correct genetic code or use codon alignment!",
"Find stop codon", JOptionPane.ERROR_MESSAGE);
}
});
buttonBox.add(checkStopCodonJButton);
*/
add(buttonBox, BorderLayout.SOUTH);
}

private void updateColumnData(char[] headerChar) {
Expand Down Expand Up @@ -254,82 +341,35 @@ private char mostFrequentCharInPattern(String pattern) {
}

public void showInDialog() {
JDialog dlg = new JDialog();
dlg.setName("CodonAlignmentViewer");
dlg.add(this);

Box buttonBox = Box.createHorizontalBox();
JCheckBox useDotsCheckBox = new JCheckBox("Use dots", true);
useDotsCheckBox.addActionListener(e -> {
JCheckBox _useDots = (JCheckBox) e.getSource();
useDots = _useDots.isSelected();
updateTableData();
repaint();
});
buttonBox.add(useDotsCheckBox);
Dialog dialog = new Dialog();
DialogPane pane = dialog.getDialogPane();
pane.getButtonTypes().add(ButtonType.CLOSE);
pane.setId("CodonAlignmentViewer");
SwingNode swingNode = new SwingNode();
swingNode.setContent(this);
pane.setContent(swingNode);
pane.setPrefSize(1024, 600);
dialog.setResizable(true);
ThemeProvider.loadStyleSheet(pane.getScene());
dialog.showAndWait();
}

JCheckBox useColorCheckBox = new JCheckBox("Use Color");
useColorCheckBox.setName("UseColor");
useColorCheckBox.addActionListener(e -> {
JCheckBox hasColor = (JCheckBox) e.getSource();
useColor = hasColor.isSelected();
updateTableData();
repaint();
});
buttonBox.add(useColorCheckBox);
public static void main(String[] args) {
BEASTClassLoader.initServices();
// set user.dir = ~/WorkSpace/codonsubstmodels
BEASTClassLoader.addServices(System.getProperty("user.dir") +
File.separator + "version.xml");

JComboBox geneticCodeComboBox = new JComboBox(GeneticCode.GENETIC_CODE_NAMES);
int idx = 0;
for (int i = 0; i < GeneticCode.GENETIC_CODE_NAMES.length; i++) {
String gcName = GeneticCode.GENETIC_CODE_NAMES[i];
if (gcName.equalsIgnoreCase(m_alignment.getGeneticCode().getName())) {
idx = i;
break;
}
try {
NexusParser parser = new NexusParser();
parser.parseFile(new File(args[0]));
Alignment data = parser.m_alignment;
CodonAlignment codonAlignment = new CodonAlignment(data, GeneticCode.VERTEBRATE_MT);
CodonAlignmentViewer panel = new CodonAlignmentViewer(codonAlignment);
new JFXPanel();
Platform.runLater(panel::showInDialog);
} catch (Exception e) {
e.printStackTrace();
}
geneticCodeComboBox.setSelectedIndex(idx);
geneticCodeComboBox.addActionListener(e -> {
JComboBox cb = (JComboBox)e.getSource();
String geneticCodeName = (String)cb.getSelectedItem();
GeneticCode geneticCode = GeneticCode.findByName(geneticCodeName);
m_alignment.setGeneticCode(geneticCode);

char[] headerChar = updateTableData();
// System.out.println(headerChar);
updateColumnData(headerChar); // not refresh
JTableHeader th = mainTable.getTableHeader();
TableColumnModel tcm = th.getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++) {
TableColumn tc = tcm.getColumn(i);
tc.setHeaderValue( columnData[i+1] );
}
th.repaint();
repaint();
});
buttonBox.add(geneticCodeComboBox);

JButton checkStopCodonJButton = new JButton("Check Stop Codon");
checkStopCodonJButton.addActionListener(e -> {
if (stopCodonSite < 0) {
JOptionPane.showMessageDialog(this,
"There is no stop codon,\nthe genetic code is valid for this alignment.",
"No stop codon", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this,
"Find a stop codon at triplet " + (stopCodonSite+1) +
",\nplease choose the correct genetic code or use codon alignment!",
"Find stop codon", JOptionPane.ERROR_MESSAGE);
}
});
buttonBox.add(checkStopCodonJButton);

dlg.add(buttonBox, BorderLayout.SOUTH);

int size = UIManager.getFont("Label.font").getSize();
dlg.setSize(1024 * size / 13, 600 * size / 13);
dlg.setModal(true);
dlg.setVisible(true);
dlg.dispose();
}

}
Loading

0 comments on commit 55bcbd5

Please sign in to comment.