package jalview.ext.archaeopteryx;
+import jalview.analysis.AlignmentSorter;
+import jalview.analysis.Conservation;
+import jalview.api.AlignViewportI;
+import jalview.commands.CommandI;
+import jalview.commands.OrderCommand;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
+import jalview.gui.AlignViewport;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
import jalview.gui.PaintRefresher;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.UserColourScheme;
import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
import org.forester.archaeopteryx.MainFrame;
import org.forester.phylogeny.Phylogeny;
import org.forester.phylogeny.PhylogenyMethods;
import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.BranchColor;
/**
* Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
public final class JalviewBinding
implements ExternalTreeViewerBindingI<PhylogenyNode>
{
+ private final MainFrame aptxFrame;
+
private org.forester.archaeopteryx.TreePanel treeView;
private AlignmentViewport parentAvport;
- private JTabbedPane treeTabs;
+ private final JTabbedPane treeTabs;
private final StructureSelectionManager ssm;
+ private AlignmentPanel[] associatedPanels;
+
private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
+ private float rootX;
+
+ private float furthestNodeX;
+
+ private int nrTreeGroups = 0;
+
+ private boolean applyToAllViews = false;
+
/**
*
* @param archaeopteryx
final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
{
+
+ if (archaeopteryx.getMainPanel().getTabbedPane().getTabCount() > 1)
+ {
+ JvOptionPane.showMessageDialog(Desktop.desktop,
+ MessageManager.getString("label.tabs_detected_archaeopteryx"),
+ MessageManager.getString("label.problem_reading_tree_file"),
+ JvOptionPane.WARNING_MESSAGE);
+
+ }
+
// deal with/prohibit null values here as that will cause problems
+ aptxFrame = archaeopteryx;
parentAvport = jalviewAlignmentViewport;
sequencesBoundToNodes = alignMappedToNodes;
nodesBoundToSequences = nodesMappedToAlign;
treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
treeTabs = archaeopteryx.getMainPanel().getTabbedPane();
ssm = parentAvport.getStructureSelectionManager();
-
- // archaeopteryx.getMainPanel().getControlPanel().setColorBranches(true);
ssm.addSelectionListener(this);
treeView.addMouseListener(this);
+
PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
+ associatedPanels = PaintRefresher
+ .getAssociatedPanels(parentAvport.getSequenceSetId());
+ aptxFrame.addInternalFrameListener(new InternalFrameAdapter()
+ {
+
+ @Override
+ public void internalFrameClosed(InternalFrameEvent e)
+ {
+ AptxInit.getAllAptxFrames().remove(aptxFrame);
+ ssm.removeSelectionListener(JalviewBinding.this);
+ }
+
+ });
treeTabs.addChangeListener(new ChangeListener()
{
*/
public void run()
{
+ treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
parentAvport.sendSelection();
// PaintRefresher.Refresh(treeView,
// parentAvport.getSequenceSetId());
});
}
-
+
});
}
@Override
public void actionPerformed(ActionEvent e)
{
+ // aptxFrame.actionPerformed(e);
+
}
@Override
}
else
{
- partitionTree(e);
-
-
+
+ partitionTree(e.getX());
}
-
+ PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
+ treeView.repaint();
+
+
+
}
});
treeView.setFoundNodes0(
new HashSet<Long>(seqsel.getSequences().size()));
+
for (SequenceI selectedSequence : seqsel.getSequences())
{
PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
if (matchingNode != null)
{
treeView.getFoundNodes0().add(matchingNode.getId());
+
+
+ if (!matchingNode.getBranchData().isHasBranchColor())
+ {
+ // Color foundNodesColour = treeView.getTreeColorSet()
+ // .getFoundColor0();
+ // matchingNode.getBranchData()
+ // .setBranchColor(new BranchColor(foundNodesColour));
+
+ }
+
}
}
- treeView.repaint();
+ treeView.repaint();
}
/**
* Partially refactored from TreeCanvas
*/
- public void partitionTree(final MouseEvent e)
+ public void partitionTree(final int x)
{
- int x = e.getX();
- int lineLength = treeView.getHeight();
-
Phylogeny tree = treeView.getPhylogeny();
- double treeHeight = tree.calculateHeight(true);
+
+ if (!tree.isEmpty())
+ {
+ // should be calculated on each partition as the tree can theoretically
+ // change in the meantime
+ PhylogenyNode furthestNode = PhylogenyMethods
+ .calculateNodeWithMaxDistanceToRoot(tree);
+ furthestNodeX = furthestNode.getXcoord();
+ rootX = tree.getRoot().getXcoord();
+
+ if (furthestNodeX != rootX && !(x < rootX || x > furthestNodeX)) // don't
+ // bother
+ // if 0
+ // distance tree or
+ // clicked x lies outside
+ // of tree
+ {
+
+ float threshold = (x - rootX) / (furthestNodeX - rootX);
+ List<PhylogenyNode> foundNodes = getNodesAboveThreshold(threshold,
+ tree.getRoot());
+
+ }
+ }
+
+
+ }
+
+ public List<PhylogenyNode> getNodesAboveThreshold(double threshold,
+ PhylogenyNode node)
+ {
+
+ List<PhylogenyNode> nodesAboveThreshold = new ArrayList<>();
+
+ parentAvport.setSelectionGroup(null);
+ parentAvport.getAlignment().deleteAllGroups();
+ parentAvport.clearSequenceColours();
+ if (parentAvport.getCodingComplement() != null)
+ {
+ parentAvport.getCodingComplement().setSelectionGroup(null);
+ parentAvport.getCodingComplement().getAlignment().deleteAllGroups();
+ parentAvport.getCodingComplement().clearSequenceColours();
+ }
+ colourNodesAboveThreshold(nodesAboveThreshold, threshold,
+ node);
+ return nodesAboveThreshold;
- if (treeHeight != 0)
+ }
+
+ /**
+ * Partially refactored from TreeCanvas colourGroups (can be made nicer).
+ *
+ * @param nodeList
+ * @param threshold
+ * @param treeLength
+ * @param node
+ * @return
+ */
+ private List<PhylogenyNode> colourNodesAboveThreshold(
+ List<PhylogenyNode> nodeList, double threshold,
+ PhylogenyNode node)
+ {
+
+ for (PhylogenyNode childNode : node.getDescendants())
{
- int viewWidth = treeView.getWidth();
+ childNode.getBranchData()
+ .setBranchColor(new BranchColor(Color.black));
+ float nodeCutoff = (childNode.getXcoord() - rootX)
+ / (furthestNodeX - rootX);
+
+ if (nodeCutoff > threshold)
+ {
+ nodeList.add(childNode);
- // treeView.validate();
+ Color randomColour = new Color((int) (Math.random() * 255),
+ (int) (Math.random() * 255), (int) (Math.random() * 255));
+ childNode.getBranchData()
+ .setBranchColor(new BranchColor(randomColour));
- // System.out.println("selection");
- // System.out.println(x);
- // System.out.println("-------------");
- // System.out.println("width");
- // System.out.println(viewWidth);
+ List<SequenceI> groupSeqs = new ArrayList<>();
+ SequenceI seq = nodesBoundToSequences.get(childNode);
+ if (seq != null)
+ {
+ groupSeqs.add(seq);
+ parentAvport.setSequenceColour(seq, randomColour);
+ }
+
+ List<PhylogenyNode> descendantNodes = PhylogenyMethods
+ .getAllDescendants(childNode);
+ // .forEach instead?
+ for (PhylogenyNode descNode : descendantNodes)
+ {
+ seq = nodesBoundToSequences.get(descNode);
+ if (seq != null)
+ {
+ groupSeqs.add(seq);
+ parentAvport.setSequenceColour(seq, randomColour);
+ }
+
+ descNode.getBranchData()
+ .setBranchColor(new BranchColor(randomColour));
+ }
+ if (groupSeqs != null)
+ {
+ nrTreeGroups++;
+ groupThresholdSequences(groupSeqs, randomColour);
+ }}
+
+ else
+ {
+ colourNodesAboveThreshold(nodeList, threshold, childNode);
+ }
}
+ for (AlignmentPanel associatedPanel : associatedPanels) {
+
+ associatedPanel.updateAnnotation();
+
+ final AlignViewportI codingComplement = associatedPanel.getAlignViewport()
+ .getCodingComplement();
+ if (codingComplement != null)
+ {
+ // GROSS
+ ((AlignViewport) codingComplement).getAlignPanel()
+ .updateAnnotation();
+ }
+ }
+
+
+ return nodeList;
}
-
+ public void groupThresholdSequences(List<SequenceI> groupedSeqs,
+ Color groupColour)
+ {
+ SequenceGroup treeGroup = new SequenceGroup(groupedSeqs, null, null,
+ true, true, false, 0,
+ parentAvport.getAlignment().getWidth() - 1);
+
+ ColourSchemeI cs = null;
+ if (parentAvport.getGlobalColourScheme() != null)
+ {
+ if (parentAvport.getGlobalColourScheme() instanceof UserColourScheme)
+ {
+ cs = new UserColourScheme(
+ ((UserColourScheme) parentAvport.getGlobalColourScheme())
+ .getColours());
+ }
+ else
+ {
+ cs = ColourSchemeProperty.getColourScheme(treeGroup,
+ ColourSchemeProperty.getColourName(
+ parentAvport.getGlobalColourScheme()));
+ }
+
+ }
+ treeGroup.setColourScheme(cs);
+ treeGroup.getGroupColourScheme().setThreshold(
+ parentAvport.getResidueShading().getThreshold(),
+ parentAvport.isIgnoreGapsConsensus());
+
+ treeGroup.setName("Tree Group " + nrTreeGroups);
+ treeGroup.setIdColour(groupColour);
+
+ for (AlignmentPanel associatedPanel : associatedPanels)
+ {
+ AlignViewportI altViewport = associatedPanel
+ .getAlignViewport();
+
+ if (altViewport.getGlobalColourScheme() != null
+ && altViewport.getResidueShading()
+ .conservationApplied())
+ {
+ Conservation conserv = new Conservation(treeGroup.getName(),
+ treeGroup.getSequences(null), treeGroup.getStartRes(),
+ treeGroup.getEndRes());
+ conserv.calculate();
+ conserv.verdict(false, altViewport.getConsPercGaps());
+ treeGroup.getGroupColourScheme().setConservation(conserv);
+ }
+
+ altViewport.getAlignment().addGroup(treeGroup);
+ // TODO can we push all of the below into AlignViewportI?
+ final AlignViewportI codingComplement = altViewport
+ .getCodingComplement();
+ if (codingComplement != null)
+ {
+ SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(treeGroup,
+ parentAvport, codingComplement);
+ if (mappedGroup.getSequences().size() > 0)
+ {
+ codingComplement.getAlignment().addGroup(mappedGroup);
+ for (SequenceI seq : mappedGroup.getSequences())
+ {
+ codingComplement.setSequenceColour(seq, groupColour.brighter());
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * may or may not need an extra repaint on the alignment view (check what kira
+ * does)
+ */
@Override
public void showNodeSelectionOnAlign(final PhylogenyNode node)
{
showMatchingSequence(node);
}
+
}
@Override
public void showMatchingChildSequences(final PhylogenyNode parentNode)
{
+ // redundancy here, Forester already iterates through tree to get all
+ // descendants
List<PhylogenyNode> childNodes = PhylogenyMethods
.getAllDescendants(parentNode);
}
}
- public void sortByTree_actionPerformed() {
- // parentAvport.mirrorCommand(command, undo, ssm, source);
- // alignFrame
+ @Override
+ public void sortByTree_actionPerformed()// modify for Aptx
+ {
+
+ // if (treeCanvas.applyToAllViews)
+ // {
+ // final ArrayList<CommandI> commands = new ArrayList<>();
+ // for (AlignmentPanel ap : PaintRefresher
+ // .getAssociatedPanels(parentAvport.getSequenceSetId()))
+ // {
+ // commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
+ // }
+ // parentAvport.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
+ // {
+ //
+ // @Override
+ // public void undoCommand(AlignmentI[] views)
+ // {
+ // for (CommandI tsort : commands)
+ // {
+ // tsort.undoCommand(views);
+ // }
+ // }
+ //
+ // @Override
+ // public int getSize()
+ // {
+ // return commands.size();
+ // }
+ //
+ // @Override
+ // public String getDescription()
+ // {
+ // return "Tree Sort (many views)";
+ // }
+ //
+ // @Override
+ // public void doCommand(AlignmentI[] views)
+ // {
+ //
+ // for (CommandI tsort : commands)
+ // {
+ // tsort.doCommand(views);
+ // }
+ // }
+ // });
+ // for (AlignmentPanel ap : PaintRefresher
+ // .getAssociatedPanels(av.getSequenceSetId()))
+ // {
+ // // ensure all the alignFrames refresh their GI after adding an undo item
+ // ap.alignFrame.updateEditMenuBar();
+ // }
+ // }
+ // else
+ // {
+ // treeCanvas.ap.alignFrame
// .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
-
+ // }
+
}
-
- /**
- * sort the associated alignment view by the current tree.
- *
- * @param e
- */
- // @Override
- // public void sortByTree_actionPerformed()// modify for Aptx
- // {
- //
- // // if (treeCanvas.applyToAllViews)
- //
- // final ArrayList<CommandI> commands = new ArrayList<>();
- // for (AlignmentPanel ap : PaintRefresher
- // .getAssociatedPanels(parentAvport.getSequenceSetId()))
- // {
- // commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
- // }
- // av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
- // {
- //
- // @Override
- // public void undoCommand(AlignmentI[] views)
- // {
- // for (CommandI tsort : commands)
- // {
- // tsort.undoCommand(views);
- // }
- // }
- //
- // @Override
- // public int getSize()
- // {
- // return commands.size();
- // }
- //
- // @Override
- // public String getDescription()
- // {
- // return "Tree Sort (many views)";
- // }
- //
- // @Override
- // public void doCommand(AlignmentI[] views)
- // {
- //
- // for (CommandI tsort : commands)
- // {
- // tsort.doCommand(views);
- // }
- // }
- // });
- // for (AlignmentPanel ap : PaintRefresher
- // .getAssociatedPanels(av.getSequenceSetId()))
- // {
- // // ensure all the alignFrames refresh their GI after adding an undo item
- // ap.alignFrame.updateEditMenuBar();
- // }
- // }
- // else
- // {
- // treeCanvas.ap.alignFrame
- // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
- // }
+ public CommandI sortAlignmentIn(AlignmentPanel ap)
+ {
+ // TODO: move to alignment view controller
+ AlignmentViewport viewport = ap.av;
+ SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+ try
+ {
+ AlignmentSorter.sortByTree(viewport.getAlignment(),
+ nodesBoundToSequences,
+ treeView.getPhylogeny());
+ CommandI undo;
+ undo = new OrderCommand("Tree Sort", oldOrder,
+ viewport.getAlignment());
+
+ ap.paintAlignment(true, false);
+ return undo;
+
+ } catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ }
+ return null;
+
+ }
+
/**
{
this.parentAvport = parentAvport;
}
+
+ public AlignmentPanel[] getAssociatedPanels()
+ {
+ return associatedPanels;
+ }
+
+ public void setAssociatedPanels(AlignmentPanel[] associatedPanels)
+ {
+ this.associatedPanels = associatedPanels;
+ }
+
}